From 3de18fac1e4f5d305a4b9681b0a157a1a803b92c Mon Sep 17 00:00:00 2001 From: Boris Erakhtin Date: Mon, 9 Dec 2024 17:49:13 +0500 Subject: [PATCH 1/2] Update to 0.14.1 --- .CurrentChangelog.md | 135 +- .clang-tidy | 1 - .github/CODEOWNERS | 155 +- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .../ISSUE_TEMPLATE/lfx_mentorship_idea.yml | 70 + .../ISSUE_TEMPLATE/mentoring_workspace.yml | 54 + .github/actions/expand-variables/README.md | 7 - .github/actions/expand-variables/action.yml | 10 - .../actions/expand-variables/dist/index.js | 26209 ---------------- .../actions/expand-variables/dist/license.txt | 120 - .github/actions/expand-variables/main.js | 69 - .../expand-variables/package-lock.json | 69 - .github/actions/expand-variables/package.json | 15 - .github/extensions.paths-filter.yml | 52 + .github/labeler.yml | 4 +- .github/workflows/IWYU_scan.yml | 57 +- .github/workflows/README.md | 68 +- .github/workflows/bindings-java.yml | 28 +- .github/workflows/build-extensions.yml | 535 +- .github/workflows/build.yml | 76 +- .github/workflows/build_for_nix.yml | 41 + .github/workflows/build_for_openwrt.yml | 3 +- .github/workflows/build_for_riscv.yml | 11 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/docker.yml | 309 +- .github/workflows/ignore_words | 4 + .github/workflows/labeler.yml | 2 + .github/workflows/matrix-extensions.json | 204 + .github/workflows/mdbook.yml | 88 - .github/workflows/misc-linters.yml | 5 +- .github/workflows/release.yml | 529 +- ...e-build-extensions-on-legacy-manylinux.yml | 101 + ...reusable-build-extensions-on-manylinux.yml | 159 +- .../workflows/reusable-build-extensions.yml | 109 +- .../reusable-build-on-alpine-static.yml | 9 +- .../workflows/reusable-build-on-android.yml | 9 +- .../reusable-build-on-debian-static.yml | 4 +- .../workflows/reusable-build-on-debian.yml | 56 + .../workflows/reusable-build-on-fedora.yml | 22 +- .github/workflows/reusable-build-on-macos.yml | 19 +- .../workflows/reusable-build-on-manylinux.yml | 28 +- .../workflows/reusable-build-on-ubuntu.yml | 28 +- .../reusable-build-on-windows-msvc.yml | 27 +- .../workflows/reusable-build-on-windows.yml | 40 +- .github/workflows/reusable-call-linter.yml | 9 +- .../reusable-create-source-tarball.yml | 5 +- .github/workflows/static-code-analysis.yml | 5 +- .github/workflows/test-install-script.yml | 183 +- .github/workflows/test-installer-v2.yml | 123 + .../workflows/test-python-install-script.yml | 289 +- .github/workflows/wasi-testsuite.yml | 47 +- .github/workflows/winget-submit.yml | 4 +- .gitignore | 3 - .gitvote.yml | 108 + CMakeLists.txt | 175 +- Changelog.md | 120 +- LICENSE.spdx | 9 + README-zh-TW.md | 2 +- README-zh.md | 2 +- README.md | 1 - SECURITY-INSIGHTS.yml | 2 +- SECURITY.md | 44 +- bindings/java/README.md | 63 +- bindings/java/wasmedge-java/.gitignore | 1 + bindings/java/wasmedge-java/build.gradle | 10 +- .../config/checkstyle/checkstyle.xml | 2 +- bindings/java/wasmedge-java/settings.gradle | 1 - .../src/main/java/org/wasmedge/Async.java | 1 - .../wasmedge-java/wasmedge-jni/CMakeLists.txt | 1 - .../wasmedge-jni/FindWasmEdge.cmake | 6 +- .../java/wasmedge-java/wasmedge-jni/README.md | 10 +- .../wasmedge-jni/lib/AstModuleContext.c | 5 +- .../wasmedge-jni/lib/AstModuleContext.h | 2 +- .../wasmedge-java/wasmedge-jni/lib/Async.c | 31 +- .../wasmedge-java/wasmedge-jni/lib/Async.h | 4 +- .../wasmedge-jni/lib/CompilerContext.c | 2 +- .../wasmedge-jni/lib/ConfigureContext.c | 3 +- .../wasmedge-jni/lib/ConfigureContext.h | 2 +- .../wasmedge-jni/lib/ExecutorContext.c | 5 +- .../wasmedge-jni/lib/ExportTypeContext.c | 2 +- .../wasmedge-jni/lib/ExportTypeContext.h | 2 +- .../wasmedge-jni/lib/ExternRef.c | 2 +- .../wasmedge-jni/lib/FunctionTypeContext.c | 26 +- .../wasmedge-jni/lib/FunctionTypeContext.h | 2 +- .../wasmedge-jni/lib/FunctionTypeInstance.c | 16 +- .../wasmedge-jni/lib/FunctionTypeInstance.h | 2 +- .../wasmedge-jni/lib/GlobalInstanceContext.c | 9 +- .../wasmedge-jni/lib/GlobalInstanceContext.h | 2 +- .../wasmedge-jni/lib/GlobalTypeContext.c | 7 +- .../wasmedge-jni/lib/GlobalTypeContext.h | 2 +- .../wasmedge-jni/lib/ImportTypeContext.c | 2 +- .../wasmedge-jni/lib/ImportTypeContext.h | 2 +- .../wasmedge-jni/lib/LoaderContext.c | 2 +- .../wasmedge-jni/lib/MemoryInstanceContext.c | 9 +- .../wasmedge-jni/lib/MemoryInstanceContext.h | 2 +- .../wasmedge-jni/lib/MemoryTypeContext.c | 8 +- .../wasmedge-jni/lib/MemoryTypeContext.h | 2 +- .../wasmedge-jni/lib/ModuleInstanceContext.c | 9 +- .../wasmedge-jni/lib/ModuleInstanceContext.h | 2 +- .../wasmedge-jni/lib/StatisticsContext.c | 5 +- .../wasmedge-jni/lib/StatisticsContext.h | 2 +- .../wasmedge-jni/lib/StoreContext.c | 4 +- .../wasmedge-jni/lib/StoreContext.h | 2 +- .../wasmedge-jni/lib/TableInstanceContext.c | 8 +- .../wasmedge-jni/lib/TableInstanceContext.h | 2 +- .../wasmedge-jni/lib/TableTypeContext.c | 11 +- .../wasmedge-jni/lib/TableTypeContext.h | 2 +- .../wasmedge-jni/lib/ValidatorContext.c | 4 +- .../wasmedge-jni/lib/ValueType.c | 79 +- .../wasmedge-jni/lib/ValueType.h | 4 +- .../wasmedge-jni/lib/VmContext.c | 4 +- .../wasmedge-java/wasmedge-jni/lib/WasmEdge.c | 4 +- .../wasmedge-jni/lib/WasmEdgeVM.c | 14 +- .../wasmedge-java/wasmedge-jni/lib/common.c | 28 +- .../wasmedge-java/wasmedge-jni/lib/common.h | 21 +- .../wasmedge-jni/lib/constants.h | 18 +- ...metic-operations-in-uint128_fallback.patch | 201 + cmake/Helper.cmake | 139 +- cmake/Hunter/config.cmake | 18 + cmake/WASINNDeps.cmake | 123 +- cmake/cpack_config.cmake | 2 +- cmake/wasmedge-config.cmake | 36 +- docs/CODE_OF_CONDUCT.md | 2 +- docs/GOVERNANCE.md | 49 +- docs/OWNER.md | 21 +- docs/ROADMAP.md | 91 +- docs/SECURITY_CONTACTS.md | 17 + docs/book/en/book.toml | 166 - docs/book/en/src/SUMMARY.md | 163 - docs/book/en/src/cli.md | 3 - docs/book/en/src/cli/wasmedge.md | 3 - docs/book/en/src/cli/wasmedge_compile.md | 4 - docs/book/en/src/cli/wasmedge_tool.md | 3 - docs/book/en/src/contribute.md | 3 - docs/book/en/src/contribute/build_from_src.md | 3 - .../src/contribute/build_from_src/android.md | 3 - .../contribute/build_from_src/android/apk.md | 3 - .../contribute/build_from_src/android/cli.md | 3 - .../contribute/build_from_src/android/ndk.md | 3 - .../en/src/contribute/build_from_src/linux.md | 3 - .../en/src/contribute/build_from_src/macos.md | 3 - .../contribute/build_from_src/openharmony.md | 3 - .../src/contribute/build_from_src/openwrt.md | 3 - .../build_from_src/plugin_wasi_crypto.md | 3 - .../build_from_src/plugin_wasi_logging.md | 3 - .../build_from_src/plugin_wasi_nn.md | 3 - .../build_from_src/plugin_wasmedge_process.md | 3 - .../contribute/build_from_src/raspberrypi.md | 3 - .../src/contribute/build_from_src/riscv64.md | 3 - .../en/src/contribute/build_from_src/sel4.md | 3 - .../src/contribute/build_from_src/windows.md | 3 - docs/book/en/src/contribute/contribute.md | 3 - docs/book/en/src/contribute/installer.md | 3 - docs/book/en/src/contribute/internal.md | 3 - .../book/en/src/contribute/release_process.md | 3 - docs/book/en/src/contribute/wish_list.md | 3 - docs/book/en/src/develop_plugin/c.md | 3 - docs/book/en/src/develop_plugin/cpp.md | 3 - docs/book/en/src/develop_plugin/rust-sdk.md | 3 - docs/book/en/src/features.md | 3 - docs/book/en/src/features/comparison.md | 3 - docs/book/en/src/features/integrations.md | 3 - docs/book/en/src/features/platforms.md | 3 - docs/book/en/src/features/proposals.md | 3 - .../en/src/features/proprietary_extend.md | 3 - docs/book/en/src/index.md | 3 - docs/book/en/src/plugin.md | 3 - docs/book/en/src/quick_start.md | 3 - docs/book/en/src/quick_start/install.md | 3 - docs/book/en/src/quick_start/run_cli.md | 3 - .../en/src/quick_start/run_in_aot_mode.md | 3 - docs/book/en/src/quick_start/use_docker.md | 3 - docs/book/en/src/sdk.md | 3 - docs/book/en/src/sdk/c++.md | 3 - docs/book/en/src/sdk/c.md | 3 - docs/book/en/src/sdk/c/0.10.1/ref.md | 3 - .../en/src/sdk/c/0.10.1/upgrade_to_0.11.0.md | 3 - docs/book/en/src/sdk/c/0.11.2/ref.md | 3 - .../en/src/sdk/c/0.11.2/upgrade_to_0.12.0.md | 3 - docs/book/en/src/sdk/c/0.9.1/ref.md | 3 - .../en/src/sdk/c/0.9.1/upgrade_to_0.10.0.md | 3 - docs/book/en/src/sdk/c/externref.md | 3 - docs/book/en/src/sdk/c/hostfunction.md | 3 - docs/book/en/src/sdk/c/library.md | 3 - docs/book/en/src/sdk/c/multimodule.md | 3 - docs/book/en/src/sdk/c/ref.md | 3 - docs/book/en/src/sdk/go.md | 3 - docs/book/en/src/sdk/go/0.10.1/ref.md | 3 - .../en/src/sdk/go/0.10.1/upgrade_to_0.11.0.md | 3 - docs/book/en/src/sdk/go/0.11.2/ref.md | 3 - .../en/src/sdk/go/0.11.2/upgrade_to_0.12.0.md | 3 - docs/book/en/src/sdk/go/0.9.1/ref.md | 3 - .../en/src/sdk/go/0.9.1/upgrade_to_0.10.0.md | 3 - docs/book/en/src/sdk/go/app.md | 3 - docs/book/en/src/sdk/go/bindgen.md | 3 - docs/book/en/src/sdk/go/function.md | 3 - docs/book/en/src/sdk/go/memory.md | 3 - docs/book/en/src/sdk/go/ref.md | 3 - docs/book/en/src/sdk/go/tensorflow.md | 3 - docs/book/en/src/sdk/python.md | 3 - docs/book/en/src/sdk/rust.md | 3 - docs/book/en/src/sdk/rust/concurrent_fib.md | 85 - .../sdk/rust/how_to_use_module_instance.md | 301 - .../en/src/sdk/rust/memory_manipulation.md | 156 - docs/book/en/src/sdk/rust/say_hello.md | 131 - .../book/en/src/sdk/rust/sys_run_host_func.md | 105 - .../book/en/src/sdk/rust/table_and_funcref.md | 140 - docs/book/en/src/use_cases.md | 3 - docs/book/en/src/use_cases/frameworks.md | 9 - docs/book/en/src/use_cases/frameworks/app.md | 3 - .../en/src/use_cases/frameworks/app/reactr.md | 372 - .../en/src/use_cases/frameworks/app/yomo.md | 282 - docs/book/en/src/use_cases/frameworks/mesh.md | 3 - .../en/src/use_cases/frameworks/mesh/dapr.md | 259 - .../use_cases/frameworks/mesh/eventmesh.md | 3 - .../en/src/use_cases/frameworks/mesh/mosn.md | 3 - .../frameworks/mesh/wasm-nginx-module.md | 3 - .../en/src/use_cases/frameworks/serverless.md | 3 - .../use_cases/frameworks/serverless/aws.md | 262 - .../frameworks/serverless/netlify.md | 185 - .../frameworks/serverless/secondstate.md | 14 - .../frameworks/serverless/tencent.md | 7 - .../use_cases/frameworks/serverless/vercel.md | 187 - .../en/src/use_cases/js_or_dsl_runtime.md | 25 - docs/book/en/src/use_cases/kubernetes.md | 22 - docs/book/en/src/use_cases/kubernetes.png | Bin 42780 -> 0 bytes .../en/src/use_cases/kubernetes/container.md | 7 - .../use_cases/kubernetes/container/crun.md | 3 - .../use_cases/kubernetes/container/runc.md | 3 - .../use_cases/kubernetes/container/youki.md | 3 - docs/book/en/src/use_cases/kubernetes/cri.md | 7 - .../use_cases/kubernetes/cri/containerd.md | 3 - .../en/src/use_cases/kubernetes/cri/crio.md | 3 - docs/book/en/src/use_cases/kubernetes/demo.md | 15 - .../src/use_cases/kubernetes/demo/server.md | 3 - .../en/src/use_cases/kubernetes/demo/wasi.md | 97 - .../en/src/use_cases/kubernetes/docker.md | 6 - .../use_cases/kubernetes/docker/containerd.md | 5 - .../en/src/use_cases/kubernetes/docker/lxc.md | 3 - .../en/src/use_cases/kubernetes/kubernetes.md | 13 - .../use_cases/kubernetes/kubernetes/kind.md | 3 - .../kubernetes/kubernetes/knative.md | 3 - .../kubernetes/kubernetes/kubeedge.md | 3 - .../kubernetes/kubernetes-containerd.md | 3 - .../kubernetes/kubernetes/kubernetes-crio.md | 3 - .../use_cases/kubernetes/kubernetes/kwasm.md | 3 - .../kubernetes/kubernetes/openyurt.md | 3 - .../kubernetes/kubernetes/superedge.md | 3 - .../en/src/use_cases/kubernetes/quickstart.md | 54 - docs/book/en/src/use_cases/microservice.md | 26 - .../en/src/use_cases/server_side_render.md | 19 - docs/book/en/src/use_cases/serverless_faas.md | 27 - docs/book/en/src/use_cases/serverless_saas.md | 18 - docs/book/en/src/use_cases/smart_device.md | 10 - docs/book/en/src/write_wasm.md | 3 - docs/book/en/src/write_wasm/c.md | 3 - docs/book/en/src/write_wasm/c/quickstart.md | 3 - docs/book/en/src/write_wasm/c/simd.md | 3 - docs/book/en/src/write_wasm/go.md | 3 - docs/book/en/src/write_wasm/js.md | 3 - docs/book/en/src/write_wasm/js/es6.md | 3 - docs/book/en/src/write_wasm/js/modules.md | 3 - docs/book/en/src/write_wasm/js/networking.md | 3 - docs/book/en/src/write_wasm/js/nodejs.md | 3 - docs/book/en/src/write_wasm/js/npm.md | 3 - docs/book/en/src/write_wasm/js/quickstart.md | 3 - docs/book/en/src/write_wasm/js/rust.md | 3 - docs/book/en/src/write_wasm/js/ssr.md | 3 - docs/book/en/src/write_wasm/js/tensorflow.md | 3 - docs/book/en/src/write_wasm/kotlin.md | 3 - docs/book/en/src/write_wasm/python.md | 3 - docs/book/en/src/write_wasm/rust.md | 3 - docs/book/en/src/write_wasm/rust/bindgen.md | 3 - docs/book/en/src/write_wasm/rust/command.md | 3 - .../write_wasm/rust/networking-nonblocking.md | 7 - .../book/en/src/write_wasm/rust/networking.md | 6 - docs/book/en/src/write_wasm/rust/ssr.md | 3 - .../book/en/src/write_wasm/rust/tensorflow.md | 3 - docs/book/en/src/write_wasm/rust/wasi.md | 3 - .../book/en/src/write_wasm/rust/wasicrypto.md | 3 - docs/book/en/src/write_wasm/rust/wasinn.md | 9 - docs/book/en/src/write_wasm/swift.md | 3 - docs/book/en/theme/css/chrome.css | 543 - docs/book/en/theme/css/general.css | 200 - docs/book/en/theme/css/variables.css | 252 - docs/book/en/theme/head.hbs | 9 - docs/embargo-policy.md | 30 + docs/self-assessment.md | 257 + .../host_functions/parse_json/host_function.c | 4 +- .../host_functions/parse_json/parse-json.wat | 2 +- .../capi/host_functions/parse_json/test.json | 2 +- .../capi/mandelbrot-set-in-threads/Makefile | 1 - .../capi/mandelbrot-set-in-threads/README.md | 2 +- .../capi/mandelbrot-set-in-threads/main.cc | 2 +- .../mandelbrot-set-in-threads/mandelbrot.c | 2 +- examples/capi/unix_domain_socket/Makefile | 1 - examples/capi/unix_domain_socket/README.md | 18 +- examples/embed_cxx/CMakeLists.txt | 2 +- examples/embed_cxx/README.md | 2 +- examples/js/hello.js | 2 +- examples/js/repl.js | 2 +- examples/plugin/get-string/CMakeLists.txt | 2 +- examples/plugin/get-string/getstring.cpp | 30 +- examples/plugin/get-string/test.wat | 2 +- .../plugin/wasi-crypto-signature/.gitignore | 2 +- .../plugin/wasi-crypto-signature/README.md | 16 +- examples/plugin/wasi-logging/.gitignore | 2 +- examples/plugin/wasi-logging/Cargo.toml | 2 +- examples/plugin/wasi-logging/README.md | 107 +- examples/plugin/wasi-logging/src/lib.rs | 24 +- examples/plugin/wasi-logging/src/main.rs | 2 +- examples/plugin/wasi-logging/wit/logging.wit | 2 +- examples/plugin/wasi-logging/wit/world.wit | 6 +- examples/plugin/wasmedge-zlib/README.md | 18 +- examples/wasm/README.md | 1 + flake.lock | 84 +- flake.nix | 82 +- include/CMakeLists.txt | 4 +- include/aot/blake3.h | 2 +- include/aot/cache.h | 2 +- include/aot/version.h | 2 +- include/api/wasmedge/int128.h | 2 +- include/api/wasmedge/version.h.in | 2 +- include/api/wasmedge/wasmedge.h | 129 +- include/ast/component/alias.h | 2 +- include/ast/component/canonical.h | 2 +- include/ast/component/import_export.h | 6 +- include/ast/component/instance.h | 2 +- include/ast/component/sort.h | 3 +- include/ast/component/start.h | 2 +- include/ast/component/type.h | 284 +- include/ast/description.h | 5 +- include/ast/expression.h | 2 +- include/ast/instruction.h | 127 +- include/ast/module.h | 92 +- include/ast/section.h | 42 +- include/ast/segment.h | 2 +- include/ast/type.h | 598 +- include/common/async.h | 2 +- include/common/config.h.in | 2 +- include/common/configure.h | 53 +- include/common/defines.h | 5 +- include/common/dense_enum_map.h | 2 +- include/common/endian.h | 2 +- include/common/enum.inc | 1312 +- include/common/enum_ast.hpp | 36 +- include/common/enum_configure.h | 2 +- include/common/enum_configure.hpp | 5 +- include/common/enum_errcode.h | 2 +- include/common/enum_errcode.hpp | 8 +- include/common/enum_errinfo.hpp | 11 +- include/common/enum_types.h | 2 +- include/common/enum_types.hpp | 2 +- include/common/errcode.h | 4 +- include/common/errinfo.h | 4 +- include/common/executable.h | 83 + include/common/expected.h | 2 +- include/common/filesystem.h | 2 +- include/common/hexstr.h | 2 +- include/common/int128.h | 56 +- include/common/roundeven.h | 2 +- include/common/span.h | 2 +- include/common/spare_enum_map.h | 2 +- include/common/{log.h => spdlog.h} | 5 +- include/common/statistics.h | 4 +- include/common/symbol.h | 19 +- include/common/timer.h | 2 +- include/common/types.h | 182 +- include/common/variant.h | 2 +- include/common/version.h.in | 2 +- include/driver/compiler.h | 15 +- include/driver/fuzzPO.h | 2 +- include/driver/fuzzTool.h | 2 +- include/driver/tool.h | 32 +- include/driver/unitool.h | 4 +- .../wasi_nn_rpcserver/wasi_nn_rpcserver.h | 145 +- include/executor/engine/atomic.ipp | 2 +- include/executor/engine/binary_numeric.ipp | 2 +- .../executor/engine/binary_numeric_vector.ipp | 63 +- .../engine/binary_numeric_vector_msvc.ipp | 107 +- include/executor/engine/cast_numeric.ipp | 2 +- include/executor/engine/memory.ipp | 2 +- include/executor/engine/relation_numeric.ipp | 2 +- include/executor/engine/unary_numeric.ipp | 14 +- .../executor/engine/unary_numeric_vector.ipp | 2 +- .../engine/unary_numeric_vector_msvc.ipp | 53 +- include/executor/engine/vector_helper.h | 2 +- include/executor/executor.h | 220 +- include/experimental/expected.hpp | 15 +- include/experimental/scope.hpp | 2 +- include/host/mock/log.h | 4 +- include/host/mock/wasi_crypto_func.h | 2 +- include/host/mock/wasi_crypto_module.h | 2 +- include/host/mock/wasi_logging_func.h | 2 +- include/host/mock/wasi_logging_module.h | 2 +- include/host/mock/wasi_nn_func.h | 2 +- include/host/mock/wasi_nn_module.h | 2 +- include/host/mock/wasmedge_image_func.h | 2 +- include/host/mock/wasmedge_image_module.h | 2 +- include/host/mock/wasmedge_process_func.h | 2 +- include/host/mock/wasmedge_process_module.h | 2 +- .../host/mock/wasmedge_stablediffusion_func.h | 64 + .../mock/wasmedge_stablediffusion_module.h | 24 + include/host/mock/wasmedge_tensorflow_func.h | 2 +- .../host/mock/wasmedge_tensorflow_module.h | 2 +- .../host/mock/wasmedge_tensorflowlite_func.h | 2 +- .../mock/wasmedge_tensorflowlite_module.h | 2 +- include/host/wasi/clock.h | 2 +- include/host/wasi/environ.h | 2 +- include/host/wasi/error.h | 4 +- include/host/wasi/inode.h | 24 +- include/host/wasi/vfs.h | 2 +- include/host/wasi/vinode.h | 2 +- include/host/wasi/wasibase.h | 2 +- include/host/wasi/wasifunc.h | 2 +- include/host/wasi/wasimodule.h | 2 +- include/llvm/codegen.h | 38 + include/{aot => llvm}/compiler.h | 16 +- include/llvm/data.h | 41 + include/llvm/jit.h | 50 + include/loader/aot_section.h | 93 + include/loader/filemgr.h | 5 +- include/loader/ldmgr.h | 56 - include/loader/loader.h | 150 +- include/loader/serialize.h | 4 +- include/loader/shared_library.h | 103 +- include/plugin/plugin.h | 107 +- include/plugin/wasi_logging/base.h | 31 + include/plugin/wasi_logging/env.h | 88 + include/plugin/wasi_logging/func.h | 25 + include/plugin/wasi_logging/module.h | 31 + include/po/argument_parser.h | 4 +- include/po/error.h | 2 +- include/po/helper.h | 2 +- include/po/list.h | 2 +- include/po/option.h | 2 +- include/po/parser.h | 4 +- include/po/subcommand.h | 2 +- include/runtime/callingframe.h | 2 +- include/runtime/hostfunc.h | 17 +- include/runtime/instance/array.h | 69 + include/runtime/instance/component.h | 260 + include/runtime/instance/composite.h | 87 + include/runtime/instance/data.h | 16 +- include/runtime/instance/elem.h | 2 +- include/runtime/instance/function.h | 56 +- include/runtime/instance/global.h | 7 +- include/runtime/instance/memory.h | 17 +- include/runtime/instance/module.h | 170 +- include/runtime/instance/struct.h | 49 + include/runtime/instance/table.h | 4 +- include/runtime/instance/tag.h | 40 + include/runtime/stackmgr.h | 97 +- include/runtime/storemgr.h | 55 +- include/system/allocator.h | 2 +- include/system/fault.h | 3 +- include/system/mmap.h | 2 +- include/system/path.h | 2 +- include/system/winapi.h | 144 +- include/validator/formchecker.h | 23 +- include/validator/validator.h | 4 +- include/vm/vm.h | 11 +- lib/CMakeLists.txt | 5 +- lib/aot/CMakeLists.txt | 97 +- lib/aot/blake3.cpp | 2 +- lib/aot/cache.cpp | 2 +- lib/api/CMakeLists.txt | 29 +- lib/api/libwasmedge.lds | 2 +- lib/api/wasmedge.cpp | 229 +- lib/common/CMakeLists.txt | 38 +- lib/common/errinfo.cpp | 7 +- lib/common/hexstr.cpp | 2 +- lib/common/int128.cpp | 135 - lib/common/{log.cpp => spdlog.cpp} | 4 +- lib/driver/CMakeLists.txt | 9 +- lib/driver/compilerTool.cpp | 21 +- lib/driver/fuzzPO.cpp | 6 +- lib/driver/fuzzTool.cpp | 18 +- lib/driver/runtimeTool.cpp | 46 +- lib/driver/uniTool.cpp | 14 +- lib/driver/wasiNNRPCServerTool.cpp | 14 +- lib/executor/CMakeLists.txt | 12 +- lib/executor/engine/controlInstr.cpp | 112 +- lib/executor/engine/engine.cpp | 297 +- lib/executor/engine/memoryInstr.cpp | 2 +- lib/executor/engine/proxy.cpp | 52 +- lib/executor/engine/refInstr.cpp | 576 + lib/executor/engine/tableInstr.cpp | 2 +- lib/executor/engine/threadInstr.cpp | 2 +- lib/executor/engine/variableInstr.cpp | 4 +- lib/executor/executor.cpp | 85 +- lib/executor/helper.cpp | 223 +- lib/executor/instantiate/component.cpp | 92 + .../component/instantiate_component_alias.cpp | 124 + .../component/instantiate_component_canon.cpp | 380 + .../instantiate_component_export.cpp | 65 + .../instantiate_component_import.cpp | 62 + .../instantiate_component_instance.cpp | 173 + .../component/instantiate_component_start.cpp | 25 + .../component/instantiate_component_type.cpp | 35 + lib/executor/instantiate/data.cpp | 7 +- lib/executor/instantiate/elem.cpp | 4 +- lib/executor/instantiate/export.cpp | 5 +- lib/executor/instantiate/function.cpp | 15 +- lib/executor/instantiate/global.cpp | 2 +- lib/executor/instantiate/import.cpp | 132 +- lib/executor/instantiate/memory.cpp | 2 +- lib/executor/instantiate/module.cpp | 33 +- lib/executor/instantiate/table.cpp | 2 +- lib/executor/instantiate/tag.cpp | 22 + lib/host/CMakeLists.txt | 2 +- lib/host/wasi/CMakeLists.txt | 3 +- lib/host/wasi/clock-linux.cpp | 2 +- lib/host/wasi/clock-macos.cpp | 2 +- lib/host/wasi/clock-win.cpp | 2 +- lib/host/wasi/environ-linux.cpp | 2 +- lib/host/wasi/environ-macos.cpp | 2 +- lib/host/wasi/environ-win.cpp | 2 +- lib/host/wasi/environ.cpp | 4 +- lib/host/wasi/inode-linux.cpp | 31 +- lib/host/wasi/inode-macos.cpp | 23 +- lib/host/wasi/inode-win.cpp | 381 +- lib/host/wasi/linux.h | 2 +- lib/host/wasi/macos.h | 2 +- lib/host/wasi/macos.mm | 2 +- lib/host/wasi/vinode.cpp | 9 +- lib/host/wasi/wasifunc.cpp | 11 +- lib/host/wasi/wasimodule.cpp | 2 +- lib/host/wasi/win.h | 13 +- lib/llvm/CMakeLists.txt | 102 + lib/llvm/codegen.cpp | 639 + lib/{aot => llvm}/compiler.cpp | 1069 +- lib/llvm/data.cpp | 19 + lib/llvm/data.h | 14 + lib/llvm/jit.cpp | 97 + lib/{aot => llvm}/llvm.h | 619 +- lib/loader/CMakeLists.txt | 16 +- lib/loader/aot_section.cpp | 164 + lib/loader/ast/component.cpp | 85 +- .../{alias.cpp => component_alias.cpp} | 2 +- ...{canonical.cpp => component_canonical.cpp} | 2 +- ...export.cpp => component_import_export.cpp} | 2 +- .../{instance.cpp => component_instance.cpp} | 2 +- .../{sort.cpp => component_sort.cpp} | 2 +- .../{start.cpp => component_start.cpp} | 2 +- lib/loader/ast/component/type.cpp | 9 +- lib/loader/ast/description.cpp | 18 +- lib/loader/ast/expression.cpp | 2 +- lib/loader/ast/instruction.cpp | 484 +- lib/loader/ast/module.cpp | 138 +- lib/loader/ast/section.cpp | 87 +- lib/loader/ast/segment.cpp | 54 +- lib/loader/ast/type.cpp | 291 +- lib/loader/filemgr.cpp | 17 +- lib/loader/ldmgr.cpp | 53 - lib/loader/loader.cpp | 36 +- lib/loader/serialize/serial_description.cpp | 2 +- lib/loader/serialize/serial_expression.cpp | 2 +- lib/loader/serialize/serial_instruction.cpp | 78 +- lib/loader/serialize/serial_module.cpp | 2 +- lib/loader/serialize/serial_section.cpp | 47 +- lib/loader/serialize/serial_segment.cpp | 2 +- lib/loader/serialize/serial_type.cpp | 53 +- lib/loader/shared_library.cpp | 117 +- lib/plugin/CMakeLists.txt | 7 +- lib/plugin/plugin.cpp | 208 +- lib/plugin/wasi_logging/CMakeLists.txt | 15 + lib/plugin/wasi_logging/func.cpp | 101 + lib/plugin/wasi_logging/module.cpp | 56 + lib/po/CMakeLists.txt | 2 +- lib/po/argument_parser.cpp | 4 +- lib/system/CMakeLists.txt | 2 +- lib/system/allocator.cpp | 2 +- lib/system/fault.cpp | 10 +- lib/system/mmap.cpp | 13 +- lib/system/path.cpp | 2 +- lib/validator/CMakeLists.txt | 2 +- lib/validator/formchecker.cpp | 950 +- lib/validator/validator.cpp | 246 +- lib/vm/CMakeLists.txt | 13 +- lib/vm/vm.cpp | 243 +- lib/wasi_nn_rpc/wasi_ephemeral_nn.proto | 17 + plugins/CMakeLists.txt | 103 +- plugins/wasi_crypto/CMakeLists.txt | 7 +- plugins/wasi_crypto/asymmetric_common/ctx.cpp | 2 +- plugins/wasi_crypto/asymmetric_common/ecdsa.h | 2 +- .../wasi_crypto/asymmetric_common/func.cpp | 2 +- plugins/wasi_crypto/asymmetric_common/func.h | 2 +- .../wasi_crypto/asymmetric_common/keypair.cpp | 2 +- .../wasi_crypto/asymmetric_common/keypair.h | 2 +- .../wasi_crypto/asymmetric_common/module.cpp | 2 +- .../wasi_crypto/asymmetric_common/module.h | 2 +- .../asymmetric_common/publickey.cpp | 2 +- .../wasi_crypto/asymmetric_common/publickey.h | 2 +- .../asymmetric_common/registered.h | 2 +- .../asymmetric_common/secretkey.cpp | 2 +- .../wasi_crypto/asymmetric_common/secretkey.h | 2 +- plugins/wasi_crypto/common/array_output.cpp | 2 +- plugins/wasi_crypto/common/array_output.h | 2 +- plugins/wasi_crypto/common/ctx.cpp | 2 +- plugins/wasi_crypto/common/func.cpp | 2 +- plugins/wasi_crypto/common/func.h | 2 +- plugins/wasi_crypto/common/module.cpp | 2 +- plugins/wasi_crypto/common/module.h | 2 +- plugins/wasi_crypto/common/options.cpp | 2 +- plugins/wasi_crypto/common/options.h | 2 +- plugins/wasi_crypto/ctx.cpp | 5 +- plugins/wasi_crypto/ctx.h | 3 +- plugins/wasi_crypto/kx/ctx.cpp | 2 +- plugins/wasi_crypto/kx/dh/ecdsa.cpp | 2 +- plugins/wasi_crypto/kx/dh/ecdsa.h | 2 +- plugins/wasi_crypto/kx/dh/x25519.cpp | 2 +- plugins/wasi_crypto/kx/dh/x25519.h | 2 +- plugins/wasi_crypto/kx/func.cpp | 2 +- plugins/wasi_crypto/kx/func.h | 2 +- plugins/wasi_crypto/kx/kx.cpp | 2 +- plugins/wasi_crypto/kx/kx.h | 2 +- plugins/wasi_crypto/kx/module.cpp | 2 +- plugins/wasi_crypto/kx/module.h | 2 +- plugins/wasi_crypto/kx/options.cpp | 2 +- plugins/wasi_crypto/kx/options.h | 2 +- plugins/wasi_crypto/kx/registered.h | 2 +- plugins/wasi_crypto/signatures/ctx.cpp | 2 +- plugins/wasi_crypto/signatures/ecdsa.cpp | 2 +- plugins/wasi_crypto/signatures/ecdsa.h | 2 +- plugins/wasi_crypto/signatures/eddsa.cpp | 2 +- plugins/wasi_crypto/signatures/eddsa.h | 2 +- plugins/wasi_crypto/signatures/func.cpp | 2 +- plugins/wasi_crypto/signatures/func.h | 2 +- plugins/wasi_crypto/signatures/module.cpp | 2 +- plugins/wasi_crypto/signatures/module.h | 2 +- plugins/wasi_crypto/signatures/options.cpp | 2 +- plugins/wasi_crypto/signatures/options.h | 2 +- plugins/wasi_crypto/signatures/registered.h | 2 +- plugins/wasi_crypto/signatures/rsa.cpp | 2 +- plugins/wasi_crypto/signatures/rsa.h | 2 +- plugins/wasi_crypto/signatures/signatures.cpp | 2 +- plugins/wasi_crypto/signatures/signatures.h | 2 +- plugins/wasi_crypto/signatures/signstate.cpp | 2 +- plugins/wasi_crypto/signatures/signstate.h | 2 +- .../signatures/verificationstate.cpp | 2 +- .../signatures/verificationstate.h | 2 +- plugins/wasi_crypto/symmetric/aeads.cpp | 2 +- plugins/wasi_crypto/symmetric/aeads.h | 2 +- plugins/wasi_crypto/symmetric/ctx.cpp | 2 +- plugins/wasi_crypto/symmetric/func.cpp | 2 +- plugins/wasi_crypto/symmetric/func.h | 2 +- plugins/wasi_crypto/symmetric/hash.cpp | 2 +- plugins/wasi_crypto/symmetric/hash.h | 2 +- plugins/wasi_crypto/symmetric/kdf.h | 2 +- plugins/wasi_crypto/symmetric/key.cpp | 2 +- plugins/wasi_crypto/symmetric/key.h | 2 +- plugins/wasi_crypto/symmetric/mac.cpp | 2 +- plugins/wasi_crypto/symmetric/mac.h | 2 +- plugins/wasi_crypto/symmetric/module.cpp | 2 +- plugins/wasi_crypto/symmetric/module.h | 2 +- plugins/wasi_crypto/symmetric/options.cpp | 4 +- plugins/wasi_crypto/symmetric/options.h | 2 +- plugins/wasi_crypto/symmetric/registered.h | 2 +- plugins/wasi_crypto/symmetric/state.cpp | 2 +- plugins/wasi_crypto/symmetric/state.h | 2 +- plugins/wasi_crypto/symmetric/tag.cpp | 2 +- plugins/wasi_crypto/symmetric/tag.h | 2 +- plugins/wasi_crypto/utils/error.h | 2 +- plugins/wasi_crypto/utils/evp_wrapper.cpp | 2 +- plugins/wasi_crypto/utils/evp_wrapper.h | 4 +- plugins/wasi_crypto/utils/handles_manager.h | 9 +- plugins/wasi_crypto/utils/hostfunction.cpp | 2 +- plugins/wasi_crypto/utils/hostfunction.h | 2 +- plugins/wasi_crypto/utils/optional.h | 2 +- plugins/wasi_crypto/utils/secret_vec.h | 2 +- plugins/wasi_http/CMakeLists.txt | 48 + plugins/wasi_http/README.md | 3 + plugins/wasi_http/base.h | 24 + plugins/wasi_http/env.cpp | 42 + plugins/wasi_http/env.h | 19 + plugins/wasi_http/func.cpp | 34 + plugins/wasi_http/func.h | 25 + plugins/wasi_http/module.cpp | 18 + plugins/wasi_http/module.h | 24 + plugins/wasi_logging/CMakeLists.txt | 31 - plugins/wasi_logging/env.cpp | 36 - plugins/wasi_logging/func.cpp | 85 - plugins/wasi_logging/module.cpp | 16 - plugins/wasi_logging/wasi_logging/base.h | 22 - plugins/wasi_logging/wasi_logging/enum.h | 13 - plugins/wasi_logging/wasi_logging/env.h | 23 - plugins/wasi_logging/wasi_logging/func.h | 17 - plugins/wasi_logging/wasi_logging/module.h | 20 - plugins/wasi_nn/CMakeLists.txt | 331 +- plugins/wasi_nn/chattts.cpp | 360 + plugins/wasi_nn/chattts.h | 66 + plugins/wasi_nn/ggml.cpp | 1189 +- plugins/wasi_nn/ggml.h | 20 +- plugins/wasi_nn/neuralspeed.cpp | 40 + plugins/wasi_nn/neuralspeed.h | 39 + plugins/wasi_nn/onnx.cpp | 2 +- plugins/wasi_nn/onnx.h | 2 +- plugins/wasi_nn/openvino.cpp | 2 +- plugins/wasi_nn/openvino.h | 2 +- plugins/wasi_nn/piper.cpp | 521 + plugins/wasi_nn/piper.h | 105 + plugins/wasi_nn/piper.patch | 472 + plugins/wasi_nn/tf.cpp | 2 +- plugins/wasi_nn/tf.h | 2 +- plugins/wasi_nn/tfl.cpp | 2 +- plugins/wasi_nn/tfl.h | 2 +- plugins/wasi_nn/torch.cpp | 2 +- plugins/wasi_nn/torch.h | 2 +- plugins/wasi_nn/types.h | 22 +- plugins/wasi_nn/wasinnbase.h | 2 +- plugins/wasi_nn/wasinnenv.cpp | 83 +- plugins/wasi_nn/wasinnenv.h | 20 +- plugins/wasi_nn/wasinnfunc.cpp | 178 +- plugins/wasi_nn/wasinnfunc.h | 14 +- plugins/wasi_nn/wasinnmodule.cpp | 3 +- plugins/wasi_nn/wasinnmodule.h | 2 +- plugins/wasi_nn/whispercpp.cpp | 513 + plugins/wasi_nn/whispercpp.h | 89 + .../.gitignore | 0 plugins/wasi_nn_burnrs/CMakeLists.txt | 25 + plugins/wasi_nn_burnrs/Cargo.toml | 38 + plugins/wasi_nn_burnrs/src/helper.rs | 11 + plugins/wasi_nn_burnrs/src/lib.rs | 382 + plugins/wasi_nn_burnrs/src/models/mod.rs | 4 + .../wasi_nn_burnrs/src/models/squeezenet.rs | 45 + plugins/wasi_nn_burnrs/src/models/whisper.rs | 96 + plugins/wasi_poll/CMakeLists.txt | 42 + plugins/wasi_poll/README.md | 3 + plugins/wasi_poll/base.h | 24 + plugins/wasi_poll/env.cpp | 42 + plugins/wasi_poll/env.h | 19 + plugins/wasi_poll/func.cpp | 14 + plugins/wasi_poll/func.h | 23 + plugins/wasi_poll/module.cpp | 17 + plugins/wasi_poll/module.h | 24 + plugins/wasm_bpf/CMakeLists.txt | 2 +- plugins/wasm_bpf/README.md | 2 +- plugins/wasm_bpf/bpf-api.h | 2 +- plugins/wasm_bpf/func-attach-bpf-program.cpp | 2 +- plugins/wasm_bpf/func-attach-bpf-program.h | 2 +- plugins/wasm_bpf/func-bpf-buffer-poll.cpp | 3 +- plugins/wasm_bpf/func-bpf-buffer-poll.h | 2 +- plugins/wasm_bpf/func-bpf-map-fd-by-name.cpp | 2 +- plugins/wasm_bpf/func-bpf-map-fd-by-name.h | 2 +- plugins/wasm_bpf/func-bpf-map-operate.cpp | 3 +- plugins/wasm_bpf/func-bpf-map-operate.h | 2 +- plugins/wasm_bpf/func-close-bpf-object.cpp | 2 +- plugins/wasm_bpf/func-close-bpf-object.h | 2 +- plugins/wasm_bpf/func-load-bpf-object.cpp | 2 +- plugins/wasm_bpf/func-load-bpf-object.h | 2 +- plugins/wasm_bpf/state.h | 2 +- plugins/wasm_bpf/util.cpp | 2 +- plugins/wasm_bpf/util.h | 2 +- plugins/wasm_bpf/wasm-bpf-module.cpp | 5 +- plugins/wasm_bpf/wasm-bpf-module.h | 2 +- plugins/wasm_bpf/wasm-bpf.cpp | 2 +- plugins/wasmedge_ffmpeg/CMakeLists.txt | 91 + plugins/wasmedge_ffmpeg/avcodec/avCodec.cpp | 237 + plugins/wasmedge_ffmpeg/avcodec/avCodec.h | 142 + .../avcodec/avCodecContext.cpp | 771 + .../wasmedge_ffmpeg/avcodec/avCodecContext.h | 686 + .../avcodec/avCodecParameters.cpp | 38 + .../avcodec/avCodecParameters.h | 37 + plugins/wasmedge_ffmpeg/avcodec/avPacket.cpp | 171 + plugins/wasmedge_ffmpeg/avcodec/avPacket.h | 154 + .../wasmedge_ffmpeg/avcodec/avcodec_func.cpp | 316 + .../wasmedge_ffmpeg/avcodec/avcodec_func.h | 210 + plugins/wasmedge_ffmpeg/avcodec/module.cpp | 363 + plugins/wasmedge_ffmpeg/avcodec/module.h | 23 + .../avdevice/avDevice_func.cpp | 120 + .../wasmedge_ffmpeg/avdevice/avDevice_func.h | 107 + plugins/wasmedge_ffmpeg/avdevice/module.cpp | 40 + plugins/wasmedge_ffmpeg/avdevice/module.h | 23 + plugins/wasmedge_ffmpeg/avfilter/avFilter.cpp | 146 + plugins/wasmedge_ffmpeg/avfilter/avFilter.h | 106 + .../avfilter/avfilter_func.cpp | 289 + .../wasmedge_ffmpeg/avfilter/avfilter_func.h | 179 + .../avfilter/buffer_source_sink.cpp | 66 + .../avfilter/buffer_source_sink.h | 60 + plugins/wasmedge_ffmpeg/avfilter/module.cpp | 110 + plugins/wasmedge_ffmpeg/avfilter/module.h | 23 + .../wasmedge_ffmpeg/avformat/avChapter.cpp | 200 + plugins/wasmedge_ffmpeg/avformat/avChapter.h | 93 + .../avformat/avInputOutputFormat.cpp | 210 + .../avformat/avInputOutputFormat.h | 123 + plugins/wasmedge_ffmpeg/avformat/avStream.cpp | 290 + plugins/wasmedge_ffmpeg/avformat/avStream.h | 135 + .../avformat/avformatContext.cpp | 116 + .../avformat/avformatContext.h | 86 + .../avformat/avformat_func.cpp | 363 + .../wasmedge_ffmpeg/avformat/avformat_func.h | 234 + plugins/wasmedge_ffmpeg/avformat/module.cpp | 195 + plugins/wasmedge_ffmpeg/avformat/module.h | 23 + .../wasmedge_ffmpeg/avutil/avDictionary.cpp | 163 + plugins/wasmedge_ffmpeg/avutil/avDictionary.h | 56 + plugins/wasmedge_ffmpeg/avutil/avFrame.cpp | 424 + plugins/wasmedge_ffmpeg/avutil/avFrame.h | 346 + plugins/wasmedge_ffmpeg/avutil/avRational.cpp | 161 + plugins/wasmedge_ffmpeg/avutil/avRational.h | 99 + plugins/wasmedge_ffmpeg/avutil/avTime.cpp | 35 + plugins/wasmedge_ffmpeg/avutil/avTime.h | 41 + .../wasmedge_ffmpeg/avutil/avutil_func.cpp | 138 + plugins/wasmedge_ffmpeg/avutil/avutil_func.h | 182 + plugins/wasmedge_ffmpeg/avutil/error.cpp | 41 + plugins/wasmedge_ffmpeg/avutil/error.h | 35 + plugins/wasmedge_ffmpeg/avutil/module.cpp | 265 + plugins/wasmedge_ffmpeg/avutil/module.h | 23 + plugins/wasmedge_ffmpeg/avutil/pixfmt.cpp | 166 + plugins/wasmedge_ffmpeg/avutil/pixfmt.h | 118 + plugins/wasmedge_ffmpeg/avutil/samplefmt.cpp | 134 + plugins/wasmedge_ffmpeg/avutil/samplefmt.h | 95 + plugins/wasmedge_ffmpeg/bindings.h | 4536 +++ plugins/wasmedge_ffmpeg/ffmpeg_base.h | 26 + plugins/wasmedge_ffmpeg/ffmpeg_env.cpp | 117 + plugins/wasmedge_ffmpeg/ffmpeg_env.h | 114 + plugins/wasmedge_ffmpeg/swresample/module.cpp | 42 + plugins/wasmedge_ffmpeg/swresample/module.h | 24 + .../swresample/swresample_func.cpp | 122 + .../swresample/swresample_func.h | 96 + plugins/wasmedge_ffmpeg/swscale/module.cpp | 76 + plugins/wasmedge_ffmpeg/swscale/module.h | 23 + .../wasmedge_ffmpeg/swscale/swscale_func.cpp | 284 + .../wasmedge_ffmpeg/swscale/swscale_func.h | 199 + plugins/wasmedge_image/CMakeLists.txt | 7 +- plugins/wasmedge_image/image_base.h | 2 +- plugins/wasmedge_image/image_env.cpp | 7 +- plugins/wasmedge_image/image_env.h | 6 +- plugins/wasmedge_image/image_func.cpp | 4 +- plugins/wasmedge_image/image_func.h | 2 +- plugins/wasmedge_image/image_module.cpp | 2 +- plugins/wasmedge_image/image_module.h | 2 +- plugins/wasmedge_llmc/CMakeLists.txt | 65 + plugins/wasmedge_llmc/llmc_base.h | 28 + plugins/wasmedge_llmc/llmc_env.cpp | 85 + plugins/wasmedge_llmc/llmc_env.h | 57 + plugins/wasmedge_llmc/llmc_func.cpp | 127 + plugins/wasmedge_llmc/llmc_func.h | 91 + plugins/wasmedge_llmc/llmc_fwd.h | 29 + plugins/wasmedge_llmc/llmc_module.cpp | 20 + plugins/wasmedge_llmc/llmc_module.h | 22 + plugins/wasmedge_ocr/CMakeLists.txt | 54 + plugins/wasmedge_ocr/ocr_base.h | 25 + plugins/wasmedge_ocr/ocr_env.cpp | 40 + plugins/wasmedge_ocr/ocr_env.h | 48 + plugins/wasmedge_ocr/ocr_func.cpp | 71 + plugins/wasmedge_ocr/ocr_func.h | 32 + plugins/wasmedge_ocr/ocr_module.cpp | 17 + plugins/wasmedge_ocr/ocr_module.h | 24 + plugins/wasmedge_opencvmini/CMakeLists.txt | 7 +- plugins/wasmedge_opencvmini/opencvmini_base.h | 2 +- .../wasmedge_opencvmini/opencvmini_env.cpp | 7 +- plugins/wasmedge_opencvmini/opencvmini_env.h | 4 +- .../wasmedge_opencvmini/opencvmini_func.cpp | 2 +- plugins/wasmedge_opencvmini/opencvmini_func.h | 2 +- .../wasmedge_opencvmini/opencvmini_module.cpp | 2 +- .../wasmedge_opencvmini/opencvmini_module.h | 2 +- plugins/wasmedge_process/CMakeLists.txt | 7 +- plugins/wasmedge_process/processbase.h | 2 +- plugins/wasmedge_process/processenv.cpp | 7 +- plugins/wasmedge_process/processenv.h | 3 +- plugins/wasmedge_process/processfunc.cpp | 2 +- plugins/wasmedge_process/processfunc.h | 2 +- plugins/wasmedge_process/processmodule.cpp | 2 +- plugins/wasmedge_process/processmodule.h | 2 +- plugins/wasmedge_rustls/CMakeLists.txt | 19 - plugins/wasmedge_rustls/Cargo.toml | 18 - plugins/wasmedge_rustls/src/lib.rs | 703 - .../wasmedge_stablediffusion/CMakeLists.txt | 124 + plugins/wasmedge_stablediffusion/sd_base.h | 28 + plugins/wasmedge_stablediffusion/sd_env.cpp | 77 + plugins/wasmedge_stablediffusion/sd_env.h | 44 + plugins/wasmedge_stablediffusion/sd_func.cpp | 427 + plugins/wasmedge_stablediffusion/sd_func.h | 81 + .../wasmedge_stablediffusion/sd_module.cpp | 21 + plugins/wasmedge_stablediffusion/sd_module.h | 23 + plugins/wasmedge_tensorflow/CMakeLists.txt | 7 +- plugins/wasmedge_tensorflow/tensorflow_base.h | 2 +- .../wasmedge_tensorflow/tensorflow_env.cpp | 7 +- plugins/wasmedge_tensorflow/tensorflow_env.h | 4 +- .../wasmedge_tensorflow/tensorflow_func.cpp | 4 +- plugins/wasmedge_tensorflow/tensorflow_func.h | 2 +- .../wasmedge_tensorflow/tensorflow_module.cpp | 2 +- .../wasmedge_tensorflow/tensorflow_module.h | 2 +- .../wasmedge_tensorflowlite/CMakeLists.txt | 7 +- .../tensorflowlite_base.h | 2 +- .../tensorflowlite_env.cpp | 7 +- .../tensorflowlite_env.h | 4 +- .../tensorflowlite_func.cpp | 4 +- .../tensorflowlite_func.h | 2 +- .../tensorflowlite_module.cpp | 2 +- .../tensorflowlite_module.h | 2 +- plugins/wasmedge_zlib/CMakeLists.txt | 23 +- plugins/wasmedge_zlib/zlibbase.h | 2 +- plugins/wasmedge_zlib/zlibenv.cpp | 7 +- plugins/wasmedge_zlib/zlibenv.h | 16 +- plugins/wasmedge_zlib/zlibfunc.cpp | 3 +- plugins/wasmedge_zlib/zlibfunc.h | 2 +- plugins/wasmedge_zlib/zlibmodule.cpp | 2 +- plugins/wasmedge_zlib/zlibmodule.h | 2 +- test/CMakeLists.txt | 57 +- test/aot/AOTBlake3Test.cpp | 2 +- test/aot/AOTCacheTest.cpp | 2 +- test/aot/CMakeLists.txt | 18 +- test/api/APIAOTCoreTest.cpp | 2 +- test/api/APIStepsCoreTest.cpp | 7 +- test/api/APIUnitTest.cpp | 596 +- test/api/APIVMCoreTest.cpp | 6 +- test/api/CMakeLists.txt | 8 +- test/api/apiTestData/import.wat | 10 + test/api/helper.cpp | 9 +- test/api/helper.h | 2 +- test/api/hostfunc_c.c | 54 +- test/api/hostfunc_c.h | 2 +- test/common/CMakeLists.txt | 2 +- test/common/int128Test.cpp | 114 +- test/errinfo/CMakeLists.txt | 2 +- test/errinfo/errinfoTest.cpp | 2 +- test/executor/CMakeLists.txt | 2 +- test/executor/ExecutorTest.cpp | 4 +- test/expected/CMakeLists.txt | 2 +- test/expected/catch.hpp | 3 +- test/expected/noexcept.cpp | 7 + test/externref/CMakeLists.txt | 2 +- test/externref/ExternrefTest.cpp | 12 +- test/host/mock/CMakeLists.txt | 2 +- test/host/mock/mockTest.cpp | 2 +- test/host/socket/CMakeLists.txt | 2 +- test/host/socket/wasi_socket.cpp | 4 +- test/host/wasi/CMakeLists.txt | 2 +- test/host/wasi/wasi.cpp | 11 +- test/llvm/CMakeLists.txt | 18 + .../AOTcoreTest.cpp => llvm/LLVMcoreTest.cpp} | 174 +- test/loader/CMakeLists.txt | 2 +- test/loader/descriptionTest.cpp | 4 +- test/loader/expressionTest.cpp | 2 +- test/loader/filemgrTest.cpp | 310 +- test/loader/instructionTest.cpp | 4 +- test/loader/moduleTest.cpp | 2 +- test/loader/sectionTest.cpp | 2 +- test/loader/segmentTest.cpp | 2 +- test/loader/serializeDescriptionTest.cpp | 2 +- test/loader/serializeExpressionTest.cpp | 2 +- test/loader/serializeInstructionTest.cpp | 18 +- test/loader/serializeModuleTest.cpp | 2 +- test/loader/serializeSectionTest.cpp | 2 +- test/loader/serializeSegmentTest.cpp | 2 +- test/loader/serializeTypeTest.cpp | 2 +- test/loader/typeTest.cpp | 2 +- test/memlimit/CMakeLists.txt | 2 +- test/memlimit/MemLimitTest.cpp | 5 +- test/mixcall/CMakeLists.txt | 4 +- test/mixcall/mixcallTest.cpp | 51 +- test/plugins/CMakeLists.txt | 95 +- test/plugins/unittest/CMakeLists.txt | 11 +- test/plugins/unittest/testplugin.c | 22 +- test/plugins/unittest/testplugin.cpp | 44 +- test/plugins/unittest/testplugin.h | 15 +- test/plugins/unittest/unittest_c.cpp | 16 +- test/plugins/unittest/unittest_cpp.cpp | 68 +- test/plugins/wasi_crypto/CMakeLists.txt | 2 +- test/plugins/wasi_crypto/aeads.cpp | 2 +- test/plugins/wasi_crypto/asymmetric.cpp | 2 +- test/plugins/wasi_crypto/common.cpp | 5 +- test/plugins/wasi_crypto/hash.cpp | 2 +- test/plugins/wasi_crypto/helper.cpp | 5 +- test/plugins/wasi_crypto/helper.h | 68 +- test/plugins/wasi_crypto/kdf.cpp | 2 +- test/plugins/wasi_crypto/kx.cpp | 2 +- test/plugins/wasi_crypto/mac.cpp | 2 +- test/plugins/wasi_crypto/notimplement.cpp | 2 +- test/plugins/wasi_crypto/signatures.cpp | 2 +- test/plugins/wasi_logging/CMakeLists.txt | 3 +- test/plugins/wasi_logging/wasi_logging.cpp | 165 +- test/plugins/wasi_nn/CMakeLists.txt | 148 +- test/plugins/wasi_nn/wasi_nn.cpp | 1400 +- test/plugins/wasm_bpf/CMakeLists.txt | 2 +- .../assets/bpf-sources/simple_map.bpf.c | 2 +- .../assets/bpf-sources/simple_ringbuf.bpf.c | 2 +- test/plugins/wasm_bpf/simple_map_test.cpp | 8 +- test/plugins/wasm_bpf/simple_ringbuf_test.cpp | 19 +- test/plugins/wasm_bpf/wasm_bpf.cpp | 84 +- test/plugins/wasmedge_ffmpeg/CMakeLists.txt | 73 + .../wasmedge_ffmpeg/avcodec/avCodec.cpp | 367 + .../wasmedge_ffmpeg/avcodec/avCodecCtx.cpp | 1661 + .../avcodec/avCodecParameters.cpp | 79 + .../wasmedge_ffmpeg/avcodec/avPacket.cpp | 371 + .../wasmedge_ffmpeg/avcodec/avcodec_func.cpp | 577 + .../wasmedge_ffmpeg/avfilter/avfilter.cpp | 291 + .../avfilter/avfilter_func.cpp | 685 + .../wasmedge_ffmpeg/avformat/avChapter.cpp | 223 + .../avformat/avInputOutputContext.cpp | 210 + .../wasmedge_ffmpeg/avformat/avStream.cpp | 306 + .../avformat/avformatContext.cpp | 187 + .../avformat/avformat_func.cpp | 591 + .../wasmedge_ffmpeg/avutil/avDictionary.cpp | 156 + .../wasmedge_ffmpeg/avutil/avError.cpp | 67 + .../wasmedge_ffmpeg/avutil/avFrame.cpp | 784 + .../wasmedge_ffmpeg/avutil/avPixfmt.cpp | 247 + .../wasmedge_ffmpeg/avutil/avRational.cpp | 316 + .../wasmedge_ffmpeg/avutil/avSampleFmt.cpp | 205 + .../wasmedge_ffmpeg/avutil/avutil_func.cpp | 264 + test/plugins/wasmedge_ffmpeg/main.cpp | 9 + .../swresample/swresample_func.cpp | 258 + .../wasmedge_ffmpeg/swscale/swscale_func.cpp | 540 + test/plugins/wasmedge_ffmpeg/utils.cpp | 257 + test/plugins/wasmedge_ffmpeg/utils.h | 172 + test/plugins/wasmedge_image/CMakeLists.txt | 2 +- .../plugins/wasmedge_image/wasmedge_image.cpp | 32 +- test/plugins/wasmedge_llmc/CMakeLists.txt | 78 + test/plugins/wasmedge_llmc/wasmedge_llmc.cpp | 214 + .../wasmedge_opencvmini/CMakeLists.txt | 2 +- .../wasmedge_opencvmini.cpp | 31 +- test/plugins/wasmedge_process/CMakeLists.txt | 2 +- .../wasmedge_process/wasmedge_process.cpp | 126 +- test/plugins/wasmedge_rustls/CMakeLists.txt | 35 - .../wasmedge_rustls/wasmedge_rustls.cpp | 54 - .../wasmedge_stablediffusion/CMakeLists.txt | 47 + .../wasmedge_stablediffusion.cpp | 337 + .../wasmedge_tensorflow/CMakeLists.txt | 2 +- .../wasmedge_tensorflow.cpp | 32 +- .../wasmedge_tensorflowlite/CMakeLists.txt | 2 +- .../wasmedge_tensorflowlite.cpp | 33 +- test/plugins/wasmedge_zlib/CMakeLists.txt | 2 +- test/plugins/wasmedge_zlib/wasmedge_zlib.cpp | 38 +- test/po/CMakeLists.txt | 2 +- test/po/gtest.cpp | 2 +- test/po/help.cpp | 2 +- test/po/po.cpp | 2 +- test/po/subcommand.cpp | 11 +- test/span/CMakeLists.txt | 2 +- test/spec/CMakeLists.txt | 64 +- test/spec/hostfunc.h | 6 +- test/spec/spectest.cpp | 273 +- test/spec/spectest.h | 3 +- test/thread/CMakeLists.txt | 8 +- test/thread/ThreadTest.cpp | 25 +- test/thread/mt19937.c | 2 +- thirdparty/CMakeLists.txt | 5 +- thirdparty/blake3/CMakeLists.txt | 4 +- thirdparty/blake3/blake3.c | 2 +- thirdparty/blake3/blake3_avx2_x86-64_unix.S | 1 - .../blake3/blake3_avx2_x86-64_windows_gnu.S | 1 - .../blake3_sse41_x86-64_windows_msvc.asm | 1 - thirdparty/ggml/ggml.patch | 17 - thirdparty/wasi/api.hpp | 2 +- thirdparty/wasi_crypto/api.hpp | 7 +- tools/CMakeLists.txt | 2 +- tools/fuzz/CMakeLists.txt | 2 +- tools/fuzz/po.cpp | 2 +- tools/fuzz/tool.cpp | 2 +- tools/wasmedge/CMakeLists.txt | 4 +- tools/wasmedge/wasi_nn_rpcserver.cpp | 2 +- tools/wasmedge/wasmedge.cpp | 2 +- tools/wasmedge/wasmedgec.cpp | 2 +- utils/android/app/.idea/.name | 2 +- utils/android/app/.idea/compiler.xml | 2 +- utils/android/app/.idea/gradle.xml | 2 +- utils/android/app/.idea/misc.xml | 2 +- utils/android/app/.idea/vcs.xml | 2 +- utils/android/app/app/.gitignore | 2 +- utils/android/app/app/build.gradle | 2 +- utils/android/app/app/proguard-rules.pro | 2 +- .../app/app/src/main/AndroidManifest.xml | 2 +- .../org/wasmedge/example_app/MainActivity.kt | 2 +- .../drawable-v24/ic_launcher_foreground.xml | 2 +- .../app/src/main/res/layout/activity_main.xml | 2 +- .../res/mipmap-anydpi-v26/ic_launcher.xml | 2 +- .../mipmap-anydpi-v26/ic_launcher_round.xml | 2 +- .../app/src/main/res/values-night/themes.xml | 2 +- .../app/app/src/main/res/values/colors.xml | 2 +- .../app/app/src/main/res/values/strings.xml | 2 +- .../app/app/src/main/res/values/themes.xml | 2 +- utils/android/app/build.gradle | 2 +- utils/android/app/gradle.properties | 2 +- utils/android/app/lib/.gitignore | 2 +- utils/android/app/lib/build.gradle | 1 - utils/android/app/lib/proguard-rules.pro | 2 +- .../app/lib/src/main/AndroidManifest.xml | 2 +- .../app/lib/src/main/cpp/CMakeLists.txt | 2 +- .../app/lib/src/main/cpp/wasmedge_lib.cpp | 1 - .../java/org/wasmedge/native_lib/NativeLib.kt | 2 +- utils/android/standalone/build_for_android.sh | 2 +- utils/docker/Dockerfile.alpine-static | 2 +- utils/docker/Dockerfile.base | 19 - utils/docker/Dockerfile.build-clang | 10 - utils/docker/Dockerfile.build-gcc | 11 - utils/docker/Dockerfile.build-plugins-deps | 12 - utils/docker/Dockerfile.ci-image-base | 3 +- utils/docker/Dockerfile.debian-static | 4 +- ...ockerfile.manylinux2014-build-plugins-deps | 29 +- utils/docker/Dockerfile.manylinux2014_aarch64 | 48 +- utils/docker/Dockerfile.manylinux2014_x86_64 | 48 +- utils/docker/Dockerfile.manylinux_2_28-base | 59 + .../Dockerfile.manylinux_2_28-plugins-deps | 44 + utils/docker/Dockerfile.ubuntu-base | 52 + utils/docker/Dockerfile.ubuntu-gcc | 5 + utils/docker/Dockerfile.ubuntu-plugins-deps | 28 + utils/docker/Dockerfile.ubuntu2104_armv7l | 10 +- utils/docker/SHA256SUM | 8 - utils/docker/SHA256SUM.manylinux2014 | 9 + utils/docker/SHA256SUM.manylinux_2_28 | 7 + utils/docker/build-manylinux.sh | 2 +- utils/docker/build.sh | 49 - utils/docker/docker-bake.ci-image-base.hcl | 26 + utils/docker/docker-bake.manylinux.hcl | 51 + utils/docker/docker-bake.ubuntu.hcl | 125 + utils/docker/install-opencvmini.sh | 16 - utils/ffmpeg/download-ffmpeg-sample-video.sh | 22 + utils/ffmpeg/install-ffmpeg-v6.0.sh | 13 + utils/install.py | 552 +- utils/install_v2.sh | 630 + utils/ohos/build_for_ohos.sh | 4 +- utils/ohos/configuration/BUILD.gn | 2 +- utils/ohos/configuration/CMakeLists.txt | 5 +- utils/ohos/configuration/build_thirdparty.py | 2 +- utils/opencvmini/install-opencvmini.sh | 7 +- utils/openwrt/build_for_openwrt.sh | 2 +- utils/openwrt/configuration/Makefile | 9 +- utils/wasi-cpp-header/.gitignore | 2 +- utils/wasi-cpp-header/Cargo.toml | 2 +- utils/wasi-cpp-header/add-addrinfo.patch | 1 - utils/wasi-cpp-header/add-wasi_sock.patch | 1 - utils/wasi-cpp-header/change-tag-type.patch | 1 - utils/wasi-cpp-header/crypto_generate.sh | 1 - utils/wasi-cpp-header/generate.sh | 4 +- utils/wasi-cpp-header/src/cpp_header.rs | 4 +- utils/wasi-cpp-header/src/lib.rs | 2 +- utils/wasi-cpp-header/src/main.rs | 2 +- utils/wasi-crypto/build-openssl.sh | 2 +- utils/wasi-nn/build-wasinn-ubuntu-openvino.sh | 2 +- utils/wasi-nn/download-ggml-fixtures.sh | 17 - utils/wasi-nn/download-openvino-fixtures.sh | 25 - utils/wasi-nn/download-pytorch-fixtures.sh | 19 - utils/wasi-nn/download-tflite-fixtures.sh | 19 - utils/wasi-nn/install-onnxruntime.sh | 27 + utils/wasi-nn/install-openvino.sh | 8 +- utils/wasi-nn/install-pytorch.sh | 2 +- utils/wasi-nn/test-wasinn-ubuntu-openvino.sh | 4 + ...-Disable-other-tests-except-wasmedge.patch | 1 - utils/wasi-test/run-wasi-test.sh | 2 +- 1141 files changed, 51459 insertions(+), 41001 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/lfx_mentorship_idea.yml create mode 100644 .github/ISSUE_TEMPLATE/mentoring_workspace.yml delete mode 100644 .github/actions/expand-variables/README.md delete mode 100644 .github/actions/expand-variables/action.yml delete mode 100644 .github/actions/expand-variables/dist/index.js delete mode 100644 .github/actions/expand-variables/dist/license.txt delete mode 100644 .github/actions/expand-variables/main.js delete mode 100644 .github/actions/expand-variables/package-lock.json delete mode 100644 .github/actions/expand-variables/package.json create mode 100644 .github/extensions.paths-filter.yml create mode 100644 .github/workflows/build_for_nix.yml create mode 100644 .github/workflows/matrix-extensions.json delete mode 100644 .github/workflows/mdbook.yml create mode 100644 .github/workflows/reusable-build-extensions-on-legacy-manylinux.yml create mode 100644 .github/workflows/reusable-build-on-debian.yml create mode 100644 .github/workflows/test-installer-v2.yml create mode 100644 .gitvote.yml create mode 100644 bindings/java/wasmedge-java/.gitignore create mode 100644 cmake/0001-support-arithmetic-operations-in-uint128_fallback.patch create mode 100644 docs/SECURITY_CONTACTS.md delete mode 100644 docs/book/en/book.toml delete mode 100644 docs/book/en/src/SUMMARY.md delete mode 100644 docs/book/en/src/cli.md delete mode 100644 docs/book/en/src/cli/wasmedge.md delete mode 100644 docs/book/en/src/cli/wasmedge_compile.md delete mode 100644 docs/book/en/src/cli/wasmedge_tool.md delete mode 100644 docs/book/en/src/contribute.md delete mode 100644 docs/book/en/src/contribute/build_from_src.md delete mode 100644 docs/book/en/src/contribute/build_from_src/android.md delete mode 100644 docs/book/en/src/contribute/build_from_src/android/apk.md delete mode 100644 docs/book/en/src/contribute/build_from_src/android/cli.md delete mode 100644 docs/book/en/src/contribute/build_from_src/android/ndk.md delete mode 100644 docs/book/en/src/contribute/build_from_src/linux.md delete mode 100644 docs/book/en/src/contribute/build_from_src/macos.md delete mode 100644 docs/book/en/src/contribute/build_from_src/openharmony.md delete mode 100644 docs/book/en/src/contribute/build_from_src/openwrt.md delete mode 100644 docs/book/en/src/contribute/build_from_src/plugin_wasi_crypto.md delete mode 100644 docs/book/en/src/contribute/build_from_src/plugin_wasi_logging.md delete mode 100644 docs/book/en/src/contribute/build_from_src/plugin_wasi_nn.md delete mode 100644 docs/book/en/src/contribute/build_from_src/plugin_wasmedge_process.md delete mode 100644 docs/book/en/src/contribute/build_from_src/raspberrypi.md delete mode 100644 docs/book/en/src/contribute/build_from_src/riscv64.md delete mode 100644 docs/book/en/src/contribute/build_from_src/sel4.md delete mode 100644 docs/book/en/src/contribute/build_from_src/windows.md delete mode 100644 docs/book/en/src/contribute/contribute.md delete mode 100644 docs/book/en/src/contribute/installer.md delete mode 100644 docs/book/en/src/contribute/internal.md delete mode 100644 docs/book/en/src/contribute/release_process.md delete mode 100644 docs/book/en/src/contribute/wish_list.md delete mode 100644 docs/book/en/src/develop_plugin/c.md delete mode 100644 docs/book/en/src/develop_plugin/cpp.md delete mode 100644 docs/book/en/src/develop_plugin/rust-sdk.md delete mode 100644 docs/book/en/src/features.md delete mode 100644 docs/book/en/src/features/comparison.md delete mode 100644 docs/book/en/src/features/integrations.md delete mode 100644 docs/book/en/src/features/platforms.md delete mode 100644 docs/book/en/src/features/proposals.md delete mode 100644 docs/book/en/src/features/proprietary_extend.md delete mode 100644 docs/book/en/src/index.md delete mode 100644 docs/book/en/src/plugin.md delete mode 100644 docs/book/en/src/quick_start.md delete mode 100644 docs/book/en/src/quick_start/install.md delete mode 100644 docs/book/en/src/quick_start/run_cli.md delete mode 100644 docs/book/en/src/quick_start/run_in_aot_mode.md delete mode 100644 docs/book/en/src/quick_start/use_docker.md delete mode 100644 docs/book/en/src/sdk.md delete mode 100644 docs/book/en/src/sdk/c++.md delete mode 100644 docs/book/en/src/sdk/c.md delete mode 100644 docs/book/en/src/sdk/c/0.10.1/ref.md delete mode 100644 docs/book/en/src/sdk/c/0.10.1/upgrade_to_0.11.0.md delete mode 100644 docs/book/en/src/sdk/c/0.11.2/ref.md delete mode 100644 docs/book/en/src/sdk/c/0.11.2/upgrade_to_0.12.0.md delete mode 100644 docs/book/en/src/sdk/c/0.9.1/ref.md delete mode 100644 docs/book/en/src/sdk/c/0.9.1/upgrade_to_0.10.0.md delete mode 100644 docs/book/en/src/sdk/c/externref.md delete mode 100644 docs/book/en/src/sdk/c/hostfunction.md delete mode 100644 docs/book/en/src/sdk/c/library.md delete mode 100644 docs/book/en/src/sdk/c/multimodule.md delete mode 100644 docs/book/en/src/sdk/c/ref.md delete mode 100644 docs/book/en/src/sdk/go.md delete mode 100644 docs/book/en/src/sdk/go/0.10.1/ref.md delete mode 100644 docs/book/en/src/sdk/go/0.10.1/upgrade_to_0.11.0.md delete mode 100644 docs/book/en/src/sdk/go/0.11.2/ref.md delete mode 100644 docs/book/en/src/sdk/go/0.11.2/upgrade_to_0.12.0.md delete mode 100644 docs/book/en/src/sdk/go/0.9.1/ref.md delete mode 100644 docs/book/en/src/sdk/go/0.9.1/upgrade_to_0.10.0.md delete mode 100644 docs/book/en/src/sdk/go/app.md delete mode 100644 docs/book/en/src/sdk/go/bindgen.md delete mode 100644 docs/book/en/src/sdk/go/function.md delete mode 100644 docs/book/en/src/sdk/go/memory.md delete mode 100644 docs/book/en/src/sdk/go/ref.md delete mode 100644 docs/book/en/src/sdk/go/tensorflow.md delete mode 100644 docs/book/en/src/sdk/python.md delete mode 100644 docs/book/en/src/sdk/rust.md delete mode 100644 docs/book/en/src/sdk/rust/concurrent_fib.md delete mode 100644 docs/book/en/src/sdk/rust/how_to_use_module_instance.md delete mode 100644 docs/book/en/src/sdk/rust/memory_manipulation.md delete mode 100644 docs/book/en/src/sdk/rust/say_hello.md delete mode 100644 docs/book/en/src/sdk/rust/sys_run_host_func.md delete mode 100644 docs/book/en/src/sdk/rust/table_and_funcref.md delete mode 100644 docs/book/en/src/use_cases.md delete mode 100644 docs/book/en/src/use_cases/frameworks.md delete mode 100644 docs/book/en/src/use_cases/frameworks/app.md delete mode 100644 docs/book/en/src/use_cases/frameworks/app/reactr.md delete mode 100644 docs/book/en/src/use_cases/frameworks/app/yomo.md delete mode 100644 docs/book/en/src/use_cases/frameworks/mesh.md delete mode 100644 docs/book/en/src/use_cases/frameworks/mesh/dapr.md delete mode 100644 docs/book/en/src/use_cases/frameworks/mesh/eventmesh.md delete mode 100644 docs/book/en/src/use_cases/frameworks/mesh/mosn.md delete mode 100644 docs/book/en/src/use_cases/frameworks/mesh/wasm-nginx-module.md delete mode 100644 docs/book/en/src/use_cases/frameworks/serverless.md delete mode 100644 docs/book/en/src/use_cases/frameworks/serverless/aws.md delete mode 100644 docs/book/en/src/use_cases/frameworks/serverless/netlify.md delete mode 100644 docs/book/en/src/use_cases/frameworks/serverless/secondstate.md delete mode 100644 docs/book/en/src/use_cases/frameworks/serverless/tencent.md delete mode 100644 docs/book/en/src/use_cases/frameworks/serverless/vercel.md delete mode 100644 docs/book/en/src/use_cases/js_or_dsl_runtime.md delete mode 100644 docs/book/en/src/use_cases/kubernetes.md delete mode 100644 docs/book/en/src/use_cases/kubernetes.png delete mode 100644 docs/book/en/src/use_cases/kubernetes/container.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/container/crun.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/container/runc.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/container/youki.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/cri.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/cri/containerd.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/cri/crio.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/demo.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/demo/server.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/demo/wasi.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/docker.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/docker/containerd.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/docker/lxc.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/kubernetes.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/kubernetes/kind.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/kubernetes/knative.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/kubernetes/kubeedge.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/kubernetes/kubernetes-containerd.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/kubernetes/kubernetes-crio.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/kubernetes/kwasm.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/kubernetes/openyurt.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/kubernetes/superedge.md delete mode 100644 docs/book/en/src/use_cases/kubernetes/quickstart.md delete mode 100644 docs/book/en/src/use_cases/microservice.md delete mode 100644 docs/book/en/src/use_cases/server_side_render.md delete mode 100644 docs/book/en/src/use_cases/serverless_faas.md delete mode 100644 docs/book/en/src/use_cases/serverless_saas.md delete mode 100644 docs/book/en/src/use_cases/smart_device.md delete mode 100644 docs/book/en/src/write_wasm.md delete mode 100644 docs/book/en/src/write_wasm/c.md delete mode 100644 docs/book/en/src/write_wasm/c/quickstart.md delete mode 100644 docs/book/en/src/write_wasm/c/simd.md delete mode 100644 docs/book/en/src/write_wasm/go.md delete mode 100644 docs/book/en/src/write_wasm/js.md delete mode 100644 docs/book/en/src/write_wasm/js/es6.md delete mode 100644 docs/book/en/src/write_wasm/js/modules.md delete mode 100644 docs/book/en/src/write_wasm/js/networking.md delete mode 100644 docs/book/en/src/write_wasm/js/nodejs.md delete mode 100644 docs/book/en/src/write_wasm/js/npm.md delete mode 100644 docs/book/en/src/write_wasm/js/quickstart.md delete mode 100644 docs/book/en/src/write_wasm/js/rust.md delete mode 100644 docs/book/en/src/write_wasm/js/ssr.md delete mode 100644 docs/book/en/src/write_wasm/js/tensorflow.md delete mode 100644 docs/book/en/src/write_wasm/kotlin.md delete mode 100644 docs/book/en/src/write_wasm/python.md delete mode 100644 docs/book/en/src/write_wasm/rust.md delete mode 100644 docs/book/en/src/write_wasm/rust/bindgen.md delete mode 100644 docs/book/en/src/write_wasm/rust/command.md delete mode 100644 docs/book/en/src/write_wasm/rust/networking-nonblocking.md delete mode 100644 docs/book/en/src/write_wasm/rust/networking.md delete mode 100644 docs/book/en/src/write_wasm/rust/ssr.md delete mode 100644 docs/book/en/src/write_wasm/rust/tensorflow.md delete mode 100644 docs/book/en/src/write_wasm/rust/wasi.md delete mode 100644 docs/book/en/src/write_wasm/rust/wasicrypto.md delete mode 100644 docs/book/en/src/write_wasm/rust/wasinn.md delete mode 100644 docs/book/en/src/write_wasm/swift.md delete mode 100644 docs/book/en/theme/css/chrome.css delete mode 100644 docs/book/en/theme/css/general.css delete mode 100644 docs/book/en/theme/css/variables.css delete mode 100644 docs/book/en/theme/head.hbs create mode 100644 docs/embargo-policy.md create mode 100644 docs/self-assessment.md create mode 100644 include/common/executable.h rename include/common/{log.h => spdlog.h} (90%) create mode 100644 include/host/mock/wasmedge_stablediffusion_func.h create mode 100644 include/host/mock/wasmedge_stablediffusion_module.h create mode 100644 include/llvm/codegen.h rename include/{aot => llvm}/compiler.h (77%) create mode 100644 include/llvm/data.h create mode 100644 include/llvm/jit.h create mode 100644 include/loader/aot_section.h delete mode 100644 include/loader/ldmgr.h create mode 100644 include/plugin/wasi_logging/base.h create mode 100644 include/plugin/wasi_logging/env.h create mode 100644 include/plugin/wasi_logging/func.h create mode 100644 include/plugin/wasi_logging/module.h create mode 100644 include/runtime/instance/array.h create mode 100644 include/runtime/instance/component.h create mode 100644 include/runtime/instance/composite.h create mode 100644 include/runtime/instance/struct.h create mode 100644 include/runtime/instance/tag.h delete mode 100644 lib/common/int128.cpp rename lib/common/{log.cpp => spdlog.cpp} (85%) create mode 100644 lib/executor/engine/refInstr.cpp create mode 100644 lib/executor/instantiate/component.cpp create mode 100644 lib/executor/instantiate/component/instantiate_component_alias.cpp create mode 100644 lib/executor/instantiate/component/instantiate_component_canon.cpp create mode 100644 lib/executor/instantiate/component/instantiate_component_export.cpp create mode 100644 lib/executor/instantiate/component/instantiate_component_import.cpp create mode 100644 lib/executor/instantiate/component/instantiate_component_instance.cpp create mode 100644 lib/executor/instantiate/component/instantiate_component_start.cpp create mode 100644 lib/executor/instantiate/component/instantiate_component_type.cpp create mode 100644 lib/executor/instantiate/tag.cpp create mode 100644 lib/llvm/CMakeLists.txt create mode 100644 lib/llvm/codegen.cpp rename lib/{aot => llvm}/compiler.cpp (88%) create mode 100644 lib/llvm/data.cpp create mode 100644 lib/llvm/data.h create mode 100644 lib/llvm/jit.cpp rename lib/{aot => llvm}/llvm.h (77%) create mode 100644 lib/loader/aot_section.cpp rename lib/loader/ast/component/{alias.cpp => component_alias.cpp} (97%) rename lib/loader/ast/component/{canonical.cpp => component_canonical.cpp} (98%) rename lib/loader/ast/component/{import_export.cpp => component_import_export.cpp} (95%) rename lib/loader/ast/component/{instance.cpp => component_instance.cpp} (98%) rename lib/loader/ast/component/{sort.cpp => component_sort.cpp} (97%) rename lib/loader/ast/component/{start.cpp => component_start.cpp} (93%) delete mode 100644 lib/loader/ldmgr.cpp create mode 100644 lib/plugin/wasi_logging/CMakeLists.txt create mode 100644 lib/plugin/wasi_logging/func.cpp create mode 100644 lib/plugin/wasi_logging/module.cpp create mode 100644 plugins/wasi_http/CMakeLists.txt create mode 100644 plugins/wasi_http/README.md create mode 100644 plugins/wasi_http/base.h create mode 100644 plugins/wasi_http/env.cpp create mode 100644 plugins/wasi_http/env.h create mode 100644 plugins/wasi_http/func.cpp create mode 100644 plugins/wasi_http/func.h create mode 100644 plugins/wasi_http/module.cpp create mode 100644 plugins/wasi_http/module.h delete mode 100644 plugins/wasi_logging/CMakeLists.txt delete mode 100644 plugins/wasi_logging/env.cpp delete mode 100644 plugins/wasi_logging/func.cpp delete mode 100644 plugins/wasi_logging/module.cpp delete mode 100644 plugins/wasi_logging/wasi_logging/base.h delete mode 100644 plugins/wasi_logging/wasi_logging/enum.h delete mode 100644 plugins/wasi_logging/wasi_logging/env.h delete mode 100644 plugins/wasi_logging/wasi_logging/func.h delete mode 100644 plugins/wasi_logging/wasi_logging/module.h create mode 100644 plugins/wasi_nn/chattts.cpp create mode 100644 plugins/wasi_nn/chattts.h create mode 100644 plugins/wasi_nn/neuralspeed.cpp create mode 100644 plugins/wasi_nn/neuralspeed.h create mode 100644 plugins/wasi_nn/piper.cpp create mode 100644 plugins/wasi_nn/piper.h create mode 100644 plugins/wasi_nn/piper.patch create mode 100644 plugins/wasi_nn/whispercpp.cpp create mode 100644 plugins/wasi_nn/whispercpp.h rename plugins/{wasmedge_rustls => wasi_nn_burnrs}/.gitignore (100%) create mode 100644 plugins/wasi_nn_burnrs/CMakeLists.txt create mode 100644 plugins/wasi_nn_burnrs/Cargo.toml create mode 100644 plugins/wasi_nn_burnrs/src/helper.rs create mode 100644 plugins/wasi_nn_burnrs/src/lib.rs create mode 100644 plugins/wasi_nn_burnrs/src/models/mod.rs create mode 100644 plugins/wasi_nn_burnrs/src/models/squeezenet.rs create mode 100644 plugins/wasi_nn_burnrs/src/models/whisper.rs create mode 100644 plugins/wasi_poll/CMakeLists.txt create mode 100644 plugins/wasi_poll/README.md create mode 100644 plugins/wasi_poll/base.h create mode 100644 plugins/wasi_poll/env.cpp create mode 100644 plugins/wasi_poll/env.h create mode 100644 plugins/wasi_poll/func.cpp create mode 100644 plugins/wasi_poll/func.h create mode 100644 plugins/wasi_poll/module.cpp create mode 100644 plugins/wasi_poll/module.h create mode 100644 plugins/wasmedge_ffmpeg/CMakeLists.txt create mode 100644 plugins/wasmedge_ffmpeg/avcodec/avCodec.cpp create mode 100644 plugins/wasmedge_ffmpeg/avcodec/avCodec.h create mode 100644 plugins/wasmedge_ffmpeg/avcodec/avCodecContext.cpp create mode 100644 plugins/wasmedge_ffmpeg/avcodec/avCodecContext.h create mode 100644 plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.cpp create mode 100644 plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.h create mode 100644 plugins/wasmedge_ffmpeg/avcodec/avPacket.cpp create mode 100644 plugins/wasmedge_ffmpeg/avcodec/avPacket.h create mode 100644 plugins/wasmedge_ffmpeg/avcodec/avcodec_func.cpp create mode 100644 plugins/wasmedge_ffmpeg/avcodec/avcodec_func.h create mode 100644 plugins/wasmedge_ffmpeg/avcodec/module.cpp create mode 100644 plugins/wasmedge_ffmpeg/avcodec/module.h create mode 100644 plugins/wasmedge_ffmpeg/avdevice/avDevice_func.cpp create mode 100644 plugins/wasmedge_ffmpeg/avdevice/avDevice_func.h create mode 100644 plugins/wasmedge_ffmpeg/avdevice/module.cpp create mode 100644 plugins/wasmedge_ffmpeg/avdevice/module.h create mode 100644 plugins/wasmedge_ffmpeg/avfilter/avFilter.cpp create mode 100644 plugins/wasmedge_ffmpeg/avfilter/avFilter.h create mode 100644 plugins/wasmedge_ffmpeg/avfilter/avfilter_func.cpp create mode 100644 plugins/wasmedge_ffmpeg/avfilter/avfilter_func.h create mode 100644 plugins/wasmedge_ffmpeg/avfilter/buffer_source_sink.cpp create mode 100644 plugins/wasmedge_ffmpeg/avfilter/buffer_source_sink.h create mode 100644 plugins/wasmedge_ffmpeg/avfilter/module.cpp create mode 100644 plugins/wasmedge_ffmpeg/avfilter/module.h create mode 100644 plugins/wasmedge_ffmpeg/avformat/avChapter.cpp create mode 100644 plugins/wasmedge_ffmpeg/avformat/avChapter.h create mode 100644 plugins/wasmedge_ffmpeg/avformat/avInputOutputFormat.cpp create mode 100644 plugins/wasmedge_ffmpeg/avformat/avInputOutputFormat.h create mode 100644 plugins/wasmedge_ffmpeg/avformat/avStream.cpp create mode 100644 plugins/wasmedge_ffmpeg/avformat/avStream.h create mode 100644 plugins/wasmedge_ffmpeg/avformat/avformatContext.cpp create mode 100644 plugins/wasmedge_ffmpeg/avformat/avformatContext.h create mode 100644 plugins/wasmedge_ffmpeg/avformat/avformat_func.cpp create mode 100644 plugins/wasmedge_ffmpeg/avformat/avformat_func.h create mode 100644 plugins/wasmedge_ffmpeg/avformat/module.cpp create mode 100644 plugins/wasmedge_ffmpeg/avformat/module.h create mode 100644 plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp create mode 100644 plugins/wasmedge_ffmpeg/avutil/avDictionary.h create mode 100644 plugins/wasmedge_ffmpeg/avutil/avFrame.cpp create mode 100644 plugins/wasmedge_ffmpeg/avutil/avFrame.h create mode 100644 plugins/wasmedge_ffmpeg/avutil/avRational.cpp create mode 100644 plugins/wasmedge_ffmpeg/avutil/avRational.h create mode 100644 plugins/wasmedge_ffmpeg/avutil/avTime.cpp create mode 100644 plugins/wasmedge_ffmpeg/avutil/avTime.h create mode 100644 plugins/wasmedge_ffmpeg/avutil/avutil_func.cpp create mode 100644 plugins/wasmedge_ffmpeg/avutil/avutil_func.h create mode 100644 plugins/wasmedge_ffmpeg/avutil/error.cpp create mode 100644 plugins/wasmedge_ffmpeg/avutil/error.h create mode 100644 plugins/wasmedge_ffmpeg/avutil/module.cpp create mode 100644 plugins/wasmedge_ffmpeg/avutil/module.h create mode 100644 plugins/wasmedge_ffmpeg/avutil/pixfmt.cpp create mode 100644 plugins/wasmedge_ffmpeg/avutil/pixfmt.h create mode 100644 plugins/wasmedge_ffmpeg/avutil/samplefmt.cpp create mode 100644 plugins/wasmedge_ffmpeg/avutil/samplefmt.h create mode 100644 plugins/wasmedge_ffmpeg/bindings.h create mode 100644 plugins/wasmedge_ffmpeg/ffmpeg_base.h create mode 100644 plugins/wasmedge_ffmpeg/ffmpeg_env.cpp create mode 100644 plugins/wasmedge_ffmpeg/ffmpeg_env.h create mode 100644 plugins/wasmedge_ffmpeg/swresample/module.cpp create mode 100644 plugins/wasmedge_ffmpeg/swresample/module.h create mode 100644 plugins/wasmedge_ffmpeg/swresample/swresample_func.cpp create mode 100644 plugins/wasmedge_ffmpeg/swresample/swresample_func.h create mode 100644 plugins/wasmedge_ffmpeg/swscale/module.cpp create mode 100644 plugins/wasmedge_ffmpeg/swscale/module.h create mode 100644 plugins/wasmedge_ffmpeg/swscale/swscale_func.cpp create mode 100644 plugins/wasmedge_ffmpeg/swscale/swscale_func.h create mode 100644 plugins/wasmedge_llmc/CMakeLists.txt create mode 100644 plugins/wasmedge_llmc/llmc_base.h create mode 100644 plugins/wasmedge_llmc/llmc_env.cpp create mode 100644 plugins/wasmedge_llmc/llmc_env.h create mode 100644 plugins/wasmedge_llmc/llmc_func.cpp create mode 100644 plugins/wasmedge_llmc/llmc_func.h create mode 100644 plugins/wasmedge_llmc/llmc_fwd.h create mode 100644 plugins/wasmedge_llmc/llmc_module.cpp create mode 100644 plugins/wasmedge_llmc/llmc_module.h create mode 100644 plugins/wasmedge_ocr/CMakeLists.txt create mode 100644 plugins/wasmedge_ocr/ocr_base.h create mode 100644 plugins/wasmedge_ocr/ocr_env.cpp create mode 100644 plugins/wasmedge_ocr/ocr_env.h create mode 100644 plugins/wasmedge_ocr/ocr_func.cpp create mode 100644 plugins/wasmedge_ocr/ocr_func.h create mode 100644 plugins/wasmedge_ocr/ocr_module.cpp create mode 100644 plugins/wasmedge_ocr/ocr_module.h delete mode 100644 plugins/wasmedge_rustls/CMakeLists.txt delete mode 100644 plugins/wasmedge_rustls/Cargo.toml delete mode 100644 plugins/wasmedge_rustls/src/lib.rs create mode 100644 plugins/wasmedge_stablediffusion/CMakeLists.txt create mode 100644 plugins/wasmedge_stablediffusion/sd_base.h create mode 100644 plugins/wasmedge_stablediffusion/sd_env.cpp create mode 100644 plugins/wasmedge_stablediffusion/sd_env.h create mode 100644 plugins/wasmedge_stablediffusion/sd_func.cpp create mode 100644 plugins/wasmedge_stablediffusion/sd_func.h create mode 100644 plugins/wasmedge_stablediffusion/sd_module.cpp create mode 100644 plugins/wasmedge_stablediffusion/sd_module.h create mode 100644 test/llvm/CMakeLists.txt rename test/{aot/AOTcoreTest.cpp => llvm/LLVMcoreTest.cpp} (73%) create mode 100644 test/plugins/wasmedge_ffmpeg/CMakeLists.txt create mode 100644 test/plugins/wasmedge_ffmpeg/avcodec/avCodec.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avcodec/avCodecCtx.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avcodec/avPacket.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avcodec/avcodec_func.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avfilter/avfilter.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avfilter/avfilter_func.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avformat/avChapter.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avformat/avInputOutputContext.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avformat/avStream.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avformat/avformatContext.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avformat/avformat_func.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avutil/avError.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avutil/avFrame.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avutil/avPixfmt.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avutil/avRational.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avutil/avSampleFmt.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/avutil/avutil_func.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/main.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/swresample/swresample_func.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/swscale/swscale_func.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/utils.cpp create mode 100644 test/plugins/wasmedge_ffmpeg/utils.h create mode 100644 test/plugins/wasmedge_llmc/CMakeLists.txt create mode 100644 test/plugins/wasmedge_llmc/wasmedge_llmc.cpp delete mode 100644 test/plugins/wasmedge_rustls/CMakeLists.txt delete mode 100644 test/plugins/wasmedge_rustls/wasmedge_rustls.cpp create mode 100644 test/plugins/wasmedge_stablediffusion/CMakeLists.txt create mode 100644 test/plugins/wasmedge_stablediffusion/wasmedge_stablediffusion.cpp delete mode 100644 thirdparty/ggml/ggml.patch delete mode 100644 utils/docker/Dockerfile.base delete mode 100644 utils/docker/Dockerfile.build-clang delete mode 100644 utils/docker/Dockerfile.build-gcc delete mode 100644 utils/docker/Dockerfile.build-plugins-deps create mode 100644 utils/docker/Dockerfile.manylinux_2_28-base create mode 100644 utils/docker/Dockerfile.manylinux_2_28-plugins-deps create mode 100644 utils/docker/Dockerfile.ubuntu-base create mode 100644 utils/docker/Dockerfile.ubuntu-gcc create mode 100644 utils/docker/Dockerfile.ubuntu-plugins-deps delete mode 100644 utils/docker/SHA256SUM create mode 100644 utils/docker/SHA256SUM.manylinux2014 create mode 100644 utils/docker/SHA256SUM.manylinux_2_28 delete mode 100755 utils/docker/build.sh create mode 100644 utils/docker/docker-bake.ci-image-base.hcl create mode 100644 utils/docker/docker-bake.manylinux.hcl create mode 100644 utils/docker/docker-bake.ubuntu.hcl delete mode 100644 utils/docker/install-opencvmini.sh create mode 100644 utils/ffmpeg/download-ffmpeg-sample-video.sh create mode 100755 utils/ffmpeg/install-ffmpeg-v6.0.sh create mode 100755 utils/install_v2.sh delete mode 100755 utils/wasi-nn/download-ggml-fixtures.sh delete mode 100755 utils/wasi-nn/download-openvino-fixtures.sh delete mode 100755 utils/wasi-nn/download-pytorch-fixtures.sh delete mode 100755 utils/wasi-nn/download-tflite-fixtures.sh create mode 100644 utils/wasi-nn/install-onnxruntime.sh diff --git a/.CurrentChangelog.md b/.CurrentChangelog.md index a23a94d89dd2..9793fb24c0d0 100644 --- a/.CurrentChangelog.md +++ b/.CurrentChangelog.md @@ -1,108 +1,49 @@ -### 0.14.0-alpha.1 (2024-01-05) - -Breaking changes: - -* [Version]: Bump the version of the WasmEdge shared library. - * Due to the breaking change of API, bump the `SOVERSION` to `0.1.0`. - * Due to the breaking change of API, bump the plug-in `API_VERSION` to `3`. -* [C API]: Changes for applying Typed Function References Proposal. - * New `WasmEdge_ValType` structure for replacing `enum WasmEdge_ValType`. - * Merge the `enum WasmEdge_ValType` and `enum WasmEdge_RefType` into the `enum WasmEdge_TypeCode`. - * Refactored the error code. The error code number may different from previous versions. - * Extend the error code to 2 bytes. - * Updated the related APIs for using `enum WasmEdge_ValType` as parameters. - * `WasmEdge_FunctionTypeCreate()` - * `WasmEdge_FunctionTypeGetParameters()` - * `WasmEdge_FunctionTypeGetReturns()` - * `WasmEdge_TableTypeCreate()` - * `WasmEdge_TableTypeGetRefType()` - * `WasmEdge_GlobalTypeCreate()` - * `WasmEdge_GlobalTypeGetValType()` - * Removed `WasmEdge_ValueGenNullRef()` API. - * Due to non-defaultable values after this proposal, the following APIs return the result instead of void. - * `WasmEdge_GlobalInstanceSetValue()` - * Introduced the `WasmEdge_Bytes` structure. - * This structure is for packaging the `uint8_t` buffers. The old `FromBuffer` related APIs will be replaced by the corresponding APIs in the future versions. - * `WasmEdge_CompilerCompileFromBytes()` API has the same function as `WasmEdge_CompilerCompileFromBuffer()` and will replace it in the future. - * `WasmEdge_LoaderParseFromBytes()` API has the same function as `WasmEdge_LoaderParseFromBuffer()` and will replace it in the future. - * `WasmEdge_VMRegisterModuleFromBytes()` API has the same function as `WasmEdge_VMRegisterModuleFromBuffer()` and will replace it in the future. - * `WasmEdge_VMRunWasmFromBytes()` API has the same function as `WasmEdge_VMRunWasmFromBuffer()` and will replace it in the future. - * `WasmEdge_VMAsyncRunWasmFromBytes()` API has the same function as `WasmEdge_VMAsyncRunWasmFromBuffer()` and will replace it in the future. - * `WasmEdge_VMLoadWasmFromBytes()` API has the same function as `WasmEdge_VMLoadWasmFromBuffer()` and will replace it in the future. +### 0.14.1 (2024-09-16) Features: -* [Proposal]: Apply new propoals. - * Supported WASM Typed Function References proposal. - * Added the `WasmEdge_Proposal_FunctionReferences` for the configuration in WasmEdge C API. - * Users can use the `--enable-function-reference` to enable the proposal in `wasmedge` and `wasmedgec` tools. - * Component Model proposal (experimental, loader phase only). - * Added the `WasmEdge_Proposal_Component` for the configuration in WasmEdge C API. - * Users can use the `--enable-function-reference` to enable the proposal in `wasmedge` tool. -* [C API]: New C API for supporting the new proposals. - * `WasmEdge_ValType` related APIs can help developers to generate or compare value types. - * `WasmEdge_ValTypeGenI32()` (replacing `WasmEdge_ValType_I32`) - * `WasmEdge_ValTypeGenI64()` (replacing `WasmEdge_ValType_I64`) - * `WasmEdge_ValTypeGenF32()` (replacing `WasmEdge_ValType_F32`) - * `WasmEdge_ValTypeGenF64()` (replacing `WasmEdge_ValType_F64`) - * `WasmEdge_ValTypeGenV128()` (replacing `WasmEdge_ValType_V128`) - * `WasmEdge_ValTypeGenFuncRef()` (replacing `WasmEdge_ValType_FuncRef`) - * `WasmEdge_ValTypeGenExternRef()` (replacing `WasmEdge_ValType_ExternRef`) - * `WasmEdge_ValTypeIsEqual()` - * `WasmEdge_ValTypeIsI32()` - * `WasmEdge_ValTypeIsI64()` - * `WasmEdge_ValTypeIsF32()` - * `WasmEdge_ValTypeIsF64()` - * `WasmEdge_ValTypeIsV128()` - * `WasmEdge_ValTypeIsFuncRef()` - * `WasmEdge_ValTypeIsExternRef()` - * `WasmEdge_ValTypeIsRef()` - * `WasmEdge_ValTypeIsRefNull()` - * `WasmEdge_Bytes` related APIs can help developers to control the buffers. - * `WasmEdge_BytesCreate()` - * `WasmEdge_BytesWrap()` - * `WasmEdge_BytesDelete()` - * `WasmEdge_TableInstanceCreateWithInit()` to create a table instance with non-defaultable elements with assigning the initial value. -* [Serializer]: Supported WASM module serialization (experimental). - * This is the API-level feature. Developers can use the `WasmEdge_LoaderSerializeASTModule()` API to serialize a loaded WASM module into bytes. -* [Tools]: Print the plug-in versions when using the `--version` option. -* [Installer]: Enabled `ggml-blas` and `rustls` plugin supporting (#3032) (#3108). +* Supported LLVM 17.0.6. +* Bumpped `spdlog` to `v1.13.0`. +* Bumpped `fmt` to `11.0.2`. +* Bumpped `simdjson` to `v3.10.0`. +* Bumpped `googletest` to `1.15.2`. * [WASI-NN] ggml backend: - * Bump llama.cpp to b1743 - * Support llama.cpp options: - * `threads`: the thread number for inference. - * `temp`: set temperature for inference. - * `repeat-penalty`: set repeat penalty for inference. - * Add `enable-debug-log` option to show more debug information. - * Default enable Metal on macOS. - * Introduce `load_by_name_with_config()` to load model with metadata. - * Introduce single token inference by `compute_single`, `get_output_single`, and `fini_single` - * Add some llama errors to WASI-NN - * `EndOfSequence`: returned when encounter `` token on single token inferece. - * `ContextFull`: returned when the context is full. - * `PromptTooLong`: returned when the input size is too large. + * Bump llama.cpp to b3651. + * Static link `libggml` and `libllama`. + * Refined the CMake to support multiple backends of WASI-NN with ggml backend. + * Supported compute single in RPC mode. +* [WASI-NN] Added support for whisper.cpp backend. +* [WASI-NN] Added support for piper backend. +* [WASI-NN] Added support for ChatTTS backend. +* [WASI-NN] Added support for Burn.rs backend. + * Supported `squeezenet` and `whisper` models. +* [Plugin] Supported `wasmedge_stablediffusion` plug-in. + * Enabled CUBLAS. + * Enabled metal support on MacOS. +* [Plugin] Moved `wasi_logging` into built-in plug-in. + * Instead of installing `wasi_logging` plug-in shared library, developers can find and get this plug-in after calling `WasmEdge_PluginLoadWithDefaultPaths()` API. + * In the WasmEdge CLI tools, the built-in plug-ins will automatically be loaded. +* [Proposal] Initial support for instantiation phase of component model. + * Due to the breaking change of API, bump the plug-in `API_VERSION` to `3`. +* [Proposal] Supported WASM Relaxed-SIMD proposal. + * Added the `WasmEdge_Proposal_RelaxSIMD` for the configuration in WasmEdge C API. + * Users can use the `--enable-relaxed-simd` to enable the proposal in `wasmedge` and `wasmedgec` tools. Fixed issues: -* Fixed some API document in the API header. -* [WASI]: Minor fixes. - * Fixed the function signature matching for WASI imports when backwarding supporting older version. (#3073) - * Fixed large timestamp causing overflow (#3106). - * Handle HUP only events. - * Checking same file descriptor for `fd_renumber` (#3040). - * Fixed `path_unlink_file` for trailing slash path. - * Fixed `path_readlink` for not following symbolic link issue. - * Fixed `path_open` for checking `O_TRUNC` rights. - * Fixed `path_open` for removing path relative rights on file. - * Checking `path_symlink` for creating a symlink to an absolute path. - * Checking `fd_prestat_dir_name` buffer size. - * Checking `filestat_set_times` for invalid flags. - * Checking validation of file descriptor in `socket_accept` (#3041). +* Fixed warnings on GCC-14. +* Fixed the `fmt` related header inclusion for error logging. +* Fixed WASI test error in Windows. +* Fixed version checking in source tarball. +* Fixed version detection issue when building from source. +* Fixed the visibility of internal symbols. +* [Loader] Fixed alignment checking in loading immediates for memory instructions. +* [Runtime] Fixed allocation issue when configured the limited memory page size. +* Used `fmt::format` instead of string stream in error logging. Tests: -* Updated the WASM spec tests to the date 2023/10/26. -* Added the spec tests for the Typed Function Reference proposal. +* Added WASI test suites on Windows. Known issues: @@ -112,6 +53,6 @@ Known issues: Thank all the contributors who made this release possible! -Abhinandan Udupa, Akihiro Suda, Dhruv Jain, Draco, Little Willy, Lîm Tsú-thuàn, Meenu Yadav, Omkar Acharekar, Saiyam Pathak, Shen-Ta Hsieh, Shreyas Atre, Yage Hu, Yi-Ying He, alabulei1, am009, dm4, hydai, richzw, zhumeme +Biswapriyo Nath, Elmira, Faidon Liambotis, Fusaaaann, Han-Wen Tsao, Jun Zhang, Kefu Chai, Lîm Tsú-thuàn, Michael Morris, PeterD1524, Shen-Ta Hsieh, Shreyas Atre, Sylveon, Yi Huang, Yi-Ying He, alabulei1, dm4, grorge, hydai, junxiangMu, vincent -If you want to build from source, please use WasmEdge-0.14.0-alpha.1-src.tar.gz instead of the zip or tarball provided by GitHub directly. +If you want to build from source, please use WasmEdge-0.14.1-src.tar.gz instead of the zip or tarball provided by GitHub directly. diff --git a/.clang-tidy b/.clang-tidy index 3f407e0160e6..3787b22feae4 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -14,4 +14,3 @@ CheckOptions: value: CamelCase - key: readability-identifier-naming.VariableCase value: CamelCase - diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index da2534d545ec..95058cfd36d3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,28 +1,129 @@ # Global rule: -* @hydai -.devcontainer/ @hydai -.github/ @hydai -bindings/ @hydai -bindings/rust/ @hydai @yanganto -bindings/java/ @dannypsnl -cmake/ @ibmibmibm -docs/ @hydai -include/ @q82419 -lib/ @q82419 -**/aot/ @ibmibmibm -**/host/wasi/ @ibmibmibm -**/system/ @ibmibmibm -**/api/ @q82419 -plugins/ @ibmibmibm -plugins/wasi_logging/ @michael1017 -rpm/ @hydai @dm4 -test/ @q82419 -test/aot/ @ibmibmibm -test/host/wasi/ @ibmibmibm -test/po/ @ibmibmibm -test/span/ @ibmibmibm -thirdparty/ @ibmibmibm -tools/ @hydai @ibmibmibm @q82419 -utils/ @hydai @ibmibmibm @q82419 -utils/install.sh @SAtacker -utils/uninstall.sh @SAtacker +# General Owner: @hydai +* @hydai + +# Specific Files +# General Owner: @dannypsnl +*.nix @dannypsnl + +# GitHub Actions +# General Owner: @hydai +.devcontainer/ @hydai +.github/ @hydai +.github/actions/ @0yi0 +.github/workflows/ @0yi0 + +# Language Bindings +# General Owner: @hydai +bindings/ @hydai +bindings/java/ @dannypsnl + +# CMake +# General Owner: @ibmibmibm +cmake/ @ibmibmibm + +# Documentation +# General Owner: @hydai +docs/ @hydai + +# Examples +# General Owner: @q82419 +examples/ @q82419 +examples/capi/unix_domain_socket/ @hydai +examples/capi/wasi-env/ @hydai +examples/js/ @hydai + +# Source Codes +# General Owner: @ibmibmibm @q82419 +include/ @q82419 @ibmibmibm +lib/ @q82419 @ibmibmibm + +**/aot/ @ibmibmibm +**/api/ @q82419 +**/common/ @ibmibmibm +**/driver/ @ibmibmibm +**/executor/ @q82419 +**/host/ @q82419 +**/host/wasi/ @ibmibmibm +**/llvm/ @ibmibmibm +**/loader/ @q82419 @ibmibmibm @dannypsnl +**/plugin/ @ibmibmibm +**/po/ @ibmibmibm +**/system/ @ibmibmibm +**/validator/ @q82419 @dannypsnl +**/vm/ @q82419 @dannypsnl + +include/ast/ @q82419 +include/ast/component/ @dannypsnl +include/driver/wasi_nn_rpc/ @dm4 +include/experimental/ @ibmibmibm +include/runtime/ @q82419 @dannypsnl +lib/loader/ast/ @q82419 +lib/loader/ast/component/ @dannypsnl +lib/loader/serialize/ @q82419 +lib/wasi_nn_rpc/ @dm4 + +plugins/ @hydai +plugins/wasi_crypto/ @sonder-joker +plugins/wasi_logging/ @michael1017 @q82419 +plugins/wasi_nn/ @dm4 @hydai +plugins/wasmedge_image/ @q82419 +plugins/wasmedge_opencvmini/ @dannypsnl +plugins/wasmedge_process/ @q82419 +plugins/wasmedge_tensorflow/ @q82419 +plugins/wasmedge_tensorflowlite/ @q82419 + +# Tests +test/ @q82419 @ibmibmibm +test/aot/ @ibmibmibm +test/api/ @q82419 +test/common/ @ibmibmibm +test/errinfo/ @q82419 +test/executor/ @q82419 +test/expected/ @ibmibmibm +test/externref/ @q82419 +test/host/ @q82419 @ibmibmibm +test/host/mock/ @q82419 +test/host/socket/ @ibmibmibm +test/host/wasi/ @ibmibmibm +test/llvm/ @ibmibmibm +test/loader/ @q82419 @dannypsnl +test/memlimit/ @q82419 +test/mixcall/ @q82419 +test/plugins/ @hydai +test/plugins/unittest/ @q82419 +test/plugins/wasi_crypto/ @sonder-joker @hydai +test/plugins/wasi_logging/ @michael1017 @q82419 +test/plugins/wasi_nn/ @dm4 @hydai +test/plugins/wasm_bpf/ @hydai +test/plugins/wasmedge_ffmpeg/ @hydai +test/plugins/wasmedge_image/ @q82419 +test/plugins/wasmedge_opencvmini/ @dannypsnl +test/plugins/wasmedge_process/ @q82419 +test/plugins/wasmedge_tensorflow/ @q82419 +test/plugins/wasmedge_tensorflowlite/ @q82419 +test/plugins/wasmedge_zlib/ @hydai +test/po/ @ibmibmibm +test/span/ @ibmibmibm +test/spec/ @q82419 +test/thread/ @ibmibmibm + +# Thirdparty Libraries +thirdparty/ @ibmibmibm +thirdparty/wasi_crypto/ @sonder-joker @hydai + +# Tools +tools/ @ibmibmibm + +# Utils +utils/ @hydai +utils/corpus/ @ibmibmibm +utils/docker/ @hydai @0yi0 +utils/install* @SAtacker +utils/uninstall.sh @SAtacker +utils/opencvmini/ @dannypsnl +utils/openwrt/ @ibmibmibm +utils/wasi-cpp-header/ @ibmibmibm +utils/wasi-crypto/ @sonder-joker +utils/wasi-nn/ @dm4 +utils/wasi-test/ @ibmibmibm diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 0b45d8453b09..afbeaedaab5e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -100,6 +100,6 @@ body: placeholder: | - C++ Compiler version: - CMake version: - - CMake flags: (e.g. `-DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_AOT_RUNTIME=ON`) + - CMake flags: (e.g. `-DCMAKE_BUILD_TYPE=Release -DWASMEDGE_USE_LLVM=ON`) validations: required: false diff --git a/.github/ISSUE_TEMPLATE/lfx_mentorship_idea.yml b/.github/ISSUE_TEMPLATE/lfx_mentorship_idea.yml new file mode 100644 index 000000000000..6a259626f15d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/lfx_mentorship_idea.yml @@ -0,0 +1,70 @@ +name: "LFX Mentorship Project Idea" +description: This template is for submitting a project idea for the LFX Mentorship program. +title: "LFX mentorship (): " +labels: ["LFX Mentorship", "LFX Mentorship Idea"] +projects: ["WasmEdge/8"] +body: + - type: textarea + id: project-title + attributes: + label: "Project Title" + description: Please shortly describe the project title you want to propose for the LFX Mentorship program. + placeholder: Describe in one line + validations: + required: true + - type: textarea + id: description + attributes: + label: "Description" + description: Please shortly describe the project content you want to propose for the LFX Mentorship program. + placeholder: Describe in a few lines about the project content. + validations: + required: true + - type: textarea + id: expected-outcome + attributes: + label: "Expected Outcome" + description: Please shortly describe the expected outcome of the project you want to propose for the LFX Mentorship program. + placeholder: Describe in several bullet points about the expected outcome. E.g. A new feature, a new tool, etc. + validations: + required: true + - type: textarea + id: recommend-skills + attributes: + label: "Recommend skills" + description: Please shortly describe the recommend skills for the project you want to propose for the LFX Mentorship program. + placeholder: Describe in several bullet points about the recommend skills. E.g. C++, Rust, WebAssembly, etc. + validations: + required: true + - type: textarea + id: pre-tests + attributes: + label: "Pre-tests" + description: Please shortly describe the pre-tests for the project you want to propose for the LFX Mentorship program. + placeholder: This is optional, if you have any pre-tests for the project, please describe in several bullet points. Otherwise, you can leave it "N/A". + validations: + required: true + - type: textarea + id: mentors + attributes: + label: "Mentor(s)" + description: Please write down the mentor(s) in this format, e.g. "MentorName (@MentorGitHubID, MentorEmail)" + placeholder: According to the CNCF policy, at least two mentors(one for major, another for backup) are required for each project. + validations: + required: true + - type: textarea + id: apply-link + attributes: + label: "Apply Link" + description: Leave TBD if you don't have the apply link yet. + placeholder: TBD + validations: + required: true + - type: textarea + id: appendix + attributes: + label: "Appendix" + description: Please provide any additional information you want to share. + placeholder: This is optional, if you have any additional information, please describe in several bullet points. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/mentoring_workspace.yml b/.github/ISSUE_TEMPLATE/mentoring_workspace.yml new file mode 100644 index 000000000000..2be6d6b056c6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/mentoring_workspace.yml @@ -0,0 +1,54 @@ +name: "Mentorship Workspace" +description: This template is for mentees to submit a project workspace for the mentoring programs, including OSPP, GSoC, and LFX mentorship. +title: "<Mentoring Program, e.g. LFX> Workspace: <title>" +labels: ["LFX Mentorship", "LFX Mentorship Workspace"] +projects: ["WasmEdge/8"] +body: + - type: textarea + id: project-title + attributes: + label: "Project Title" + description: Please shortly describe the project title + placeholder: Describe in one line + validations: + required: true + - type: textarea + id: motivation + attributes: + label: "Motivation" + description: Please describe the motivation for the project + placeholder: Describe in a few lines about the motivation for the project + validations: + required: true + - type: textarea + id: expected-outcome + attributes: + label: "Expected Outcome" + description: Please shortly describe the expected outcome of the project + placeholder: Describe in several bullet points about the expected outcome. E.g. A new feature, a new tool, etc. + validations: + required: true + - type: textarea + id: details + attributes: + label: "Details" + description: Please describe the details of the project + placeholder: Describe in a few lines about the details of the project + validations: + required: true + - type: textarea + id: milestones + attributes: + label: "Milestones" + description: Please describe the milestones and corresponding timeline of the project. Each milestone should be clear and measurable. + placeholder: Describe in several bullet points about the milestones and corresponding timeline of the project + validations: + required: true + - type: textarea + id: appendix + attributes: + label: "Appendix" + description: Please provide any additional information you want to share. + placeholder: This is optional, if you have any additional information, please describe in several bullet points. + validations: + required: false diff --git a/.github/actions/expand-variables/README.md b/.github/actions/expand-variables/README.md deleted file mode 100644 index c2e94c386821..000000000000 --- a/.github/actions/expand-variables/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Update dist/* with: - -``` -ncc build main.js --license license.txt -``` - -* https://docs.github.com/en/actions/creating-actions/creating-a-javascript-action diff --git a/.github/actions/expand-variables/action.yml b/.github/actions/expand-variables/action.yml deleted file mode 100644 index 18e8a79d3cbf..000000000000 --- a/.github/actions/expand-variables/action.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: Expand Variables -description: Generate variables for building WasmEdge extensions - -outputs: - matrix: - description: list of {arch, runner, docker_tag, plugins} - -runs: - using: node20 - main: "dist/index.js" diff --git a/.github/actions/expand-variables/dist/index.js b/.github/actions/expand-variables/dist/index.js deleted file mode 100644 index f39cb0b80874..000000000000 --- a/.github/actions/expand-variables/dist/index.js +++ /dev/null @@ -1,26209 +0,0 @@ -/******/ (() => { // webpackBootstrap -/******/ var __webpack_modules__ = ({ - -/***/ 5183: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.issue = exports.issueCommand = void 0; -const os = __importStar(__nccwpck_require__(2037)); -const utils_1 = __nccwpck_require__(8091); -/** - * Commands - * - * Command Format: - * ::name key=value,key=value::message - * - * Examples: - * ::warning::This is the message - * ::set-env name=MY_VAR::some value - */ -function issueCommand(command, properties, message) { - const cmd = new Command(command, properties, message); - process.stdout.write(cmd.toString() + os.EOL); -} -exports.issueCommand = issueCommand; -function issue(name, message = '') { - issueCommand(name, {}, message); -} -exports.issue = issue; -const CMD_STRING = '::'; -class Command { - constructor(command, properties, message) { - if (!command) { - command = 'missing.command'; - } - this.command = command; - this.properties = properties; - this.message = message; - } - toString() { - let cmdStr = CMD_STRING + this.command; - if (this.properties && Object.keys(this.properties).length > 0) { - cmdStr += ' '; - let first = true; - for (const key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - const val = this.properties[key]; - if (val) { - if (first) { - first = false; - } - else { - cmdStr += ','; - } - cmdStr += `${key}=${escapeProperty(val)}`; - } - } - } - } - cmdStr += `${CMD_STRING}${escapeData(this.message)}`; - return cmdStr; - } -} -function escapeData(s) { - return utils_1.toCommandValue(s) - .replace(/%/g, '%25') - .replace(/\r/g, '%0D') - .replace(/\n/g, '%0A'); -} -function escapeProperty(s) { - return utils_1.toCommandValue(s) - .replace(/%/g, '%25') - .replace(/\r/g, '%0D') - .replace(/\n/g, '%0A') - .replace(/:/g, '%3A') - .replace(/,/g, '%2C'); -} -//# sourceMappingURL=command.js.map - -/***/ }), - -/***/ 2619: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getIDToken = exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.notice = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0; -const command_1 = __nccwpck_require__(5183); -const file_command_1 = __nccwpck_require__(5939); -const utils_1 = __nccwpck_require__(8091); -const os = __importStar(__nccwpck_require__(2037)); -const path = __importStar(__nccwpck_require__(1017)); -const oidc_utils_1 = __nccwpck_require__(3669); -/** - * The code to exit an action - */ -var ExitCode; -(function (ExitCode) { - /** - * A code indicating that the action was successful - */ - ExitCode[ExitCode["Success"] = 0] = "Success"; - /** - * A code indicating that the action was a failure - */ - ExitCode[ExitCode["Failure"] = 1] = "Failure"; -})(ExitCode = exports.ExitCode || (exports.ExitCode = {})); -//----------------------------------------------------------------------- -// Variables -//----------------------------------------------------------------------- -/** - * Sets env variable for this action and future actions in the job - * @param name the name of the variable to set - * @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function exportVariable(name, val) { - const convertedVal = utils_1.toCommandValue(val); - process.env[name] = convertedVal; - const filePath = process.env['GITHUB_ENV'] || ''; - if (filePath) { - return file_command_1.issueFileCommand('ENV', file_command_1.prepareKeyValueMessage(name, val)); - } - command_1.issueCommand('set-env', { name }, convertedVal); -} -exports.exportVariable = exportVariable; -/** - * Registers a secret which will get masked from logs - * @param secret value of the secret - */ -function setSecret(secret) { - command_1.issueCommand('add-mask', {}, secret); -} -exports.setSecret = setSecret; -/** - * Prepends inputPath to the PATH (for this action and future actions) - * @param inputPath - */ -function addPath(inputPath) { - const filePath = process.env['GITHUB_PATH'] || ''; - if (filePath) { - file_command_1.issueFileCommand('PATH', inputPath); - } - else { - command_1.issueCommand('add-path', {}, inputPath); - } - process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`; -} -exports.addPath = addPath; -/** - * Gets the value of an input. - * Unless trimWhitespace is set to false in InputOptions, the value is also trimmed. - * Returns an empty string if the value is not defined. - * - * @param name name of the input to get - * @param options optional. See InputOptions. - * @returns string - */ -function getInput(name, options) { - const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''; - if (options && options.required && !val) { - throw new Error(`Input required and not supplied: ${name}`); - } - if (options && options.trimWhitespace === false) { - return val; - } - return val.trim(); -} -exports.getInput = getInput; -/** - * Gets the values of an multiline input. Each value is also trimmed. - * - * @param name name of the input to get - * @param options optional. See InputOptions. - * @returns string[] - * - */ -function getMultilineInput(name, options) { - const inputs = getInput(name, options) - .split('\n') - .filter(x => x !== ''); - if (options && options.trimWhitespace === false) { - return inputs; - } - return inputs.map(input => input.trim()); -} -exports.getMultilineInput = getMultilineInput; -/** - * Gets the input value of the boolean type in the YAML 1.2 "core schema" specification. - * Support boolean input list: `true | True | TRUE | false | False | FALSE` . - * The return value is also in boolean type. - * ref: https://yaml.org/spec/1.2/spec.html#id2804923 - * - * @param name name of the input to get - * @param options optional. See InputOptions. - * @returns boolean - */ -function getBooleanInput(name, options) { - const trueValue = ['true', 'True', 'TRUE']; - const falseValue = ['false', 'False', 'FALSE']; - const val = getInput(name, options); - if (trueValue.includes(val)) - return true; - if (falseValue.includes(val)) - return false; - throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${name}\n` + - `Support boolean input list: \`true | True | TRUE | false | False | FALSE\``); -} -exports.getBooleanInput = getBooleanInput; -/** - * Sets the value of an output. - * - * @param name name of the output to set - * @param value value to store. Non-string values will be converted to a string via JSON.stringify - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function setOutput(name, value) { - const filePath = process.env['GITHUB_OUTPUT'] || ''; - if (filePath) { - return file_command_1.issueFileCommand('OUTPUT', file_command_1.prepareKeyValueMessage(name, value)); - } - process.stdout.write(os.EOL); - command_1.issueCommand('set-output', { name }, utils_1.toCommandValue(value)); -} -exports.setOutput = setOutput; -/** - * Enables or disables the echoing of commands into stdout for the rest of the step. - * Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. - * - */ -function setCommandEcho(enabled) { - command_1.issue('echo', enabled ? 'on' : 'off'); -} -exports.setCommandEcho = setCommandEcho; -//----------------------------------------------------------------------- -// Results -//----------------------------------------------------------------------- -/** - * Sets the action status to failed. - * When the action exits it will be with an exit code of 1 - * @param message add error issue message - */ -function setFailed(message) { - process.exitCode = ExitCode.Failure; - error(message); -} -exports.setFailed = setFailed; -//----------------------------------------------------------------------- -// Logging Commands -//----------------------------------------------------------------------- -/** - * Gets whether Actions Step Debug is on or not - */ -function isDebug() { - return process.env['RUNNER_DEBUG'] === '1'; -} -exports.isDebug = isDebug; -/** - * Writes debug message to user log - * @param message debug message - */ -function debug(message) { - command_1.issueCommand('debug', {}, message); -} -exports.debug = debug; -/** - * Adds an error issue - * @param message error issue message. Errors will be converted to string via toString() - * @param properties optional properties to add to the annotation. - */ -function error(message, properties = {}) { - command_1.issueCommand('error', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); -} -exports.error = error; -/** - * Adds a warning issue - * @param message warning issue message. Errors will be converted to string via toString() - * @param properties optional properties to add to the annotation. - */ -function warning(message, properties = {}) { - command_1.issueCommand('warning', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); -} -exports.warning = warning; -/** - * Adds a notice issue - * @param message notice issue message. Errors will be converted to string via toString() - * @param properties optional properties to add to the annotation. - */ -function notice(message, properties = {}) { - command_1.issueCommand('notice', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); -} -exports.notice = notice; -/** - * Writes info to log with console.log. - * @param message info message - */ -function info(message) { - process.stdout.write(message + os.EOL); -} -exports.info = info; -/** - * Begin an output group. - * - * Output until the next `groupEnd` will be foldable in this group - * - * @param name The name of the output group - */ -function startGroup(name) { - command_1.issue('group', name); -} -exports.startGroup = startGroup; -/** - * End an output group. - */ -function endGroup() { - command_1.issue('endgroup'); -} -exports.endGroup = endGroup; -/** - * Wrap an asynchronous function call in a group. - * - * Returns the same type as the function itself. - * - * @param name The name of the group - * @param fn The function to wrap in the group - */ -function group(name, fn) { - return __awaiter(this, void 0, void 0, function* () { - startGroup(name); - let result; - try { - result = yield fn(); - } - finally { - endGroup(); - } - return result; - }); -} -exports.group = group; -//----------------------------------------------------------------------- -// Wrapper action state -//----------------------------------------------------------------------- -/** - * Saves state for current action, the state can only be retrieved by this action's post job execution. - * - * @param name name of the state to store - * @param value value to store. Non-string values will be converted to a string via JSON.stringify - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function saveState(name, value) { - const filePath = process.env['GITHUB_STATE'] || ''; - if (filePath) { - return file_command_1.issueFileCommand('STATE', file_command_1.prepareKeyValueMessage(name, value)); - } - command_1.issueCommand('save-state', { name }, utils_1.toCommandValue(value)); -} -exports.saveState = saveState; -/** - * Gets the value of an state set by this action's main execution. - * - * @param name name of the state to get - * @returns string - */ -function getState(name) { - return process.env[`STATE_${name}`] || ''; -} -exports.getState = getState; -function getIDToken(aud) { - return __awaiter(this, void 0, void 0, function* () { - return yield oidc_utils_1.OidcClient.getIDToken(aud); - }); -} -exports.getIDToken = getIDToken; -/** - * Summary exports - */ -var summary_1 = __nccwpck_require__(4992); -Object.defineProperty(exports, "summary", ({ enumerable: true, get: function () { return summary_1.summary; } })); -/** - * @deprecated use core.summary - */ -var summary_2 = __nccwpck_require__(4992); -Object.defineProperty(exports, "markdownSummary", ({ enumerable: true, get: function () { return summary_2.markdownSummary; } })); -/** - * Path exports - */ -var path_utils_1 = __nccwpck_require__(6067); -Object.defineProperty(exports, "toPosixPath", ({ enumerable: true, get: function () { return path_utils_1.toPosixPath; } })); -Object.defineProperty(exports, "toWin32Path", ({ enumerable: true, get: function () { return path_utils_1.toWin32Path; } })); -Object.defineProperty(exports, "toPlatformPath", ({ enumerable: true, get: function () { return path_utils_1.toPlatformPath; } })); -//# sourceMappingURL=core.js.map - -/***/ }), - -/***/ 5939: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -// For internal use, subject to change. -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.prepareKeyValueMessage = exports.issueFileCommand = void 0; -// We use any as a valid input type -/* eslint-disable @typescript-eslint/no-explicit-any */ -const fs = __importStar(__nccwpck_require__(7147)); -const os = __importStar(__nccwpck_require__(2037)); -const uuid_1 = __nccwpck_require__(8860); -const utils_1 = __nccwpck_require__(8091); -function issueFileCommand(command, message) { - const filePath = process.env[`GITHUB_${command}`]; - if (!filePath) { - throw new Error(`Unable to find environment variable for file command ${command}`); - } - if (!fs.existsSync(filePath)) { - throw new Error(`Missing file at path: ${filePath}`); - } - fs.appendFileSync(filePath, `${utils_1.toCommandValue(message)}${os.EOL}`, { - encoding: 'utf8' - }); -} -exports.issueFileCommand = issueFileCommand; -function prepareKeyValueMessage(key, value) { - const delimiter = `ghadelimiter_${uuid_1.v4()}`; - const convertedValue = utils_1.toCommandValue(value); - // These should realistically never happen, but just in case someone finds a - // way to exploit uuid generation let's not allow keys or values that contain - // the delimiter. - if (key.includes(delimiter)) { - throw new Error(`Unexpected input: name should not contain the delimiter "${delimiter}"`); - } - if (convertedValue.includes(delimiter)) { - throw new Error(`Unexpected input: value should not contain the delimiter "${delimiter}"`); - } - return `${key}<<${delimiter}${os.EOL}${convertedValue}${os.EOL}${delimiter}`; -} -exports.prepareKeyValueMessage = prepareKeyValueMessage; -//# sourceMappingURL=file-command.js.map - -/***/ }), - -/***/ 3669: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.OidcClient = void 0; -const http_client_1 = __nccwpck_require__(429); -const auth_1 = __nccwpck_require__(1535); -const core_1 = __nccwpck_require__(2619); -class OidcClient { - static createHttpClient(allowRetry = true, maxRetry = 10) { - const requestOptions = { - allowRetries: allowRetry, - maxRetries: maxRetry - }; - return new http_client_1.HttpClient('actions/oidc-client', [new auth_1.BearerCredentialHandler(OidcClient.getRequestToken())], requestOptions); - } - static getRequestToken() { - const token = process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN']; - if (!token) { - throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable'); - } - return token; - } - static getIDTokenUrl() { - const runtimeUrl = process.env['ACTIONS_ID_TOKEN_REQUEST_URL']; - if (!runtimeUrl) { - throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable'); - } - return runtimeUrl; - } - static getCall(id_token_url) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - const httpclient = OidcClient.createHttpClient(); - const res = yield httpclient - .getJson(id_token_url) - .catch(error => { - throw new Error(`Failed to get ID Token. \n - Error Code : ${error.statusCode}\n - Error Message: ${error.message}`); - }); - const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value; - if (!id_token) { - throw new Error('Response json body do not have ID Token field'); - } - return id_token; - }); - } - static getIDToken(audience) { - return __awaiter(this, void 0, void 0, function* () { - try { - // New ID Token is requested from action service - let id_token_url = OidcClient.getIDTokenUrl(); - if (audience) { - const encodedAudience = encodeURIComponent(audience); - id_token_url = `${id_token_url}&audience=${encodedAudience}`; - } - core_1.debug(`ID token url is ${id_token_url}`); - const id_token = yield OidcClient.getCall(id_token_url); - core_1.setSecret(id_token); - return id_token; - } - catch (error) { - throw new Error(`Error message: ${error.message}`); - } - }); - } -} -exports.OidcClient = OidcClient; -//# sourceMappingURL=oidc-utils.js.map - -/***/ }), - -/***/ 6067: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.toPlatformPath = exports.toWin32Path = exports.toPosixPath = void 0; -const path = __importStar(__nccwpck_require__(1017)); -/** - * toPosixPath converts the given path to the posix form. On Windows, \\ will be - * replaced with /. - * - * @param pth. Path to transform. - * @return string Posix path. - */ -function toPosixPath(pth) { - return pth.replace(/[\\]/g, '/'); -} -exports.toPosixPath = toPosixPath; -/** - * toWin32Path converts the given path to the win32 form. On Linux, / will be - * replaced with \\. - * - * @param pth. Path to transform. - * @return string Win32 path. - */ -function toWin32Path(pth) { - return pth.replace(/[/]/g, '\\'); -} -exports.toWin32Path = toWin32Path; -/** - * toPlatformPath converts the given path to a platform-specific path. It does - * this by replacing instances of / and \ with the platform-specific path - * separator. - * - * @param pth The path to platformize. - * @return string The platform-specific path. - */ -function toPlatformPath(pth) { - return pth.replace(/[/\\]/g, path.sep); -} -exports.toPlatformPath = toPlatformPath; -//# sourceMappingURL=path-utils.js.map - -/***/ }), - -/***/ 4992: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.summary = exports.markdownSummary = exports.SUMMARY_DOCS_URL = exports.SUMMARY_ENV_VAR = void 0; -const os_1 = __nccwpck_require__(2037); -const fs_1 = __nccwpck_require__(7147); -const { access, appendFile, writeFile } = fs_1.promises; -exports.SUMMARY_ENV_VAR = 'GITHUB_STEP_SUMMARY'; -exports.SUMMARY_DOCS_URL = 'https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-job-summary'; -class Summary { - constructor() { - this._buffer = ''; - } - /** - * Finds the summary file path from the environment, rejects if env var is not found or file does not exist - * Also checks r/w permissions. - * - * @returns step summary file path - */ - filePath() { - return __awaiter(this, void 0, void 0, function* () { - if (this._filePath) { - return this._filePath; - } - const pathFromEnv = process.env[exports.SUMMARY_ENV_VAR]; - if (!pathFromEnv) { - throw new Error(`Unable to find environment variable for $${exports.SUMMARY_ENV_VAR}. Check if your runtime environment supports job summaries.`); - } - try { - yield access(pathFromEnv, fs_1.constants.R_OK | fs_1.constants.W_OK); - } - catch (_a) { - throw new Error(`Unable to access summary file: '${pathFromEnv}'. Check if the file has correct read/write permissions.`); - } - this._filePath = pathFromEnv; - return this._filePath; - }); - } - /** - * Wraps content in an HTML tag, adding any HTML attributes - * - * @param {string} tag HTML tag to wrap - * @param {string | null} content content within the tag - * @param {[attribute: string]: string} attrs key-value list of HTML attributes to add - * - * @returns {string} content wrapped in HTML element - */ - wrap(tag, content, attrs = {}) { - const htmlAttrs = Object.entries(attrs) - .map(([key, value]) => ` ${key}="${value}"`) - .join(''); - if (!content) { - return `<${tag}${htmlAttrs}>`; - } - return `<${tag}${htmlAttrs}>${content}</${tag}>`; - } - /** - * Writes text in the buffer to the summary buffer file and empties buffer. Will append by default. - * - * @param {SummaryWriteOptions} [options] (optional) options for write operation - * - * @returns {Promise<Summary>} summary instance - */ - write(options) { - return __awaiter(this, void 0, void 0, function* () { - const overwrite = !!(options === null || options === void 0 ? void 0 : options.overwrite); - const filePath = yield this.filePath(); - const writeFunc = overwrite ? writeFile : appendFile; - yield writeFunc(filePath, this._buffer, { encoding: 'utf8' }); - return this.emptyBuffer(); - }); - } - /** - * Clears the summary buffer and wipes the summary file - * - * @returns {Summary} summary instance - */ - clear() { - return __awaiter(this, void 0, void 0, function* () { - return this.emptyBuffer().write({ overwrite: true }); - }); - } - /** - * Returns the current summary buffer as a string - * - * @returns {string} string of summary buffer - */ - stringify() { - return this._buffer; - } - /** - * If the summary buffer is empty - * - * @returns {boolen} true if the buffer is empty - */ - isEmptyBuffer() { - return this._buffer.length === 0; - } - /** - * Resets the summary buffer without writing to summary file - * - * @returns {Summary} summary instance - */ - emptyBuffer() { - this._buffer = ''; - return this; - } - /** - * Adds raw text to the summary buffer - * - * @param {string} text content to add - * @param {boolean} [addEOL=false] (optional) append an EOL to the raw text (default: false) - * - * @returns {Summary} summary instance - */ - addRaw(text, addEOL = false) { - this._buffer += text; - return addEOL ? this.addEOL() : this; - } - /** - * Adds the operating system-specific end-of-line marker to the buffer - * - * @returns {Summary} summary instance - */ - addEOL() { - return this.addRaw(os_1.EOL); - } - /** - * Adds an HTML codeblock to the summary buffer - * - * @param {string} code content to render within fenced code block - * @param {string} lang (optional) language to syntax highlight code - * - * @returns {Summary} summary instance - */ - addCodeBlock(code, lang) { - const attrs = Object.assign({}, (lang && { lang })); - const element = this.wrap('pre', this.wrap('code', code), attrs); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML list to the summary buffer - * - * @param {string[]} items list of items to render - * @param {boolean} [ordered=false] (optional) if the rendered list should be ordered or not (default: false) - * - * @returns {Summary} summary instance - */ - addList(items, ordered = false) { - const tag = ordered ? 'ol' : 'ul'; - const listItems = items.map(item => this.wrap('li', item)).join(''); - const element = this.wrap(tag, listItems); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML table to the summary buffer - * - * @param {SummaryTableCell[]} rows table rows - * - * @returns {Summary} summary instance - */ - addTable(rows) { - const tableBody = rows - .map(row => { - const cells = row - .map(cell => { - if (typeof cell === 'string') { - return this.wrap('td', cell); - } - const { header, data, colspan, rowspan } = cell; - const tag = header ? 'th' : 'td'; - const attrs = Object.assign(Object.assign({}, (colspan && { colspan })), (rowspan && { rowspan })); - return this.wrap(tag, data, attrs); - }) - .join(''); - return this.wrap('tr', cells); - }) - .join(''); - const element = this.wrap('table', tableBody); - return this.addRaw(element).addEOL(); - } - /** - * Adds a collapsable HTML details element to the summary buffer - * - * @param {string} label text for the closed state - * @param {string} content collapsable content - * - * @returns {Summary} summary instance - */ - addDetails(label, content) { - const element = this.wrap('details', this.wrap('summary', label) + content); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML image tag to the summary buffer - * - * @param {string} src path to the image you to embed - * @param {string} alt text description of the image - * @param {SummaryImageOptions} options (optional) addition image attributes - * - * @returns {Summary} summary instance - */ - addImage(src, alt, options) { - const { width, height } = options || {}; - const attrs = Object.assign(Object.assign({}, (width && { width })), (height && { height })); - const element = this.wrap('img', null, Object.assign({ src, alt }, attrs)); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML section heading element - * - * @param {string} text heading text - * @param {number | string} [level=1] (optional) the heading level, default: 1 - * - * @returns {Summary} summary instance - */ - addHeading(text, level) { - const tag = `h${level}`; - const allowedTag = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag) - ? tag - : 'h1'; - const element = this.wrap(allowedTag, text); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML thematic break (<hr>) to the summary buffer - * - * @returns {Summary} summary instance - */ - addSeparator() { - const element = this.wrap('hr', null); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML line break (<br>) to the summary buffer - * - * @returns {Summary} summary instance - */ - addBreak() { - const element = this.wrap('br', null); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML blockquote to the summary buffer - * - * @param {string} text quote text - * @param {string} cite (optional) citation url - * - * @returns {Summary} summary instance - */ - addQuote(text, cite) { - const attrs = Object.assign({}, (cite && { cite })); - const element = this.wrap('blockquote', text, attrs); - return this.addRaw(element).addEOL(); - } - /** - * Adds an HTML anchor tag to the summary buffer - * - * @param {string} text link text/content - * @param {string} href hyperlink - * - * @returns {Summary} summary instance - */ - addLink(text, href) { - const element = this.wrap('a', text, { href }); - return this.addRaw(element).addEOL(); - } -} -const _summary = new Summary(); -/** - * @deprecated use `core.summary` - */ -exports.markdownSummary = _summary; -exports.summary = _summary; -//# sourceMappingURL=summary.js.map - -/***/ }), - -/***/ 8091: -/***/ ((__unused_webpack_module, exports) => { - -"use strict"; - -// We use any as a valid input type -/* eslint-disable @typescript-eslint/no-explicit-any */ -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.toCommandProperties = exports.toCommandValue = void 0; -/** - * Sanitizes an input into a string so it can be passed into issueCommand safely - * @param input input to sanitize into a string - */ -function toCommandValue(input) { - if (input === null || input === undefined) { - return ''; - } - else if (typeof input === 'string' || input instanceof String) { - return input; - } - return JSON.stringify(input); -} -exports.toCommandValue = toCommandValue; -/** - * - * @param annotationProperties - * @returns The command properties to send with the actual annotation command - * See IssueCommandProperties: https://github.com/actions/runner/blob/main/src/Runner.Worker/ActionCommandManager.cs#L646 - */ -function toCommandProperties(annotationProperties) { - if (!Object.keys(annotationProperties).length) { - return {}; - } - return { - title: annotationProperties.title, - file: annotationProperties.file, - line: annotationProperties.startLine, - endLine: annotationProperties.endLine, - col: annotationProperties.startColumn, - endColumn: annotationProperties.endColumn - }; -} -exports.toCommandProperties = toCommandProperties; -//# sourceMappingURL=utils.js.map - -/***/ }), - -/***/ 1535: -/***/ (function(__unused_webpack_module, exports) { - -"use strict"; - -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.PersonalAccessTokenCredentialHandler = exports.BearerCredentialHandler = exports.BasicCredentialHandler = void 0; -class BasicCredentialHandler { - constructor(username, password) { - this.username = username; - this.password = password; - } - prepareRequest(options) { - if (!options.headers) { - throw Error('The request has no headers'); - } - options.headers['Authorization'] = `Basic ${Buffer.from(`${this.username}:${this.password}`).toString('base64')}`; - } - // This handler cannot handle 401 - canHandleAuthentication() { - return false; - } - handleAuthentication() { - return __awaiter(this, void 0, void 0, function* () { - throw new Error('not implemented'); - }); - } -} -exports.BasicCredentialHandler = BasicCredentialHandler; -class BearerCredentialHandler { - constructor(token) { - this.token = token; - } - // currently implements pre-authorization - // TODO: support preAuth = false where it hooks on 401 - prepareRequest(options) { - if (!options.headers) { - throw Error('The request has no headers'); - } - options.headers['Authorization'] = `Bearer ${this.token}`; - } - // This handler cannot handle 401 - canHandleAuthentication() { - return false; - } - handleAuthentication() { - return __awaiter(this, void 0, void 0, function* () { - throw new Error('not implemented'); - }); - } -} -exports.BearerCredentialHandler = BearerCredentialHandler; -class PersonalAccessTokenCredentialHandler { - constructor(token) { - this.token = token; - } - // currently implements pre-authorization - // TODO: support preAuth = false where it hooks on 401 - prepareRequest(options) { - if (!options.headers) { - throw Error('The request has no headers'); - } - options.headers['Authorization'] = `Basic ${Buffer.from(`PAT:${this.token}`).toString('base64')}`; - } - // This handler cannot handle 401 - canHandleAuthentication() { - return false; - } - handleAuthentication() { - return __awaiter(this, void 0, void 0, function* () { - throw new Error('not implemented'); - }); - } -} -exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler; -//# sourceMappingURL=auth.js.map - -/***/ }), - -/***/ 429: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -/* eslint-disable @typescript-eslint/no-explicit-any */ -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.HttpClient = exports.isHttps = exports.HttpClientResponse = exports.HttpClientError = exports.getProxyUrl = exports.MediaTypes = exports.Headers = exports.HttpCodes = void 0; -const http = __importStar(__nccwpck_require__(3685)); -const https = __importStar(__nccwpck_require__(5687)); -const pm = __importStar(__nccwpck_require__(5957)); -const tunnel = __importStar(__nccwpck_require__(6237)); -const undici_1 = __nccwpck_require__(5116); -var HttpCodes; -(function (HttpCodes) { - HttpCodes[HttpCodes["OK"] = 200] = "OK"; - HttpCodes[HttpCodes["MultipleChoices"] = 300] = "MultipleChoices"; - HttpCodes[HttpCodes["MovedPermanently"] = 301] = "MovedPermanently"; - HttpCodes[HttpCodes["ResourceMoved"] = 302] = "ResourceMoved"; - HttpCodes[HttpCodes["SeeOther"] = 303] = "SeeOther"; - HttpCodes[HttpCodes["NotModified"] = 304] = "NotModified"; - HttpCodes[HttpCodes["UseProxy"] = 305] = "UseProxy"; - HttpCodes[HttpCodes["SwitchProxy"] = 306] = "SwitchProxy"; - HttpCodes[HttpCodes["TemporaryRedirect"] = 307] = "TemporaryRedirect"; - HttpCodes[HttpCodes["PermanentRedirect"] = 308] = "PermanentRedirect"; - HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest"; - HttpCodes[HttpCodes["Unauthorized"] = 401] = "Unauthorized"; - HttpCodes[HttpCodes["PaymentRequired"] = 402] = "PaymentRequired"; - HttpCodes[HttpCodes["Forbidden"] = 403] = "Forbidden"; - HttpCodes[HttpCodes["NotFound"] = 404] = "NotFound"; - HttpCodes[HttpCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed"; - HttpCodes[HttpCodes["NotAcceptable"] = 406] = "NotAcceptable"; - HttpCodes[HttpCodes["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired"; - HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout"; - HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict"; - HttpCodes[HttpCodes["Gone"] = 410] = "Gone"; - HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests"; - HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError"; - HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented"; - HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway"; - HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable"; - HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout"; -})(HttpCodes || (exports.HttpCodes = HttpCodes = {})); -var Headers; -(function (Headers) { - Headers["Accept"] = "accept"; - Headers["ContentType"] = "content-type"; -})(Headers || (exports.Headers = Headers = {})); -var MediaTypes; -(function (MediaTypes) { - MediaTypes["ApplicationJson"] = "application/json"; -})(MediaTypes || (exports.MediaTypes = MediaTypes = {})); -/** - * Returns the proxy URL, depending upon the supplied url and proxy environment variables. - * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com - */ -function getProxyUrl(serverUrl) { - const proxyUrl = pm.getProxyUrl(new URL(serverUrl)); - return proxyUrl ? proxyUrl.href : ''; -} -exports.getProxyUrl = getProxyUrl; -const HttpRedirectCodes = [ - HttpCodes.MovedPermanently, - HttpCodes.ResourceMoved, - HttpCodes.SeeOther, - HttpCodes.TemporaryRedirect, - HttpCodes.PermanentRedirect -]; -const HttpResponseRetryCodes = [ - HttpCodes.BadGateway, - HttpCodes.ServiceUnavailable, - HttpCodes.GatewayTimeout -]; -const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD']; -const ExponentialBackoffCeiling = 10; -const ExponentialBackoffTimeSlice = 5; -class HttpClientError extends Error { - constructor(message, statusCode) { - super(message); - this.name = 'HttpClientError'; - this.statusCode = statusCode; - Object.setPrototypeOf(this, HttpClientError.prototype); - } -} -exports.HttpClientError = HttpClientError; -class HttpClientResponse { - constructor(message) { - this.message = message; - } - readBody() { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { - let output = Buffer.alloc(0); - this.message.on('data', (chunk) => { - output = Buffer.concat([output, chunk]); - }); - this.message.on('end', () => { - resolve(output.toString()); - }); - })); - }); - } - readBodyBuffer() { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { - const chunks = []; - this.message.on('data', (chunk) => { - chunks.push(chunk); - }); - this.message.on('end', () => { - resolve(Buffer.concat(chunks)); - }); - })); - }); - } -} -exports.HttpClientResponse = HttpClientResponse; -function isHttps(requestUrl) { - const parsedUrl = new URL(requestUrl); - return parsedUrl.protocol === 'https:'; -} -exports.isHttps = isHttps; -class HttpClient { - constructor(userAgent, handlers, requestOptions) { - this._ignoreSslError = false; - this._allowRedirects = true; - this._allowRedirectDowngrade = false; - this._maxRedirects = 50; - this._allowRetries = false; - this._maxRetries = 1; - this._keepAlive = false; - this._disposed = false; - this.userAgent = userAgent; - this.handlers = handlers || []; - this.requestOptions = requestOptions; - if (requestOptions) { - if (requestOptions.ignoreSslError != null) { - this._ignoreSslError = requestOptions.ignoreSslError; - } - this._socketTimeout = requestOptions.socketTimeout; - if (requestOptions.allowRedirects != null) { - this._allowRedirects = requestOptions.allowRedirects; - } - if (requestOptions.allowRedirectDowngrade != null) { - this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade; - } - if (requestOptions.maxRedirects != null) { - this._maxRedirects = Math.max(requestOptions.maxRedirects, 0); - } - if (requestOptions.keepAlive != null) { - this._keepAlive = requestOptions.keepAlive; - } - if (requestOptions.allowRetries != null) { - this._allowRetries = requestOptions.allowRetries; - } - if (requestOptions.maxRetries != null) { - this._maxRetries = requestOptions.maxRetries; - } - } - } - options(requestUrl, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('OPTIONS', requestUrl, null, additionalHeaders || {}); - }); - } - get(requestUrl, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('GET', requestUrl, null, additionalHeaders || {}); - }); - } - del(requestUrl, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('DELETE', requestUrl, null, additionalHeaders || {}); - }); - } - post(requestUrl, data, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('POST', requestUrl, data, additionalHeaders || {}); - }); - } - patch(requestUrl, data, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('PATCH', requestUrl, data, additionalHeaders || {}); - }); - } - put(requestUrl, data, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('PUT', requestUrl, data, additionalHeaders || {}); - }); - } - head(requestUrl, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request('HEAD', requestUrl, null, additionalHeaders || {}); - }); - } - sendStream(verb, requestUrl, stream, additionalHeaders) { - return __awaiter(this, void 0, void 0, function* () { - return this.request(verb, requestUrl, stream, additionalHeaders); - }); - } - /** - * Gets a typed object from an endpoint - * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise - */ - getJson(requestUrl, additionalHeaders = {}) { - return __awaiter(this, void 0, void 0, function* () { - additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); - const res = yield this.get(requestUrl, additionalHeaders); - return this._processResponse(res, this.requestOptions); - }); - } - postJson(requestUrl, obj, additionalHeaders = {}) { - return __awaiter(this, void 0, void 0, function* () { - const data = JSON.stringify(obj, null, 2); - additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); - additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); - const res = yield this.post(requestUrl, data, additionalHeaders); - return this._processResponse(res, this.requestOptions); - }); - } - putJson(requestUrl, obj, additionalHeaders = {}) { - return __awaiter(this, void 0, void 0, function* () { - const data = JSON.stringify(obj, null, 2); - additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); - additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); - const res = yield this.put(requestUrl, data, additionalHeaders); - return this._processResponse(res, this.requestOptions); - }); - } - patchJson(requestUrl, obj, additionalHeaders = {}) { - return __awaiter(this, void 0, void 0, function* () { - const data = JSON.stringify(obj, null, 2); - additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); - additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); - const res = yield this.patch(requestUrl, data, additionalHeaders); - return this._processResponse(res, this.requestOptions); - }); - } - /** - * Makes a raw http request. - * All other methods such as get, post, patch, and request ultimately call this. - * Prefer get, del, post and patch - */ - request(verb, requestUrl, data, headers) { - return __awaiter(this, void 0, void 0, function* () { - if (this._disposed) { - throw new Error('Client has already been disposed.'); - } - const parsedUrl = new URL(requestUrl); - let info = this._prepareRequest(verb, parsedUrl, headers); - // Only perform retries on reads since writes may not be idempotent. - const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb) - ? this._maxRetries + 1 - : 1; - let numTries = 0; - let response; - do { - response = yield this.requestRaw(info, data); - // Check if it's an authentication challenge - if (response && - response.message && - response.message.statusCode === HttpCodes.Unauthorized) { - let authenticationHandler; - for (const handler of this.handlers) { - if (handler.canHandleAuthentication(response)) { - authenticationHandler = handler; - break; - } - } - if (authenticationHandler) { - return authenticationHandler.handleAuthentication(this, info, data); - } - else { - // We have received an unauthorized response but have no handlers to handle it. - // Let the response return to the caller. - return response; - } - } - let redirectsRemaining = this._maxRedirects; - while (response.message.statusCode && - HttpRedirectCodes.includes(response.message.statusCode) && - this._allowRedirects && - redirectsRemaining > 0) { - const redirectUrl = response.message.headers['location']; - if (!redirectUrl) { - // if there's no location to redirect to, we won't - break; - } - const parsedRedirectUrl = new URL(redirectUrl); - if (parsedUrl.protocol === 'https:' && - parsedUrl.protocol !== parsedRedirectUrl.protocol && - !this._allowRedirectDowngrade) { - throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.'); - } - // we need to finish reading the response before reassigning response - // which will leak the open socket. - yield response.readBody(); - // strip authorization header if redirected to a different hostname - if (parsedRedirectUrl.hostname !== parsedUrl.hostname) { - for (const header in headers) { - // header names are case insensitive - if (header.toLowerCase() === 'authorization') { - delete headers[header]; - } - } - } - // let's make the request with the new redirectUrl - info = this._prepareRequest(verb, parsedRedirectUrl, headers); - response = yield this.requestRaw(info, data); - redirectsRemaining--; - } - if (!response.message.statusCode || - !HttpResponseRetryCodes.includes(response.message.statusCode)) { - // If not a retry code, return immediately instead of retrying - return response; - } - numTries += 1; - if (numTries < maxTries) { - yield response.readBody(); - yield this._performExponentialBackoff(numTries); - } - } while (numTries < maxTries); - return response; - }); - } - /** - * Needs to be called if keepAlive is set to true in request options. - */ - dispose() { - if (this._agent) { - this._agent.destroy(); - } - this._disposed = true; - } - /** - * Raw request. - * @param info - * @param data - */ - requestRaw(info, data) { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve, reject) => { - function callbackForResult(err, res) { - if (err) { - reject(err); - } - else if (!res) { - // If `err` is not passed, then `res` must be passed. - reject(new Error('Unknown error')); - } - else { - resolve(res); - } - } - this.requestRawWithCallback(info, data, callbackForResult); - }); - }); - } - /** - * Raw request with callback. - * @param info - * @param data - * @param onResult - */ - requestRawWithCallback(info, data, onResult) { - if (typeof data === 'string') { - if (!info.options.headers) { - info.options.headers = {}; - } - info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8'); - } - let callbackCalled = false; - function handleResult(err, res) { - if (!callbackCalled) { - callbackCalled = true; - onResult(err, res); - } - } - const req = info.httpModule.request(info.options, (msg) => { - const res = new HttpClientResponse(msg); - handleResult(undefined, res); - }); - let socket; - req.on('socket', sock => { - socket = sock; - }); - // If we ever get disconnected, we want the socket to timeout eventually - req.setTimeout(this._socketTimeout || 3 * 60000, () => { - if (socket) { - socket.end(); - } - handleResult(new Error(`Request timeout: ${info.options.path}`)); - }); - req.on('error', function (err) { - // err has statusCode property - // res should have headers - handleResult(err); - }); - if (data && typeof data === 'string') { - req.write(data, 'utf8'); - } - if (data && typeof data !== 'string') { - data.on('close', function () { - req.end(); - }); - data.pipe(req); - } - else { - req.end(); - } - } - /** - * Gets an http agent. This function is useful when you need an http agent that handles - * routing through a proxy server - depending upon the url and proxy environment variables. - * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com - */ - getAgent(serverUrl) { - const parsedUrl = new URL(serverUrl); - return this._getAgent(parsedUrl); - } - getAgentDispatcher(serverUrl) { - const parsedUrl = new URL(serverUrl); - const proxyUrl = pm.getProxyUrl(parsedUrl); - const useProxy = proxyUrl && proxyUrl.hostname; - if (!useProxy) { - return; - } - return this._getProxyAgentDispatcher(parsedUrl, proxyUrl); - } - _prepareRequest(method, requestUrl, headers) { - const info = {}; - info.parsedUrl = requestUrl; - const usingSsl = info.parsedUrl.protocol === 'https:'; - info.httpModule = usingSsl ? https : http; - const defaultPort = usingSsl ? 443 : 80; - info.options = {}; - info.options.host = info.parsedUrl.hostname; - info.options.port = info.parsedUrl.port - ? parseInt(info.parsedUrl.port) - : defaultPort; - info.options.path = - (info.parsedUrl.pathname || '') + (info.parsedUrl.search || ''); - info.options.method = method; - info.options.headers = this._mergeHeaders(headers); - if (this.userAgent != null) { - info.options.headers['user-agent'] = this.userAgent; - } - info.options.agent = this._getAgent(info.parsedUrl); - // gives handlers an opportunity to participate - if (this.handlers) { - for (const handler of this.handlers) { - handler.prepareRequest(info.options); - } - } - return info; - } - _mergeHeaders(headers) { - if (this.requestOptions && this.requestOptions.headers) { - return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers || {})); - } - return lowercaseKeys(headers || {}); - } - _getExistingOrDefaultHeader(additionalHeaders, header, _default) { - let clientHeader; - if (this.requestOptions && this.requestOptions.headers) { - clientHeader = lowercaseKeys(this.requestOptions.headers)[header]; - } - return additionalHeaders[header] || clientHeader || _default; - } - _getAgent(parsedUrl) { - let agent; - const proxyUrl = pm.getProxyUrl(parsedUrl); - const useProxy = proxyUrl && proxyUrl.hostname; - if (this._keepAlive && useProxy) { - agent = this._proxyAgent; - } - if (this._keepAlive && !useProxy) { - agent = this._agent; - } - // if agent is already assigned use that agent. - if (agent) { - return agent; - } - const usingSsl = parsedUrl.protocol === 'https:'; - let maxSockets = 100; - if (this.requestOptions) { - maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets; - } - // This is `useProxy` again, but we need to check `proxyURl` directly for TypeScripts's flow analysis. - if (proxyUrl && proxyUrl.hostname) { - const agentOptions = { - maxSockets, - keepAlive: this._keepAlive, - proxy: Object.assign(Object.assign({}, ((proxyUrl.username || proxyUrl.password) && { - proxyAuth: `${proxyUrl.username}:${proxyUrl.password}` - })), { host: proxyUrl.hostname, port: proxyUrl.port }) - }; - let tunnelAgent; - const overHttps = proxyUrl.protocol === 'https:'; - if (usingSsl) { - tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp; - } - else { - tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp; - } - agent = tunnelAgent(agentOptions); - this._proxyAgent = agent; - } - // if reusing agent across request and tunneling agent isn't assigned create a new agent - if (this._keepAlive && !agent) { - const options = { keepAlive: this._keepAlive, maxSockets }; - agent = usingSsl ? new https.Agent(options) : new http.Agent(options); - this._agent = agent; - } - // if not using private agent and tunnel agent isn't setup then use global agent - if (!agent) { - agent = usingSsl ? https.globalAgent : http.globalAgent; - } - if (usingSsl && this._ignoreSslError) { - // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process - // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options - // we have to cast it to any and change it directly - agent.options = Object.assign(agent.options || {}, { - rejectUnauthorized: false - }); - } - return agent; - } - _getProxyAgentDispatcher(parsedUrl, proxyUrl) { - let proxyAgent; - if (this._keepAlive) { - proxyAgent = this._proxyAgentDispatcher; - } - // if agent is already assigned use that agent. - if (proxyAgent) { - return proxyAgent; - } - const usingSsl = parsedUrl.protocol === 'https:'; - proxyAgent = new undici_1.ProxyAgent(Object.assign({ uri: proxyUrl.href, pipelining: !this._keepAlive ? 0 : 1 }, ((proxyUrl.username || proxyUrl.password) && { - token: `${proxyUrl.username}:${proxyUrl.password}` - }))); - this._proxyAgentDispatcher = proxyAgent; - if (usingSsl && this._ignoreSslError) { - // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process - // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options - // we have to cast it to any and change it directly - proxyAgent.options = Object.assign(proxyAgent.options.requestTls || {}, { - rejectUnauthorized: false - }); - } - return proxyAgent; - } - _performExponentialBackoff(retryNumber) { - return __awaiter(this, void 0, void 0, function* () { - retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber); - const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber); - return new Promise(resolve => setTimeout(() => resolve(), ms)); - }); - } - _processResponse(res, options) { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { - const statusCode = res.message.statusCode || 0; - const response = { - statusCode, - result: null, - headers: {} - }; - // not found leads to null obj returned - if (statusCode === HttpCodes.NotFound) { - resolve(response); - } - // get the result from the body - function dateTimeDeserializer(key, value) { - if (typeof value === 'string') { - const a = new Date(value); - if (!isNaN(a.valueOf())) { - return a; - } - } - return value; - } - let obj; - let contents; - try { - contents = yield res.readBody(); - if (contents && contents.length > 0) { - if (options && options.deserializeDates) { - obj = JSON.parse(contents, dateTimeDeserializer); - } - else { - obj = JSON.parse(contents); - } - response.result = obj; - } - response.headers = res.message.headers; - } - catch (err) { - // Invalid resource (contents not json); leaving result obj null - } - // note that 3xx redirects are handled by the http layer. - if (statusCode > 299) { - let msg; - // if exception/error in body, attempt to get better error - if (obj && obj.message) { - msg = obj.message; - } - else if (contents && contents.length > 0) { - // it may be the case that the exception is in the body message as string - msg = contents; - } - else { - msg = `Failed request: (${statusCode})`; - } - const err = new HttpClientError(msg, statusCode); - err.result = response.result; - reject(err); - } - else { - resolve(response); - } - })); - }); - } -} -exports.HttpClient = HttpClient; -const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {}); -//# sourceMappingURL=index.js.map - -/***/ }), - -/***/ 5957: -/***/ ((__unused_webpack_module, exports) => { - -"use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.checkBypass = exports.getProxyUrl = void 0; -function getProxyUrl(reqUrl) { - const usingSsl = reqUrl.protocol === 'https:'; - if (checkBypass(reqUrl)) { - return undefined; - } - const proxyVar = (() => { - if (usingSsl) { - return process.env['https_proxy'] || process.env['HTTPS_PROXY']; - } - else { - return process.env['http_proxy'] || process.env['HTTP_PROXY']; - } - })(); - if (proxyVar) { - try { - return new URL(proxyVar); - } - catch (_a) { - if (!proxyVar.startsWith('http://') && !proxyVar.startsWith('https://')) - return new URL(`http://${proxyVar}`); - } - } - else { - return undefined; - } -} -exports.getProxyUrl = getProxyUrl; -function checkBypass(reqUrl) { - if (!reqUrl.hostname) { - return false; - } - const reqHost = reqUrl.hostname; - if (isLoopbackAddress(reqHost)) { - return true; - } - const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || ''; - if (!noProxy) { - return false; - } - // Determine the request port - let reqPort; - if (reqUrl.port) { - reqPort = Number(reqUrl.port); - } - else if (reqUrl.protocol === 'http:') { - reqPort = 80; - } - else if (reqUrl.protocol === 'https:') { - reqPort = 443; - } - // Format the request hostname and hostname with port - const upperReqHosts = [reqUrl.hostname.toUpperCase()]; - if (typeof reqPort === 'number') { - upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`); - } - // Compare request host against noproxy - for (const upperNoProxyItem of noProxy - .split(',') - .map(x => x.trim().toUpperCase()) - .filter(x => x)) { - if (upperNoProxyItem === '*' || - upperReqHosts.some(x => x === upperNoProxyItem || - x.endsWith(`.${upperNoProxyItem}`) || - (upperNoProxyItem.startsWith('.') && - x.endsWith(`${upperNoProxyItem}`)))) { - return true; - } - } - return false; -} -exports.checkBypass = checkBypass; -function isLoopbackAddress(host) { - const hostLower = host.toLowerCase(); - return (hostLower === 'localhost' || - hostLower.startsWith('127.') || - hostLower.startsWith('[::1]') || - hostLower.startsWith('[0:0:0:0:0:0:0:1]')); -} -//# sourceMappingURL=proxy.js.map - -/***/ }), - -/***/ 6237: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -module.exports = __nccwpck_require__(2576); - - -/***/ }), - -/***/ 2576: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -var net = __nccwpck_require__(1808); -var tls = __nccwpck_require__(4404); -var http = __nccwpck_require__(3685); -var https = __nccwpck_require__(5687); -var events = __nccwpck_require__(2361); -var assert = __nccwpck_require__(9491); -var util = __nccwpck_require__(3837); - - -exports.httpOverHttp = httpOverHttp; -exports.httpsOverHttp = httpsOverHttp; -exports.httpOverHttps = httpOverHttps; -exports.httpsOverHttps = httpsOverHttps; - - -function httpOverHttp(options) { - var agent = new TunnelingAgent(options); - agent.request = http.request; - return agent; -} - -function httpsOverHttp(options) { - var agent = new TunnelingAgent(options); - agent.request = http.request; - agent.createSocket = createSecureSocket; - agent.defaultPort = 443; - return agent; -} - -function httpOverHttps(options) { - var agent = new TunnelingAgent(options); - agent.request = https.request; - return agent; -} - -function httpsOverHttps(options) { - var agent = new TunnelingAgent(options); - agent.request = https.request; - agent.createSocket = createSecureSocket; - agent.defaultPort = 443; - return agent; -} - - -function TunnelingAgent(options) { - var self = this; - self.options = options || {}; - self.proxyOptions = self.options.proxy || {}; - self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets; - self.requests = []; - self.sockets = []; - - self.on('free', function onFree(socket, host, port, localAddress) { - var options = toOptions(host, port, localAddress); - for (var i = 0, len = self.requests.length; i < len; ++i) { - var pending = self.requests[i]; - if (pending.host === options.host && pending.port === options.port) { - // Detect the request to connect same origin server, - // reuse the connection. - self.requests.splice(i, 1); - pending.request.onSocket(socket); - return; - } - } - socket.destroy(); - self.removeSocket(socket); - }); -} -util.inherits(TunnelingAgent, events.EventEmitter); - -TunnelingAgent.prototype.addRequest = function addRequest(req, host, port, localAddress) { - var self = this; - var options = mergeOptions({request: req}, self.options, toOptions(host, port, localAddress)); - - if (self.sockets.length >= this.maxSockets) { - // We are over limit so we'll add it to the queue. - self.requests.push(options); - return; - } - - // If we are under maxSockets create a new one. - self.createSocket(options, function(socket) { - socket.on('free', onFree); - socket.on('close', onCloseOrRemove); - socket.on('agentRemove', onCloseOrRemove); - req.onSocket(socket); - - function onFree() { - self.emit('free', socket, options); - } - - function onCloseOrRemove(err) { - self.removeSocket(socket); - socket.removeListener('free', onFree); - socket.removeListener('close', onCloseOrRemove); - socket.removeListener('agentRemove', onCloseOrRemove); - } - }); -}; - -TunnelingAgent.prototype.createSocket = function createSocket(options, cb) { - var self = this; - var placeholder = {}; - self.sockets.push(placeholder); - - var connectOptions = mergeOptions({}, self.proxyOptions, { - method: 'CONNECT', - path: options.host + ':' + options.port, - agent: false, - headers: { - host: options.host + ':' + options.port - } - }); - if (options.localAddress) { - connectOptions.localAddress = options.localAddress; - } - if (connectOptions.proxyAuth) { - connectOptions.headers = connectOptions.headers || {}; - connectOptions.headers['Proxy-Authorization'] = 'Basic ' + - new Buffer(connectOptions.proxyAuth).toString('base64'); - } - - debug('making CONNECT request'); - var connectReq = self.request(connectOptions); - connectReq.useChunkedEncodingByDefault = false; // for v0.6 - connectReq.once('response', onResponse); // for v0.6 - connectReq.once('upgrade', onUpgrade); // for v0.6 - connectReq.once('connect', onConnect); // for v0.7 or later - connectReq.once('error', onError); - connectReq.end(); - - function onResponse(res) { - // Very hacky. This is necessary to avoid http-parser leaks. - res.upgrade = true; - } - - function onUpgrade(res, socket, head) { - // Hacky. - process.nextTick(function() { - onConnect(res, socket, head); - }); - } - - function onConnect(res, socket, head) { - connectReq.removeAllListeners(); - socket.removeAllListeners(); - - if (res.statusCode !== 200) { - debug('tunneling socket could not be established, statusCode=%d', - res.statusCode); - socket.destroy(); - var error = new Error('tunneling socket could not be established, ' + - 'statusCode=' + res.statusCode); - error.code = 'ECONNRESET'; - options.request.emit('error', error); - self.removeSocket(placeholder); - return; - } - if (head.length > 0) { - debug('got illegal response body from proxy'); - socket.destroy(); - var error = new Error('got illegal response body from proxy'); - error.code = 'ECONNRESET'; - options.request.emit('error', error); - self.removeSocket(placeholder); - return; - } - debug('tunneling connection has established'); - self.sockets[self.sockets.indexOf(placeholder)] = socket; - return cb(socket); - } - - function onError(cause) { - connectReq.removeAllListeners(); - - debug('tunneling socket could not be established, cause=%s\n', - cause.message, cause.stack); - var error = new Error('tunneling socket could not be established, ' + - 'cause=' + cause.message); - error.code = 'ECONNRESET'; - options.request.emit('error', error); - self.removeSocket(placeholder); - } -}; - -TunnelingAgent.prototype.removeSocket = function removeSocket(socket) { - var pos = this.sockets.indexOf(socket) - if (pos === -1) { - return; - } - this.sockets.splice(pos, 1); - - var pending = this.requests.shift(); - if (pending) { - // If we have pending requests and a socket gets closed a new one - // needs to be created to take over in the pool for the one that closed. - this.createSocket(pending, function(socket) { - pending.request.onSocket(socket); - }); - } -}; - -function createSecureSocket(options, cb) { - var self = this; - TunnelingAgent.prototype.createSocket.call(self, options, function(socket) { - var hostHeader = options.request.getHeader('host'); - var tlsOptions = mergeOptions({}, self.options, { - socket: socket, - servername: hostHeader ? hostHeader.replace(/:.*$/, '') : options.host - }); - - // 0 is dummy port for v0.6 - var secureSocket = tls.connect(0, tlsOptions); - self.sockets[self.sockets.indexOf(socket)] = secureSocket; - cb(secureSocket); - }); -} - - -function toOptions(host, port, localAddress) { - if (typeof host === 'string') { // since v0.10 - return { - host: host, - port: port, - localAddress: localAddress - }; - } - return host; // for v0.11 or later -} - -function mergeOptions(target) { - for (var i = 1, len = arguments.length; i < len; ++i) { - var overrides = arguments[i]; - if (typeof overrides === 'object') { - var keys = Object.keys(overrides); - for (var j = 0, keyLen = keys.length; j < keyLen; ++j) { - var k = keys[j]; - if (overrides[k] !== undefined) { - target[k] = overrides[k]; - } - } - } - } - return target; -} - - -var debug; -if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) { - debug = function() { - var args = Array.prototype.slice.call(arguments); - if (typeof args[0] === 'string') { - args[0] = 'TUNNEL: ' + args[0]; - } else { - args.unshift('TUNNEL:'); - } - console.error.apply(console, args); - } -} else { - debug = function() {}; -} -exports.debug = debug; // for test - - -/***/ }), - -/***/ 5116: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const Client = __nccwpck_require__(8224) -const Dispatcher = __nccwpck_require__(1312) -const errors = __nccwpck_require__(5767) -const Pool = __nccwpck_require__(9729) -const BalancedPool = __nccwpck_require__(8580) -const Agent = __nccwpck_require__(8162) -const util = __nccwpck_require__(6223) -const { InvalidArgumentError } = errors -const api = __nccwpck_require__(4596) -const buildConnector = __nccwpck_require__(3311) -const MockClient = __nccwpck_require__(624) -const MockAgent = __nccwpck_require__(8180) -const MockPool = __nccwpck_require__(3429) -const mockErrors = __nccwpck_require__(463) -const ProxyAgent = __nccwpck_require__(2498) -const { getGlobalDispatcher, setGlobalDispatcher } = __nccwpck_require__(398) -const DecoratorHandler = __nccwpck_require__(3978) -const RedirectHandler = __nccwpck_require__(1962) -const createRedirectInterceptor = __nccwpck_require__(9095) - -let hasCrypto -try { - __nccwpck_require__(6113) - hasCrypto = true -} catch { - hasCrypto = false -} - -Object.assign(Dispatcher.prototype, api) - -module.exports.Dispatcher = Dispatcher -module.exports.Client = Client -module.exports.Pool = Pool -module.exports.BalancedPool = BalancedPool -module.exports.Agent = Agent -module.exports.ProxyAgent = ProxyAgent - -module.exports.DecoratorHandler = DecoratorHandler -module.exports.RedirectHandler = RedirectHandler -module.exports.createRedirectInterceptor = createRedirectInterceptor - -module.exports.buildConnector = buildConnector -module.exports.errors = errors - -function makeDispatcher (fn) { - return (url, opts, handler) => { - if (typeof opts === 'function') { - handler = opts - opts = null - } - - if (!url || (typeof url !== 'string' && typeof url !== 'object' && !(url instanceof URL))) { - throw new InvalidArgumentError('invalid url') - } - - if (opts != null && typeof opts !== 'object') { - throw new InvalidArgumentError('invalid opts') - } - - if (opts && opts.path != null) { - if (typeof opts.path !== 'string') { - throw new InvalidArgumentError('invalid opts.path') - } - - let path = opts.path - if (!opts.path.startsWith('/')) { - path = `/${path}` - } - - url = new URL(util.parseOrigin(url).origin + path) - } else { - if (!opts) { - opts = typeof url === 'object' ? url : {} - } - - url = util.parseURL(url) - } - - const { agent, dispatcher = getGlobalDispatcher() } = opts - - if (agent) { - throw new InvalidArgumentError('unsupported opts.agent. Did you mean opts.client?') - } - - return fn.call(dispatcher, { - ...opts, - origin: url.origin, - path: url.search ? `${url.pathname}${url.search}` : url.pathname, - method: opts.method || (opts.body ? 'PUT' : 'GET') - }, handler) - } -} - -module.exports.setGlobalDispatcher = setGlobalDispatcher -module.exports.getGlobalDispatcher = getGlobalDispatcher - -if (util.nodeMajor > 16 || (util.nodeMajor === 16 && util.nodeMinor >= 8)) { - let fetchImpl = null - module.exports.fetch = async function fetch (resource) { - if (!fetchImpl) { - fetchImpl = (__nccwpck_require__(3360).fetch) - } - - try { - return await fetchImpl(...arguments) - } catch (err) { - if (typeof err === 'object') { - Error.captureStackTrace(err, this) - } - - throw err - } - } - module.exports.Headers = __nccwpck_require__(7967).Headers - module.exports.Response = __nccwpck_require__(1570).Response - module.exports.Request = __nccwpck_require__(8619).Request - module.exports.FormData = __nccwpck_require__(4595).FormData - module.exports.File = __nccwpck_require__(9072).File - module.exports.FileReader = __nccwpck_require__(7784).FileReader - - const { setGlobalOrigin, getGlobalOrigin } = __nccwpck_require__(4428) - - module.exports.setGlobalOrigin = setGlobalOrigin - module.exports.getGlobalOrigin = getGlobalOrigin - - const { CacheStorage } = __nccwpck_require__(6723) - const { kConstruct } = __nccwpck_require__(4063) - - // Cache & CacheStorage are tightly coupled with fetch. Even if it may run - // in an older version of Node, it doesn't have any use without fetch. - module.exports.caches = new CacheStorage(kConstruct) -} - -if (util.nodeMajor >= 16) { - const { deleteCookie, getCookies, getSetCookies, setCookie } = __nccwpck_require__(30) - - module.exports.deleteCookie = deleteCookie - module.exports.getCookies = getCookies - module.exports.getSetCookies = getSetCookies - module.exports.setCookie = setCookie - - const { parseMIMEType, serializeAMimeType } = __nccwpck_require__(6822) - - module.exports.parseMIMEType = parseMIMEType - module.exports.serializeAMimeType = serializeAMimeType -} - -if (util.nodeMajor >= 18 && hasCrypto) { - const { WebSocket } = __nccwpck_require__(6624) - - module.exports.WebSocket = WebSocket -} - -module.exports.request = makeDispatcher(api.request) -module.exports.stream = makeDispatcher(api.stream) -module.exports.pipeline = makeDispatcher(api.pipeline) -module.exports.connect = makeDispatcher(api.connect) -module.exports.upgrade = makeDispatcher(api.upgrade) - -module.exports.MockClient = MockClient -module.exports.MockPool = MockPool -module.exports.MockAgent = MockAgent -module.exports.mockErrors = mockErrors - - -/***/ }), - -/***/ 8162: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { InvalidArgumentError } = __nccwpck_require__(5767) -const { kClients, kRunning, kClose, kDestroy, kDispatch, kInterceptors } = __nccwpck_require__(1439) -const DispatcherBase = __nccwpck_require__(8188) -const Pool = __nccwpck_require__(9729) -const Client = __nccwpck_require__(8224) -const util = __nccwpck_require__(6223) -const createRedirectInterceptor = __nccwpck_require__(9095) -const { WeakRef, FinalizationRegistry } = __nccwpck_require__(7905)() - -const kOnConnect = Symbol('onConnect') -const kOnDisconnect = Symbol('onDisconnect') -const kOnConnectionError = Symbol('onConnectionError') -const kMaxRedirections = Symbol('maxRedirections') -const kOnDrain = Symbol('onDrain') -const kFactory = Symbol('factory') -const kFinalizer = Symbol('finalizer') -const kOptions = Symbol('options') - -function defaultFactory (origin, opts) { - return opts && opts.connections === 1 - ? new Client(origin, opts) - : new Pool(origin, opts) -} - -class Agent extends DispatcherBase { - constructor ({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { - super() - - if (typeof factory !== 'function') { - throw new InvalidArgumentError('factory must be a function.') - } - - if (connect != null && typeof connect !== 'function' && typeof connect !== 'object') { - throw new InvalidArgumentError('connect must be a function or an object') - } - - if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { - throw new InvalidArgumentError('maxRedirections must be a positive number') - } - - if (connect && typeof connect !== 'function') { - connect = { ...connect } - } - - this[kInterceptors] = options.interceptors && options.interceptors.Agent && Array.isArray(options.interceptors.Agent) - ? options.interceptors.Agent - : [createRedirectInterceptor({ maxRedirections })] - - this[kOptions] = { ...util.deepClone(options), connect } - this[kOptions].interceptors = options.interceptors - ? { ...options.interceptors } - : undefined - this[kMaxRedirections] = maxRedirections - this[kFactory] = factory - this[kClients] = new Map() - this[kFinalizer] = new FinalizationRegistry(/* istanbul ignore next: gc is undeterministic */ key => { - const ref = this[kClients].get(key) - if (ref !== undefined && ref.deref() === undefined) { - this[kClients].delete(key) - } - }) - - const agent = this - - this[kOnDrain] = (origin, targets) => { - agent.emit('drain', origin, [agent, ...targets]) - } - - this[kOnConnect] = (origin, targets) => { - agent.emit('connect', origin, [agent, ...targets]) - } - - this[kOnDisconnect] = (origin, targets, err) => { - agent.emit('disconnect', origin, [agent, ...targets], err) - } - - this[kOnConnectionError] = (origin, targets, err) => { - agent.emit('connectionError', origin, [agent, ...targets], err) - } - } - - get [kRunning] () { - let ret = 0 - for (const ref of this[kClients].values()) { - const client = ref.deref() - /* istanbul ignore next: gc is undeterministic */ - if (client) { - ret += client[kRunning] - } - } - return ret - } - - [kDispatch] (opts, handler) { - let key - if (opts.origin && (typeof opts.origin === 'string' || opts.origin instanceof URL)) { - key = String(opts.origin) - } else { - throw new InvalidArgumentError('opts.origin must be a non-empty string or URL.') - } - - const ref = this[kClients].get(key) - - let dispatcher = ref ? ref.deref() : null - if (!dispatcher) { - dispatcher = this[kFactory](opts.origin, this[kOptions]) - .on('drain', this[kOnDrain]) - .on('connect', this[kOnConnect]) - .on('disconnect', this[kOnDisconnect]) - .on('connectionError', this[kOnConnectionError]) - - this[kClients].set(key, new WeakRef(dispatcher)) - this[kFinalizer].register(dispatcher, key) - } - - return dispatcher.dispatch(opts, handler) - } - - async [kClose] () { - const closePromises = [] - for (const ref of this[kClients].values()) { - const client = ref.deref() - /* istanbul ignore else: gc is undeterministic */ - if (client) { - closePromises.push(client.close()) - } - } - - await Promise.all(closePromises) - } - - async [kDestroy] (err) { - const destroyPromises = [] - for (const ref of this[kClients].values()) { - const client = ref.deref() - /* istanbul ignore else: gc is undeterministic */ - if (client) { - destroyPromises.push(client.destroy(err)) - } - } - - await Promise.all(destroyPromises) - } -} - -module.exports = Agent - - -/***/ }), - -/***/ 1306: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -const { addAbortListener } = __nccwpck_require__(6223) -const { RequestAbortedError } = __nccwpck_require__(5767) - -const kListener = Symbol('kListener') -const kSignal = Symbol('kSignal') - -function abort (self) { - if (self.abort) { - self.abort() - } else { - self.onError(new RequestAbortedError()) - } -} - -function addSignal (self, signal) { - self[kSignal] = null - self[kListener] = null - - if (!signal) { - return - } - - if (signal.aborted) { - abort(self) - return - } - - self[kSignal] = signal - self[kListener] = () => { - abort(self) - } - - addAbortListener(self[kSignal], self[kListener]) -} - -function removeSignal (self) { - if (!self[kSignal]) { - return - } - - if ('removeEventListener' in self[kSignal]) { - self[kSignal].removeEventListener('abort', self[kListener]) - } else { - self[kSignal].removeListener('abort', self[kListener]) - } - - self[kSignal] = null - self[kListener] = null -} - -module.exports = { - addSignal, - removeSignal -} - - -/***/ }), - -/***/ 2414: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { AsyncResource } = __nccwpck_require__(852) -const { InvalidArgumentError, RequestAbortedError, SocketError } = __nccwpck_require__(5767) -const util = __nccwpck_require__(6223) -const { addSignal, removeSignal } = __nccwpck_require__(1306) - -class ConnectHandler extends AsyncResource { - constructor (opts, callback) { - if (!opts || typeof opts !== 'object') { - throw new InvalidArgumentError('invalid opts') - } - - if (typeof callback !== 'function') { - throw new InvalidArgumentError('invalid callback') - } - - const { signal, opaque, responseHeaders } = opts - - if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') { - throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget') - } - - super('UNDICI_CONNECT') - - this.opaque = opaque || null - this.responseHeaders = responseHeaders || null - this.callback = callback - this.abort = null - - addSignal(this, signal) - } - - onConnect (abort, context) { - if (!this.callback) { - throw new RequestAbortedError() - } - - this.abort = abort - this.context = context - } - - onHeaders () { - throw new SocketError('bad connect', null) - } - - onUpgrade (statusCode, rawHeaders, socket) { - const { callback, opaque, context } = this - - removeSignal(this) - - this.callback = null - - let headers = rawHeaders - // Indicates is an HTTP2Session - if (headers != null) { - headers = this.responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders) - } - - this.runInAsyncScope(callback, null, null, { - statusCode, - headers, - socket, - opaque, - context - }) - } - - onError (err) { - const { callback, opaque } = this - - removeSignal(this) - - if (callback) { - this.callback = null - queueMicrotask(() => { - this.runInAsyncScope(callback, null, err, { opaque }) - }) - } - } -} - -function connect (opts, callback) { - if (callback === undefined) { - return new Promise((resolve, reject) => { - connect.call(this, opts, (err, data) => { - return err ? reject(err) : resolve(data) - }) - }) - } - - try { - const connectHandler = new ConnectHandler(opts, callback) - this.dispatch({ ...opts, method: 'CONNECT' }, connectHandler) - } catch (err) { - if (typeof callback !== 'function') { - throw err - } - const opaque = opts && opts.opaque - queueMicrotask(() => callback(err, { opaque })) - } -} - -module.exports = connect - - -/***/ }), - -/***/ 7576: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { - Readable, - Duplex, - PassThrough -} = __nccwpck_require__(2781) -const { - InvalidArgumentError, - InvalidReturnValueError, - RequestAbortedError -} = __nccwpck_require__(5767) -const util = __nccwpck_require__(6223) -const { AsyncResource } = __nccwpck_require__(852) -const { addSignal, removeSignal } = __nccwpck_require__(1306) -const assert = __nccwpck_require__(9491) - -const kResume = Symbol('resume') - -class PipelineRequest extends Readable { - constructor () { - super({ autoDestroy: true }) - - this[kResume] = null - } - - _read () { - const { [kResume]: resume } = this - - if (resume) { - this[kResume] = null - resume() - } - } - - _destroy (err, callback) { - this._read() - - callback(err) - } -} - -class PipelineResponse extends Readable { - constructor (resume) { - super({ autoDestroy: true }) - this[kResume] = resume - } - - _read () { - this[kResume]() - } - - _destroy (err, callback) { - if (!err && !this._readableState.endEmitted) { - err = new RequestAbortedError() - } - - callback(err) - } -} - -class PipelineHandler extends AsyncResource { - constructor (opts, handler) { - if (!opts || typeof opts !== 'object') { - throw new InvalidArgumentError('invalid opts') - } - - if (typeof handler !== 'function') { - throw new InvalidArgumentError('invalid handler') - } - - const { signal, method, opaque, onInfo, responseHeaders } = opts - - if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') { - throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget') - } - - if (method === 'CONNECT') { - throw new InvalidArgumentError('invalid method') - } - - if (onInfo && typeof onInfo !== 'function') { - throw new InvalidArgumentError('invalid onInfo callback') - } - - super('UNDICI_PIPELINE') - - this.opaque = opaque || null - this.responseHeaders = responseHeaders || null - this.handler = handler - this.abort = null - this.context = null - this.onInfo = onInfo || null - - this.req = new PipelineRequest().on('error', util.nop) - - this.ret = new Duplex({ - readableObjectMode: opts.objectMode, - autoDestroy: true, - read: () => { - const { body } = this - - if (body && body.resume) { - body.resume() - } - }, - write: (chunk, encoding, callback) => { - const { req } = this - - if (req.push(chunk, encoding) || req._readableState.destroyed) { - callback() - } else { - req[kResume] = callback - } - }, - destroy: (err, callback) => { - const { body, req, res, ret, abort } = this - - if (!err && !ret._readableState.endEmitted) { - err = new RequestAbortedError() - } - - if (abort && err) { - abort() - } - - util.destroy(body, err) - util.destroy(req, err) - util.destroy(res, err) - - removeSignal(this) - - callback(err) - } - }).on('prefinish', () => { - const { req } = this - - // Node < 15 does not call _final in same tick. - req.push(null) - }) - - this.res = null - - addSignal(this, signal) - } - - onConnect (abort, context) { - const { ret, res } = this - - assert(!res, 'pipeline cannot be retried') - - if (ret.destroyed) { - throw new RequestAbortedError() - } - - this.abort = abort - this.context = context - } - - onHeaders (statusCode, rawHeaders, resume) { - const { opaque, handler, context } = this - - if (statusCode < 200) { - if (this.onInfo) { - const headers = this.responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders) - this.onInfo({ statusCode, headers }) - } - return - } - - this.res = new PipelineResponse(resume) - - let body - try { - this.handler = null - const headers = this.responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders) - body = this.runInAsyncScope(handler, null, { - statusCode, - headers, - opaque, - body: this.res, - context - }) - } catch (err) { - this.res.on('error', util.nop) - throw err - } - - if (!body || typeof body.on !== 'function') { - throw new InvalidReturnValueError('expected Readable') - } - - body - .on('data', (chunk) => { - const { ret, body } = this - - if (!ret.push(chunk) && body.pause) { - body.pause() - } - }) - .on('error', (err) => { - const { ret } = this - - util.destroy(ret, err) - }) - .on('end', () => { - const { ret } = this - - ret.push(null) - }) - .on('close', () => { - const { ret } = this - - if (!ret._readableState.ended) { - util.destroy(ret, new RequestAbortedError()) - } - }) - - this.body = body - } - - onData (chunk) { - const { res } = this - return res.push(chunk) - } - - onComplete (trailers) { - const { res } = this - res.push(null) - } - - onError (err) { - const { ret } = this - this.handler = null - util.destroy(ret, err) - } -} - -function pipeline (opts, handler) { - try { - const pipelineHandler = new PipelineHandler(opts, handler) - this.dispatch({ ...opts, body: pipelineHandler.req }, pipelineHandler) - return pipelineHandler.ret - } catch (err) { - return new PassThrough().destroy(err) - } -} - -module.exports = pipeline - - -/***/ }), - -/***/ 233: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const Readable = __nccwpck_require__(425) -const { - InvalidArgumentError, - RequestAbortedError -} = __nccwpck_require__(5767) -const util = __nccwpck_require__(6223) -const { getResolveErrorBodyCallback } = __nccwpck_require__(4726) -const { AsyncResource } = __nccwpck_require__(852) -const { addSignal, removeSignal } = __nccwpck_require__(1306) - -class RequestHandler extends AsyncResource { - constructor (opts, callback) { - if (!opts || typeof opts !== 'object') { - throw new InvalidArgumentError('invalid opts') - } - - const { signal, method, opaque, body, onInfo, responseHeaders, throwOnError, highWaterMark } = opts - - try { - if (typeof callback !== 'function') { - throw new InvalidArgumentError('invalid callback') - } - - if (highWaterMark && (typeof highWaterMark !== 'number' || highWaterMark < 0)) { - throw new InvalidArgumentError('invalid highWaterMark') - } - - if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') { - throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget') - } - - if (method === 'CONNECT') { - throw new InvalidArgumentError('invalid method') - } - - if (onInfo && typeof onInfo !== 'function') { - throw new InvalidArgumentError('invalid onInfo callback') - } - - super('UNDICI_REQUEST') - } catch (err) { - if (util.isStream(body)) { - util.destroy(body.on('error', util.nop), err) - } - throw err - } - - this.responseHeaders = responseHeaders || null - this.opaque = opaque || null - this.callback = callback - this.res = null - this.abort = null - this.body = body - this.trailers = {} - this.context = null - this.onInfo = onInfo || null - this.throwOnError = throwOnError - this.highWaterMark = highWaterMark - - if (util.isStream(body)) { - body.on('error', (err) => { - this.onError(err) - }) - } - - addSignal(this, signal) - } - - onConnect (abort, context) { - if (!this.callback) { - throw new RequestAbortedError() - } - - this.abort = abort - this.context = context - } - - onHeaders (statusCode, rawHeaders, resume, statusMessage) { - const { callback, opaque, abort, context, responseHeaders, highWaterMark } = this - - const headers = responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders) - - if (statusCode < 200) { - if (this.onInfo) { - this.onInfo({ statusCode, headers }) - } - return - } - - const parsedHeaders = responseHeaders === 'raw' ? util.parseHeaders(rawHeaders) : headers - const contentType = parsedHeaders['content-type'] - const body = new Readable({ resume, abort, contentType, highWaterMark }) - - this.callback = null - this.res = body - if (callback !== null) { - if (this.throwOnError && statusCode >= 400) { - this.runInAsyncScope(getResolveErrorBodyCallback, null, - { callback, body, contentType, statusCode, statusMessage, headers } - ) - } else { - this.runInAsyncScope(callback, null, null, { - statusCode, - headers, - trailers: this.trailers, - opaque, - body, - context - }) - } - } - } - - onData (chunk) { - const { res } = this - return res.push(chunk) - } - - onComplete (trailers) { - const { res } = this - - removeSignal(this) - - util.parseHeaders(trailers, this.trailers) - - res.push(null) - } - - onError (err) { - const { res, callback, body, opaque } = this - - removeSignal(this) - - if (callback) { - // TODO: Does this need queueMicrotask? - this.callback = null - queueMicrotask(() => { - this.runInAsyncScope(callback, null, err, { opaque }) - }) - } - - if (res) { - this.res = null - // Ensure all queued handlers are invoked before destroying res. - queueMicrotask(() => { - util.destroy(res, err) - }) - } - - if (body) { - this.body = null - util.destroy(body, err) - } - } -} - -function request (opts, callback) { - if (callback === undefined) { - return new Promise((resolve, reject) => { - request.call(this, opts, (err, data) => { - return err ? reject(err) : resolve(data) - }) - }) - } - - try { - this.dispatch(opts, new RequestHandler(opts, callback)) - } catch (err) { - if (typeof callback !== 'function') { - throw err - } - const opaque = opts && opts.opaque - queueMicrotask(() => callback(err, { opaque })) - } -} - -module.exports = request - - -/***/ }), - -/***/ 5401: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { finished, PassThrough } = __nccwpck_require__(2781) -const { - InvalidArgumentError, - InvalidReturnValueError, - RequestAbortedError -} = __nccwpck_require__(5767) -const util = __nccwpck_require__(6223) -const { getResolveErrorBodyCallback } = __nccwpck_require__(4726) -const { AsyncResource } = __nccwpck_require__(852) -const { addSignal, removeSignal } = __nccwpck_require__(1306) - -class StreamHandler extends AsyncResource { - constructor (opts, factory, callback) { - if (!opts || typeof opts !== 'object') { - throw new InvalidArgumentError('invalid opts') - } - - const { signal, method, opaque, body, onInfo, responseHeaders, throwOnError } = opts - - try { - if (typeof callback !== 'function') { - throw new InvalidArgumentError('invalid callback') - } - - if (typeof factory !== 'function') { - throw new InvalidArgumentError('invalid factory') - } - - if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') { - throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget') - } - - if (method === 'CONNECT') { - throw new InvalidArgumentError('invalid method') - } - - if (onInfo && typeof onInfo !== 'function') { - throw new InvalidArgumentError('invalid onInfo callback') - } - - super('UNDICI_STREAM') - } catch (err) { - if (util.isStream(body)) { - util.destroy(body.on('error', util.nop), err) - } - throw err - } - - this.responseHeaders = responseHeaders || null - this.opaque = opaque || null - this.factory = factory - this.callback = callback - this.res = null - this.abort = null - this.context = null - this.trailers = null - this.body = body - this.onInfo = onInfo || null - this.throwOnError = throwOnError || false - - if (util.isStream(body)) { - body.on('error', (err) => { - this.onError(err) - }) - } - - addSignal(this, signal) - } - - onConnect (abort, context) { - if (!this.callback) { - throw new RequestAbortedError() - } - - this.abort = abort - this.context = context - } - - onHeaders (statusCode, rawHeaders, resume, statusMessage) { - const { factory, opaque, context, callback, responseHeaders } = this - - const headers = responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders) - - if (statusCode < 200) { - if (this.onInfo) { - this.onInfo({ statusCode, headers }) - } - return - } - - this.factory = null - - let res - - if (this.throwOnError && statusCode >= 400) { - const parsedHeaders = responseHeaders === 'raw' ? util.parseHeaders(rawHeaders) : headers - const contentType = parsedHeaders['content-type'] - res = new PassThrough() - - this.callback = null - this.runInAsyncScope(getResolveErrorBodyCallback, null, - { callback, body: res, contentType, statusCode, statusMessage, headers } - ) - } else { - if (factory === null) { - return - } - - res = this.runInAsyncScope(factory, null, { - statusCode, - headers, - opaque, - context - }) - - if ( - !res || - typeof res.write !== 'function' || - typeof res.end !== 'function' || - typeof res.on !== 'function' - ) { - throw new InvalidReturnValueError('expected Writable') - } - - // TODO: Avoid finished. It registers an unnecessary amount of listeners. - finished(res, { readable: false }, (err) => { - const { callback, res, opaque, trailers, abort } = this - - this.res = null - if (err || !res.readable) { - util.destroy(res, err) - } - - this.callback = null - this.runInAsyncScope(callback, null, err || null, { opaque, trailers }) - - if (err) { - abort() - } - }) - } - - res.on('drain', resume) - - this.res = res - - const needDrain = res.writableNeedDrain !== undefined - ? res.writableNeedDrain - : res._writableState && res._writableState.needDrain - - return needDrain !== true - } - - onData (chunk) { - const { res } = this - - return res ? res.write(chunk) : true - } - - onComplete (trailers) { - const { res } = this - - removeSignal(this) - - if (!res) { - return - } - - this.trailers = util.parseHeaders(trailers) - - res.end() - } - - onError (err) { - const { res, callback, opaque, body } = this - - removeSignal(this) - - this.factory = null - - if (res) { - this.res = null - util.destroy(res, err) - } else if (callback) { - this.callback = null - queueMicrotask(() => { - this.runInAsyncScope(callback, null, err, { opaque }) - }) - } - - if (body) { - this.body = null - util.destroy(body, err) - } - } -} - -function stream (opts, factory, callback) { - if (callback === undefined) { - return new Promise((resolve, reject) => { - stream.call(this, opts, factory, (err, data) => { - return err ? reject(err) : resolve(data) - }) - }) - } - - try { - this.dispatch(opts, new StreamHandler(opts, factory, callback)) - } catch (err) { - if (typeof callback !== 'function') { - throw err - } - const opaque = opts && opts.opaque - queueMicrotask(() => callback(err, { opaque })) - } -} - -module.exports = stream - - -/***/ }), - -/***/ 1771: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { InvalidArgumentError, RequestAbortedError, SocketError } = __nccwpck_require__(5767) -const { AsyncResource } = __nccwpck_require__(852) -const util = __nccwpck_require__(6223) -const { addSignal, removeSignal } = __nccwpck_require__(1306) -const assert = __nccwpck_require__(9491) - -class UpgradeHandler extends AsyncResource { - constructor (opts, callback) { - if (!opts || typeof opts !== 'object') { - throw new InvalidArgumentError('invalid opts') - } - - if (typeof callback !== 'function') { - throw new InvalidArgumentError('invalid callback') - } - - const { signal, opaque, responseHeaders } = opts - - if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') { - throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget') - } - - super('UNDICI_UPGRADE') - - this.responseHeaders = responseHeaders || null - this.opaque = opaque || null - this.callback = callback - this.abort = null - this.context = null - - addSignal(this, signal) - } - - onConnect (abort, context) { - if (!this.callback) { - throw new RequestAbortedError() - } - - this.abort = abort - this.context = null - } - - onHeaders () { - throw new SocketError('bad upgrade', null) - } - - onUpgrade (statusCode, rawHeaders, socket) { - const { callback, opaque, context } = this - - assert.strictEqual(statusCode, 101) - - removeSignal(this) - - this.callback = null - const headers = this.responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders) - this.runInAsyncScope(callback, null, null, { - headers, - socket, - opaque, - context - }) - } - - onError (err) { - const { callback, opaque } = this - - removeSignal(this) - - if (callback) { - this.callback = null - queueMicrotask(() => { - this.runInAsyncScope(callback, null, err, { opaque }) - }) - } - } -} - -function upgrade (opts, callback) { - if (callback === undefined) { - return new Promise((resolve, reject) => { - upgrade.call(this, opts, (err, data) => { - return err ? reject(err) : resolve(data) - }) - }) - } - - try { - const upgradeHandler = new UpgradeHandler(opts, callback) - this.dispatch({ - ...opts, - method: opts.method || 'GET', - upgrade: opts.protocol || 'Websocket' - }, upgradeHandler) - } catch (err) { - if (typeof callback !== 'function') { - throw err - } - const opaque = opts && opts.opaque - queueMicrotask(() => callback(err, { opaque })) - } -} - -module.exports = upgrade - - -/***/ }), - -/***/ 4596: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -module.exports.request = __nccwpck_require__(233) -module.exports.stream = __nccwpck_require__(5401) -module.exports.pipeline = __nccwpck_require__(7576) -module.exports.upgrade = __nccwpck_require__(1771) -module.exports.connect = __nccwpck_require__(2414) - - -/***/ }), - -/***/ 425: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// Ported from https://github.com/nodejs/undici/pull/907 - - - -const assert = __nccwpck_require__(9491) -const { Readable } = __nccwpck_require__(2781) -const { RequestAbortedError, NotSupportedError, InvalidArgumentError } = __nccwpck_require__(5767) -const util = __nccwpck_require__(6223) -const { ReadableStreamFrom, toUSVString } = __nccwpck_require__(6223) - -let Blob - -const kConsume = Symbol('kConsume') -const kReading = Symbol('kReading') -const kBody = Symbol('kBody') -const kAbort = Symbol('abort') -const kContentType = Symbol('kContentType') - -module.exports = class BodyReadable extends Readable { - constructor ({ - resume, - abort, - contentType = '', - highWaterMark = 64 * 1024 // Same as nodejs fs streams. - }) { - super({ - autoDestroy: true, - read: resume, - highWaterMark - }) - - this._readableState.dataEmitted = false - - this[kAbort] = abort - this[kConsume] = null - this[kBody] = null - this[kContentType] = contentType - - // Is stream being consumed through Readable API? - // This is an optimization so that we avoid checking - // for 'data' and 'readable' listeners in the hot path - // inside push(). - this[kReading] = false - } - - destroy (err) { - if (this.destroyed) { - // Node < 16 - return this - } - - if (!err && !this._readableState.endEmitted) { - err = new RequestAbortedError() - } - - if (err) { - this[kAbort]() - } - - return super.destroy(err) - } - - emit (ev, ...args) { - if (ev === 'data') { - // Node < 16.7 - this._readableState.dataEmitted = true - } else if (ev === 'error') { - // Node < 16 - this._readableState.errorEmitted = true - } - return super.emit(ev, ...args) - } - - on (ev, ...args) { - if (ev === 'data' || ev === 'readable') { - this[kReading] = true - } - return super.on(ev, ...args) - } - - addListener (ev, ...args) { - return this.on(ev, ...args) - } - - off (ev, ...args) { - const ret = super.off(ev, ...args) - if (ev === 'data' || ev === 'readable') { - this[kReading] = ( - this.listenerCount('data') > 0 || - this.listenerCount('readable') > 0 - ) - } - return ret - } - - removeListener (ev, ...args) { - return this.off(ev, ...args) - } - - push (chunk) { - if (this[kConsume] && chunk !== null && this.readableLength === 0) { - consumePush(this[kConsume], chunk) - return this[kReading] ? super.push(chunk) : true - } - return super.push(chunk) - } - - // https://fetch.spec.whatwg.org/#dom-body-text - async text () { - return consume(this, 'text') - } - - // https://fetch.spec.whatwg.org/#dom-body-json - async json () { - return consume(this, 'json') - } - - // https://fetch.spec.whatwg.org/#dom-body-blob - async blob () { - return consume(this, 'blob') - } - - // https://fetch.spec.whatwg.org/#dom-body-arraybuffer - async arrayBuffer () { - return consume(this, 'arrayBuffer') - } - - // https://fetch.spec.whatwg.org/#dom-body-formdata - async formData () { - // TODO: Implement. - throw new NotSupportedError() - } - - // https://fetch.spec.whatwg.org/#dom-body-bodyused - get bodyUsed () { - return util.isDisturbed(this) - } - - // https://fetch.spec.whatwg.org/#dom-body-body - get body () { - if (!this[kBody]) { - this[kBody] = ReadableStreamFrom(this) - if (this[kConsume]) { - // TODO: Is this the best way to force a lock? - this[kBody].getReader() // Ensure stream is locked. - assert(this[kBody].locked) - } - } - return this[kBody] - } - - async dump (opts) { - let limit = opts && Number.isFinite(opts.limit) ? opts.limit : 262144 - const signal = opts && opts.signal - const abortFn = () => { - this.destroy() - } - let signalListenerCleanup - if (signal) { - if (typeof signal !== 'object' || !('aborted' in signal)) { - throw new InvalidArgumentError('signal must be an AbortSignal') - } - util.throwIfAborted(signal) - signalListenerCleanup = util.addAbortListener(signal, abortFn) - } - try { - for await (const chunk of this) { - util.throwIfAborted(signal) - limit -= Buffer.byteLength(chunk) - if (limit < 0) { - return - } - } - } catch { - util.throwIfAborted(signal) - } finally { - if (typeof signalListenerCleanup === 'function') { - signalListenerCleanup() - } else if (signalListenerCleanup) { - signalListenerCleanup[Symbol.dispose]() - } - } - } -} - -// https://streams.spec.whatwg.org/#readablestream-locked -function isLocked (self) { - // Consume is an implicit lock. - return (self[kBody] && self[kBody].locked === true) || self[kConsume] -} - -// https://fetch.spec.whatwg.org/#body-unusable -function isUnusable (self) { - return util.isDisturbed(self) || isLocked(self) -} - -async function consume (stream, type) { - if (isUnusable(stream)) { - throw new TypeError('unusable') - } - - assert(!stream[kConsume]) - - return new Promise((resolve, reject) => { - stream[kConsume] = { - type, - stream, - resolve, - reject, - length: 0, - body: [] - } - - stream - .on('error', function (err) { - consumeFinish(this[kConsume], err) - }) - .on('close', function () { - if (this[kConsume].body !== null) { - consumeFinish(this[kConsume], new RequestAbortedError()) - } - }) - - process.nextTick(consumeStart, stream[kConsume]) - }) -} - -function consumeStart (consume) { - if (consume.body === null) { - return - } - - const { _readableState: state } = consume.stream - - for (const chunk of state.buffer) { - consumePush(consume, chunk) - } - - if (state.endEmitted) { - consumeEnd(this[kConsume]) - } else { - consume.stream.on('end', function () { - consumeEnd(this[kConsume]) - }) - } - - consume.stream.resume() - - while (consume.stream.read() != null) { - // Loop - } -} - -function consumeEnd (consume) { - const { type, body, resolve, stream, length } = consume - - try { - if (type === 'text') { - resolve(toUSVString(Buffer.concat(body))) - } else if (type === 'json') { - resolve(JSON.parse(Buffer.concat(body))) - } else if (type === 'arrayBuffer') { - const dst = new Uint8Array(length) - - let pos = 0 - for (const buf of body) { - dst.set(buf, pos) - pos += buf.byteLength - } - - resolve(dst.buffer) - } else if (type === 'blob') { - if (!Blob) { - Blob = (__nccwpck_require__(4300).Blob) - } - resolve(new Blob(body, { type: stream[kContentType] })) - } - - consumeFinish(consume) - } catch (err) { - stream.destroy(err) - } -} - -function consumePush (consume, chunk) { - consume.length += chunk.length - consume.body.push(chunk) -} - -function consumeFinish (consume, err) { - if (consume.body === null) { - return - } - - if (err) { - consume.reject(err) - } else { - consume.resolve() - } - - consume.type = null - consume.stream = null - consume.resolve = null - consume.reject = null - consume.length = 0 - consume.body = null -} - - -/***/ }), - -/***/ 4726: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -const assert = __nccwpck_require__(9491) -const { - ResponseStatusCodeError -} = __nccwpck_require__(5767) -const { toUSVString } = __nccwpck_require__(6223) - -async function getResolveErrorBodyCallback ({ callback, body, contentType, statusCode, statusMessage, headers }) { - assert(body) - - let chunks = [] - let limit = 0 - - for await (const chunk of body) { - chunks.push(chunk) - limit += chunk.length - if (limit > 128 * 1024) { - chunks = null - break - } - } - - if (statusCode === 204 || !contentType || !chunks) { - process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers)) - return - } - - try { - if (contentType.startsWith('application/json')) { - const payload = JSON.parse(toUSVString(Buffer.concat(chunks))) - process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers, payload)) - return - } - - if (contentType.startsWith('text/')) { - const payload = toUSVString(Buffer.concat(chunks)) - process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers, payload)) - return - } - } catch (err) { - // Process in a fallback if error - } - - process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers)) -} - -module.exports = { getResolveErrorBodyCallback } - - -/***/ }), - -/***/ 8580: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { - BalancedPoolMissingUpstreamError, - InvalidArgumentError -} = __nccwpck_require__(5767) -const { - PoolBase, - kClients, - kNeedDrain, - kAddClient, - kRemoveClient, - kGetDispatcher -} = __nccwpck_require__(1273) -const Pool = __nccwpck_require__(9729) -const { kUrl, kInterceptors } = __nccwpck_require__(1439) -const { parseOrigin } = __nccwpck_require__(6223) -const kFactory = Symbol('factory') - -const kOptions = Symbol('options') -const kGreatestCommonDivisor = Symbol('kGreatestCommonDivisor') -const kCurrentWeight = Symbol('kCurrentWeight') -const kIndex = Symbol('kIndex') -const kWeight = Symbol('kWeight') -const kMaxWeightPerServer = Symbol('kMaxWeightPerServer') -const kErrorPenalty = Symbol('kErrorPenalty') - -function getGreatestCommonDivisor (a, b) { - if (b === 0) return a - return getGreatestCommonDivisor(b, a % b) -} - -function defaultFactory (origin, opts) { - return new Pool(origin, opts) -} - -class BalancedPool extends PoolBase { - constructor (upstreams = [], { factory = defaultFactory, ...opts } = {}) { - super() - - this[kOptions] = opts - this[kIndex] = -1 - this[kCurrentWeight] = 0 - - this[kMaxWeightPerServer] = this[kOptions].maxWeightPerServer || 100 - this[kErrorPenalty] = this[kOptions].errorPenalty || 15 - - if (!Array.isArray(upstreams)) { - upstreams = [upstreams] - } - - if (typeof factory !== 'function') { - throw new InvalidArgumentError('factory must be a function.') - } - - this[kInterceptors] = opts.interceptors && opts.interceptors.BalancedPool && Array.isArray(opts.interceptors.BalancedPool) - ? opts.interceptors.BalancedPool - : [] - this[kFactory] = factory - - for (const upstream of upstreams) { - this.addUpstream(upstream) - } - this._updateBalancedPoolStats() - } - - addUpstream (upstream) { - const upstreamOrigin = parseOrigin(upstream).origin - - if (this[kClients].find((pool) => ( - pool[kUrl].origin === upstreamOrigin && - pool.closed !== true && - pool.destroyed !== true - ))) { - return this - } - const pool = this[kFactory](upstreamOrigin, Object.assign({}, this[kOptions])) - - this[kAddClient](pool) - pool.on('connect', () => { - pool[kWeight] = Math.min(this[kMaxWeightPerServer], pool[kWeight] + this[kErrorPenalty]) - }) - - pool.on('connectionError', () => { - pool[kWeight] = Math.max(1, pool[kWeight] - this[kErrorPenalty]) - this._updateBalancedPoolStats() - }) - - pool.on('disconnect', (...args) => { - const err = args[2] - if (err && err.code === 'UND_ERR_SOCKET') { - // decrease the weight of the pool. - pool[kWeight] = Math.max(1, pool[kWeight] - this[kErrorPenalty]) - this._updateBalancedPoolStats() - } - }) - - for (const client of this[kClients]) { - client[kWeight] = this[kMaxWeightPerServer] - } - - this._updateBalancedPoolStats() - - return this - } - - _updateBalancedPoolStats () { - this[kGreatestCommonDivisor] = this[kClients].map(p => p[kWeight]).reduce(getGreatestCommonDivisor, 0) - } - - removeUpstream (upstream) { - const upstreamOrigin = parseOrigin(upstream).origin - - const pool = this[kClients].find((pool) => ( - pool[kUrl].origin === upstreamOrigin && - pool.closed !== true && - pool.destroyed !== true - )) - - if (pool) { - this[kRemoveClient](pool) - } - - return this - } - - get upstreams () { - return this[kClients] - .filter(dispatcher => dispatcher.closed !== true && dispatcher.destroyed !== true) - .map((p) => p[kUrl].origin) - } - - [kGetDispatcher] () { - // We validate that pools is greater than 0, - // otherwise we would have to wait until an upstream - // is added, which might never happen. - if (this[kClients].length === 0) { - throw new BalancedPoolMissingUpstreamError() - } - - const dispatcher = this[kClients].find(dispatcher => ( - !dispatcher[kNeedDrain] && - dispatcher.closed !== true && - dispatcher.destroyed !== true - )) - - if (!dispatcher) { - return - } - - const allClientsBusy = this[kClients].map(pool => pool[kNeedDrain]).reduce((a, b) => a && b, true) - - if (allClientsBusy) { - return - } - - let counter = 0 - - let maxWeightIndex = this[kClients].findIndex(pool => !pool[kNeedDrain]) - - while (counter++ < this[kClients].length) { - this[kIndex] = (this[kIndex] + 1) % this[kClients].length - const pool = this[kClients][this[kIndex]] - - // find pool index with the largest weight - if (pool[kWeight] > this[kClients][maxWeightIndex][kWeight] && !pool[kNeedDrain]) { - maxWeightIndex = this[kIndex] - } - - // decrease the current weight every `this[kClients].length`. - if (this[kIndex] === 0) { - // Set the current weight to the next lower weight. - this[kCurrentWeight] = this[kCurrentWeight] - this[kGreatestCommonDivisor] - - if (this[kCurrentWeight] <= 0) { - this[kCurrentWeight] = this[kMaxWeightPerServer] - } - } - if (pool[kWeight] >= this[kCurrentWeight] && (!pool[kNeedDrain])) { - return pool - } - } - - this[kCurrentWeight] = this[kClients][maxWeightIndex][kWeight] - this[kIndex] = maxWeightIndex - return this[kClients][maxWeightIndex] - } -} - -module.exports = BalancedPool - - -/***/ }), - -/***/ 7011: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { kConstruct } = __nccwpck_require__(4063) -const { urlEquals, fieldValues: getFieldValues } = __nccwpck_require__(8265) -const { kEnumerableProperty, isDisturbed } = __nccwpck_require__(6223) -const { kHeadersList } = __nccwpck_require__(1439) -const { webidl } = __nccwpck_require__(5337) -const { Response, cloneResponse } = __nccwpck_require__(1570) -const { Request } = __nccwpck_require__(8619) -const { kState, kHeaders, kGuard, kRealm } = __nccwpck_require__(1048) -const { fetching } = __nccwpck_require__(3360) -const { urlIsHttpHttpsScheme, createDeferredPromise, readAllBytes } = __nccwpck_require__(6913) -const assert = __nccwpck_require__(9491) -const { getGlobalDispatcher } = __nccwpck_require__(398) - -/** - * @see https://w3c.github.io/ServiceWorker/#dfn-cache-batch-operation - * @typedef {Object} CacheBatchOperation - * @property {'delete' | 'put'} type - * @property {any} request - * @property {any} response - * @property {import('../../types/cache').CacheQueryOptions} options - */ - -/** - * @see https://w3c.github.io/ServiceWorker/#dfn-request-response-list - * @typedef {[any, any][]} requestResponseList - */ - -class Cache { - /** - * @see https://w3c.github.io/ServiceWorker/#dfn-relevant-request-response-list - * @type {requestResponseList} - */ - #relevantRequestResponseList - - constructor () { - if (arguments[0] !== kConstruct) { - webidl.illegalConstructor() - } - - this.#relevantRequestResponseList = arguments[1] - } - - async match (request, options = {}) { - webidl.brandCheck(this, Cache) - webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.match' }) - - request = webidl.converters.RequestInfo(request) - options = webidl.converters.CacheQueryOptions(options) - - const p = await this.matchAll(request, options) - - if (p.length === 0) { - return - } - - return p[0] - } - - async matchAll (request = undefined, options = {}) { - webidl.brandCheck(this, Cache) - - if (request !== undefined) request = webidl.converters.RequestInfo(request) - options = webidl.converters.CacheQueryOptions(options) - - // 1. - let r = null - - // 2. - if (request !== undefined) { - if (request instanceof Request) { - // 2.1.1 - r = request[kState] - - // 2.1.2 - if (r.method !== 'GET' && !options.ignoreMethod) { - return [] - } - } else if (typeof request === 'string') { - // 2.2.1 - r = new Request(request)[kState] - } - } - - // 5. - // 5.1 - const responses = [] - - // 5.2 - if (request === undefined) { - // 5.2.1 - for (const requestResponse of this.#relevantRequestResponseList) { - responses.push(requestResponse[1]) - } - } else { // 5.3 - // 5.3.1 - const requestResponses = this.#queryCache(r, options) - - // 5.3.2 - for (const requestResponse of requestResponses) { - responses.push(requestResponse[1]) - } - } - - // 5.4 - // We don't implement CORs so we don't need to loop over the responses, yay! - - // 5.5.1 - const responseList = [] - - // 5.5.2 - for (const response of responses) { - // 5.5.2.1 - const responseObject = new Response(response.body?.source ?? null) - const body = responseObject[kState].body - responseObject[kState] = response - responseObject[kState].body = body - responseObject[kHeaders][kHeadersList] = response.headersList - responseObject[kHeaders][kGuard] = 'immutable' - - responseList.push(responseObject) - } - - // 6. - return Object.freeze(responseList) - } - - async add (request) { - webidl.brandCheck(this, Cache) - webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.add' }) - - request = webidl.converters.RequestInfo(request) - - // 1. - const requests = [request] - - // 2. - const responseArrayPromise = this.addAll(requests) - - // 3. - return await responseArrayPromise - } - - async addAll (requests) { - webidl.brandCheck(this, Cache) - webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.addAll' }) - - requests = webidl.converters['sequence<RequestInfo>'](requests) - - // 1. - const responsePromises = [] - - // 2. - const requestList = [] - - // 3. - for (const request of requests) { - if (typeof request === 'string') { - continue - } - - // 3.1 - const r = request[kState] - - // 3.2 - if (!urlIsHttpHttpsScheme(r.url) || r.method !== 'GET') { - throw webidl.errors.exception({ - header: 'Cache.addAll', - message: 'Expected http/s scheme when method is not GET.' - }) - } - } - - // 4. - /** @type {ReturnType<typeof fetching>[]} */ - const fetchControllers = [] - - // 5. - for (const request of requests) { - // 5.1 - const r = new Request(request)[kState] - - // 5.2 - if (!urlIsHttpHttpsScheme(r.url)) { - throw webidl.errors.exception({ - header: 'Cache.addAll', - message: 'Expected http/s scheme.' - }) - } - - // 5.4 - r.initiator = 'fetch' - r.destination = 'subresource' - - // 5.5 - requestList.push(r) - - // 5.6 - const responsePromise = createDeferredPromise() - - // 5.7 - fetchControllers.push(fetching({ - request: r, - dispatcher: getGlobalDispatcher(), - processResponse (response) { - // 1. - if (response.type === 'error' || response.status === 206 || response.status < 200 || response.status > 299) { - responsePromise.reject(webidl.errors.exception({ - header: 'Cache.addAll', - message: 'Received an invalid status code or the request failed.' - })) - } else if (response.headersList.contains('vary')) { // 2. - // 2.1 - const fieldValues = getFieldValues(response.headersList.get('vary')) - - // 2.2 - for (const fieldValue of fieldValues) { - // 2.2.1 - if (fieldValue === '*') { - responsePromise.reject(webidl.errors.exception({ - header: 'Cache.addAll', - message: 'invalid vary field value' - })) - - for (const controller of fetchControllers) { - controller.abort() - } - - return - } - } - } - }, - processResponseEndOfBody (response) { - // 1. - if (response.aborted) { - responsePromise.reject(new DOMException('aborted', 'AbortError')) - return - } - - // 2. - responsePromise.resolve(response) - } - })) - - // 5.8 - responsePromises.push(responsePromise.promise) - } - - // 6. - const p = Promise.all(responsePromises) - - // 7. - const responses = await p - - // 7.1 - const operations = [] - - // 7.2 - let index = 0 - - // 7.3 - for (const response of responses) { - // 7.3.1 - /** @type {CacheBatchOperation} */ - const operation = { - type: 'put', // 7.3.2 - request: requestList[index], // 7.3.3 - response // 7.3.4 - } - - operations.push(operation) // 7.3.5 - - index++ // 7.3.6 - } - - // 7.5 - const cacheJobPromise = createDeferredPromise() - - // 7.6.1 - let errorData = null - - // 7.6.2 - try { - this.#batchCacheOperations(operations) - } catch (e) { - errorData = e - } - - // 7.6.3 - queueMicrotask(() => { - // 7.6.3.1 - if (errorData === null) { - cacheJobPromise.resolve(undefined) - } else { - // 7.6.3.2 - cacheJobPromise.reject(errorData) - } - }) - - // 7.7 - return cacheJobPromise.promise - } - - async put (request, response) { - webidl.brandCheck(this, Cache) - webidl.argumentLengthCheck(arguments, 2, { header: 'Cache.put' }) - - request = webidl.converters.RequestInfo(request) - response = webidl.converters.Response(response) - - // 1. - let innerRequest = null - - // 2. - if (request instanceof Request) { - innerRequest = request[kState] - } else { // 3. - innerRequest = new Request(request)[kState] - } - - // 4. - if (!urlIsHttpHttpsScheme(innerRequest.url) || innerRequest.method !== 'GET') { - throw webidl.errors.exception({ - header: 'Cache.put', - message: 'Expected an http/s scheme when method is not GET' - }) - } - - // 5. - const innerResponse = response[kState] - - // 6. - if (innerResponse.status === 206) { - throw webidl.errors.exception({ - header: 'Cache.put', - message: 'Got 206 status' - }) - } - - // 7. - if (innerResponse.headersList.contains('vary')) { - // 7.1. - const fieldValues = getFieldValues(innerResponse.headersList.get('vary')) - - // 7.2. - for (const fieldValue of fieldValues) { - // 7.2.1 - if (fieldValue === '*') { - throw webidl.errors.exception({ - header: 'Cache.put', - message: 'Got * vary field value' - }) - } - } - } - - // 8. - if (innerResponse.body && (isDisturbed(innerResponse.body.stream) || innerResponse.body.stream.locked)) { - throw webidl.errors.exception({ - header: 'Cache.put', - message: 'Response body is locked or disturbed' - }) - } - - // 9. - const clonedResponse = cloneResponse(innerResponse) - - // 10. - const bodyReadPromise = createDeferredPromise() - - // 11. - if (innerResponse.body != null) { - // 11.1 - const stream = innerResponse.body.stream - - // 11.2 - const reader = stream.getReader() - - // 11.3 - readAllBytes(reader).then(bodyReadPromise.resolve, bodyReadPromise.reject) - } else { - bodyReadPromise.resolve(undefined) - } - - // 12. - /** @type {CacheBatchOperation[]} */ - const operations = [] - - // 13. - /** @type {CacheBatchOperation} */ - const operation = { - type: 'put', // 14. - request: innerRequest, // 15. - response: clonedResponse // 16. - } - - // 17. - operations.push(operation) - - // 19. - const bytes = await bodyReadPromise.promise - - if (clonedResponse.body != null) { - clonedResponse.body.source = bytes - } - - // 19.1 - const cacheJobPromise = createDeferredPromise() - - // 19.2.1 - let errorData = null - - // 19.2.2 - try { - this.#batchCacheOperations(operations) - } catch (e) { - errorData = e - } - - // 19.2.3 - queueMicrotask(() => { - // 19.2.3.1 - if (errorData === null) { - cacheJobPromise.resolve() - } else { // 19.2.3.2 - cacheJobPromise.reject(errorData) - } - }) - - return cacheJobPromise.promise - } - - async delete (request, options = {}) { - webidl.brandCheck(this, Cache) - webidl.argumentLengthCheck(arguments, 1, { header: 'Cache.delete' }) - - request = webidl.converters.RequestInfo(request) - options = webidl.converters.CacheQueryOptions(options) - - /** - * @type {Request} - */ - let r = null - - if (request instanceof Request) { - r = request[kState] - - if (r.method !== 'GET' && !options.ignoreMethod) { - return false - } - } else { - assert(typeof request === 'string') - - r = new Request(request)[kState] - } - - /** @type {CacheBatchOperation[]} */ - const operations = [] - - /** @type {CacheBatchOperation} */ - const operation = { - type: 'delete', - request: r, - options - } - - operations.push(operation) - - const cacheJobPromise = createDeferredPromise() - - let errorData = null - let requestResponses - - try { - requestResponses = this.#batchCacheOperations(operations) - } catch (e) { - errorData = e - } - - queueMicrotask(() => { - if (errorData === null) { - cacheJobPromise.resolve(!!requestResponses?.length) - } else { - cacheJobPromise.reject(errorData) - } - }) - - return cacheJobPromise.promise - } - - /** - * @see https://w3c.github.io/ServiceWorker/#dom-cache-keys - * @param {any} request - * @param {import('../../types/cache').CacheQueryOptions} options - * @returns {readonly Request[]} - */ - async keys (request = undefined, options = {}) { - webidl.brandCheck(this, Cache) - - if (request !== undefined) request = webidl.converters.RequestInfo(request) - options = webidl.converters.CacheQueryOptions(options) - - // 1. - let r = null - - // 2. - if (request !== undefined) { - // 2.1 - if (request instanceof Request) { - // 2.1.1 - r = request[kState] - - // 2.1.2 - if (r.method !== 'GET' && !options.ignoreMethod) { - return [] - } - } else if (typeof request === 'string') { // 2.2 - r = new Request(request)[kState] - } - } - - // 4. - const promise = createDeferredPromise() - - // 5. - // 5.1 - const requests = [] - - // 5.2 - if (request === undefined) { - // 5.2.1 - for (const requestResponse of this.#relevantRequestResponseList) { - // 5.2.1.1 - requests.push(requestResponse[0]) - } - } else { // 5.3 - // 5.3.1 - const requestResponses = this.#queryCache(r, options) - - // 5.3.2 - for (const requestResponse of requestResponses) { - // 5.3.2.1 - requests.push(requestResponse[0]) - } - } - - // 5.4 - queueMicrotask(() => { - // 5.4.1 - const requestList = [] - - // 5.4.2 - for (const request of requests) { - const requestObject = new Request('https://a') - requestObject[kState] = request - requestObject[kHeaders][kHeadersList] = request.headersList - requestObject[kHeaders][kGuard] = 'immutable' - requestObject[kRealm] = request.client - - // 5.4.2.1 - requestList.push(requestObject) - } - - // 5.4.3 - promise.resolve(Object.freeze(requestList)) - }) - - return promise.promise - } - - /** - * @see https://w3c.github.io/ServiceWorker/#batch-cache-operations-algorithm - * @param {CacheBatchOperation[]} operations - * @returns {requestResponseList} - */ - #batchCacheOperations (operations) { - // 1. - const cache = this.#relevantRequestResponseList - - // 2. - const backupCache = [...cache] - - // 3. - const addedItems = [] - - // 4.1 - const resultList = [] - - try { - // 4.2 - for (const operation of operations) { - // 4.2.1 - if (operation.type !== 'delete' && operation.type !== 'put') { - throw webidl.errors.exception({ - header: 'Cache.#batchCacheOperations', - message: 'operation type does not match "delete" or "put"' - }) - } - - // 4.2.2 - if (operation.type === 'delete' && operation.response != null) { - throw webidl.errors.exception({ - header: 'Cache.#batchCacheOperations', - message: 'delete operation should not have an associated response' - }) - } - - // 4.2.3 - if (this.#queryCache(operation.request, operation.options, addedItems).length) { - throw new DOMException('???', 'InvalidStateError') - } - - // 4.2.4 - let requestResponses - - // 4.2.5 - if (operation.type === 'delete') { - // 4.2.5.1 - requestResponses = this.#queryCache(operation.request, operation.options) - - // TODO: the spec is wrong, this is needed to pass WPTs - if (requestResponses.length === 0) { - return [] - } - - // 4.2.5.2 - for (const requestResponse of requestResponses) { - const idx = cache.indexOf(requestResponse) - assert(idx !== -1) - - // 4.2.5.2.1 - cache.splice(idx, 1) - } - } else if (operation.type === 'put') { // 4.2.6 - // 4.2.6.1 - if (operation.response == null) { - throw webidl.errors.exception({ - header: 'Cache.#batchCacheOperations', - message: 'put operation should have an associated response' - }) - } - - // 4.2.6.2 - const r = operation.request - - // 4.2.6.3 - if (!urlIsHttpHttpsScheme(r.url)) { - throw webidl.errors.exception({ - header: 'Cache.#batchCacheOperations', - message: 'expected http or https scheme' - }) - } - - // 4.2.6.4 - if (r.method !== 'GET') { - throw webidl.errors.exception({ - header: 'Cache.#batchCacheOperations', - message: 'not get method' - }) - } - - // 4.2.6.5 - if (operation.options != null) { - throw webidl.errors.exception({ - header: 'Cache.#batchCacheOperations', - message: 'options must not be defined' - }) - } - - // 4.2.6.6 - requestResponses = this.#queryCache(operation.request) - - // 4.2.6.7 - for (const requestResponse of requestResponses) { - const idx = cache.indexOf(requestResponse) - assert(idx !== -1) - - // 4.2.6.7.1 - cache.splice(idx, 1) - } - - // 4.2.6.8 - cache.push([operation.request, operation.response]) - - // 4.2.6.10 - addedItems.push([operation.request, operation.response]) - } - - // 4.2.7 - resultList.push([operation.request, operation.response]) - } - - // 4.3 - return resultList - } catch (e) { // 5. - // 5.1 - this.#relevantRequestResponseList.length = 0 - - // 5.2 - this.#relevantRequestResponseList = backupCache - - // 5.3 - throw e - } - } - - /** - * @see https://w3c.github.io/ServiceWorker/#query-cache - * @param {any} requestQuery - * @param {import('../../types/cache').CacheQueryOptions} options - * @param {requestResponseList} targetStorage - * @returns {requestResponseList} - */ - #queryCache (requestQuery, options, targetStorage) { - /** @type {requestResponseList} */ - const resultList = [] - - const storage = targetStorage ?? this.#relevantRequestResponseList - - for (const requestResponse of storage) { - const [cachedRequest, cachedResponse] = requestResponse - if (this.#requestMatchesCachedItem(requestQuery, cachedRequest, cachedResponse, options)) { - resultList.push(requestResponse) - } - } - - return resultList - } - - /** - * @see https://w3c.github.io/ServiceWorker/#request-matches-cached-item-algorithm - * @param {any} requestQuery - * @param {any} request - * @param {any | null} response - * @param {import('../../types/cache').CacheQueryOptions | undefined} options - * @returns {boolean} - */ - #requestMatchesCachedItem (requestQuery, request, response = null, options) { - // if (options?.ignoreMethod === false && request.method === 'GET') { - // return false - // } - - const queryURL = new URL(requestQuery.url) - - const cachedURL = new URL(request.url) - - if (options?.ignoreSearch) { - cachedURL.search = '' - - queryURL.search = '' - } - - if (!urlEquals(queryURL, cachedURL, true)) { - return false - } - - if ( - response == null || - options?.ignoreVary || - !response.headersList.contains('vary') - ) { - return true - } - - const fieldValues = getFieldValues(response.headersList.get('vary')) - - for (const fieldValue of fieldValues) { - if (fieldValue === '*') { - return false - } - - const requestValue = request.headersList.get(fieldValue) - const queryValue = requestQuery.headersList.get(fieldValue) - - // If one has the header and the other doesn't, or one has - // a different value than the other, return false - if (requestValue !== queryValue) { - return false - } - } - - return true - } -} - -Object.defineProperties(Cache.prototype, { - [Symbol.toStringTag]: { - value: 'Cache', - configurable: true - }, - match: kEnumerableProperty, - matchAll: kEnumerableProperty, - add: kEnumerableProperty, - addAll: kEnumerableProperty, - put: kEnumerableProperty, - delete: kEnumerableProperty, - keys: kEnumerableProperty -}) - -const cacheQueryOptionConverters = [ - { - key: 'ignoreSearch', - converter: webidl.converters.boolean, - defaultValue: false - }, - { - key: 'ignoreMethod', - converter: webidl.converters.boolean, - defaultValue: false - }, - { - key: 'ignoreVary', - converter: webidl.converters.boolean, - defaultValue: false - } -] - -webidl.converters.CacheQueryOptions = webidl.dictionaryConverter(cacheQueryOptionConverters) - -webidl.converters.MultiCacheQueryOptions = webidl.dictionaryConverter([ - ...cacheQueryOptionConverters, - { - key: 'cacheName', - converter: webidl.converters.DOMString - } -]) - -webidl.converters.Response = webidl.interfaceConverter(Response) - -webidl.converters['sequence<RequestInfo>'] = webidl.sequenceConverter( - webidl.converters.RequestInfo -) - -module.exports = { - Cache -} - - -/***/ }), - -/***/ 6723: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { kConstruct } = __nccwpck_require__(4063) -const { Cache } = __nccwpck_require__(7011) -const { webidl } = __nccwpck_require__(5337) -const { kEnumerableProperty } = __nccwpck_require__(6223) - -class CacheStorage { - /** - * @see https://w3c.github.io/ServiceWorker/#dfn-relevant-name-to-cache-map - * @type {Map<string, import('./cache').requestResponseList} - */ - #caches = new Map() - - constructor () { - if (arguments[0] !== kConstruct) { - webidl.illegalConstructor() - } - } - - async match (request, options = {}) { - webidl.brandCheck(this, CacheStorage) - webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.match' }) - - request = webidl.converters.RequestInfo(request) - options = webidl.converters.MultiCacheQueryOptions(options) - - // 1. - if (options.cacheName != null) { - // 1.1.1.1 - if (this.#caches.has(options.cacheName)) { - // 1.1.1.1.1 - const cacheList = this.#caches.get(options.cacheName) - const cache = new Cache(kConstruct, cacheList) - - return await cache.match(request, options) - } - } else { // 2. - // 2.2 - for (const cacheList of this.#caches.values()) { - const cache = new Cache(kConstruct, cacheList) - - // 2.2.1.2 - const response = await cache.match(request, options) - - if (response !== undefined) { - return response - } - } - } - } - - /** - * @see https://w3c.github.io/ServiceWorker/#cache-storage-has - * @param {string} cacheName - * @returns {Promise<boolean>} - */ - async has (cacheName) { - webidl.brandCheck(this, CacheStorage) - webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.has' }) - - cacheName = webidl.converters.DOMString(cacheName) - - // 2.1.1 - // 2.2 - return this.#caches.has(cacheName) - } - - /** - * @see https://w3c.github.io/ServiceWorker/#dom-cachestorage-open - * @param {string} cacheName - * @returns {Promise<Cache>} - */ - async open (cacheName) { - webidl.brandCheck(this, CacheStorage) - webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.open' }) - - cacheName = webidl.converters.DOMString(cacheName) - - // 2.1 - if (this.#caches.has(cacheName)) { - // await caches.open('v1') !== await caches.open('v1') - - // 2.1.1 - const cache = this.#caches.get(cacheName) - - // 2.1.1.1 - return new Cache(kConstruct, cache) - } - - // 2.2 - const cache = [] - - // 2.3 - this.#caches.set(cacheName, cache) - - // 2.4 - return new Cache(kConstruct, cache) - } - - /** - * @see https://w3c.github.io/ServiceWorker/#cache-storage-delete - * @param {string} cacheName - * @returns {Promise<boolean>} - */ - async delete (cacheName) { - webidl.brandCheck(this, CacheStorage) - webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.delete' }) - - cacheName = webidl.converters.DOMString(cacheName) - - return this.#caches.delete(cacheName) - } - - /** - * @see https://w3c.github.io/ServiceWorker/#cache-storage-keys - * @returns {string[]} - */ - async keys () { - webidl.brandCheck(this, CacheStorage) - - // 2.1 - const keys = this.#caches.keys() - - // 2.2 - return [...keys] - } -} - -Object.defineProperties(CacheStorage.prototype, { - [Symbol.toStringTag]: { - value: 'CacheStorage', - configurable: true - }, - match: kEnumerableProperty, - has: kEnumerableProperty, - open: kEnumerableProperty, - delete: kEnumerableProperty, - keys: kEnumerableProperty -}) - -module.exports = { - CacheStorage -} - - -/***/ }), - -/***/ 4063: -/***/ ((module) => { - -"use strict"; - - -module.exports = { - kConstruct: Symbol('constructable') -} - - -/***/ }), - -/***/ 8265: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const assert = __nccwpck_require__(9491) -const { URLSerializer } = __nccwpck_require__(6822) -const { isValidHeaderName } = __nccwpck_require__(6913) - -/** - * @see https://url.spec.whatwg.org/#concept-url-equals - * @param {URL} A - * @param {URL} B - * @param {boolean | undefined} excludeFragment - * @returns {boolean} - */ -function urlEquals (A, B, excludeFragment = false) { - const serializedA = URLSerializer(A, excludeFragment) - - const serializedB = URLSerializer(B, excludeFragment) - - return serializedA === serializedB -} - -/** - * @see https://github.com/chromium/chromium/blob/694d20d134cb553d8d89e5500b9148012b1ba299/content/browser/cache_storage/cache_storage_cache.cc#L260-L262 - * @param {string} header - */ -function fieldValues (header) { - assert(header !== null) - - const values = [] - - for (let value of header.split(',')) { - value = value.trim() - - if (!value.length) { - continue - } else if (!isValidHeaderName(value)) { - continue - } - - values.push(value) - } - - return values -} - -module.exports = { - urlEquals, - fieldValues -} - - -/***/ }), - -/***/ 8224: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -/* global WebAssembly */ - -const assert = __nccwpck_require__(9491) -const net = __nccwpck_require__(1808) -const http = __nccwpck_require__(3685) -const { pipeline } = __nccwpck_require__(2781) -const util = __nccwpck_require__(6223) -const timers = __nccwpck_require__(8581) -const Request = __nccwpck_require__(1562) -const DispatcherBase = __nccwpck_require__(8188) -const { - RequestContentLengthMismatchError, - ResponseContentLengthMismatchError, - InvalidArgumentError, - RequestAbortedError, - HeadersTimeoutError, - HeadersOverflowError, - SocketError, - InformationalError, - BodyTimeoutError, - HTTPParserError, - ResponseExceededMaxSizeError, - ClientDestroyedError -} = __nccwpck_require__(5767) -const buildConnector = __nccwpck_require__(3311) -const { - kUrl, - kReset, - kServerName, - kClient, - kBusy, - kParser, - kConnect, - kBlocking, - kResuming, - kRunning, - kPending, - kSize, - kWriting, - kQueue, - kConnected, - kConnecting, - kNeedDrain, - kNoRef, - kKeepAliveDefaultTimeout, - kHostHeader, - kPendingIdx, - kRunningIdx, - kError, - kPipelining, - kSocket, - kKeepAliveTimeoutValue, - kMaxHeadersSize, - kKeepAliveMaxTimeout, - kKeepAliveTimeoutThreshold, - kHeadersTimeout, - kBodyTimeout, - kStrictContentLength, - kConnector, - kMaxRedirections, - kMaxRequests, - kCounter, - kClose, - kDestroy, - kDispatch, - kInterceptors, - kLocalAddress, - kMaxResponseSize, - kHTTPConnVersion, - // HTTP2 - kHost, - kHTTP2Session, - kHTTP2SessionState, - kHTTP2BuildRequest, - kHTTP2CopyHeaders, - kHTTP1BuildRequest -} = __nccwpck_require__(1439) - -/** @type {import('http2')} */ -let http2 -try { - http2 = __nccwpck_require__(5158) -} catch { - // @ts-ignore - http2 = { constants: {} } -} - -const { - constants: { - HTTP2_HEADER_AUTHORITY, - HTTP2_HEADER_METHOD, - HTTP2_HEADER_PATH, - HTTP2_HEADER_SCHEME, - HTTP2_HEADER_CONTENT_LENGTH, - HTTP2_HEADER_EXPECT, - HTTP2_HEADER_STATUS - } -} = http2 - -// Experimental -let h2ExperimentalWarned = false - -const FastBuffer = Buffer[Symbol.species] - -const kClosedResolve = Symbol('kClosedResolve') - -const channels = {} - -try { - const diagnosticsChannel = __nccwpck_require__(7643) - channels.sendHeaders = diagnosticsChannel.channel('undici:client:sendHeaders') - channels.beforeConnect = diagnosticsChannel.channel('undici:client:beforeConnect') - channels.connectError = diagnosticsChannel.channel('undici:client:connectError') - channels.connected = diagnosticsChannel.channel('undici:client:connected') -} catch { - channels.sendHeaders = { hasSubscribers: false } - channels.beforeConnect = { hasSubscribers: false } - channels.connectError = { hasSubscribers: false } - channels.connected = { hasSubscribers: false } -} - -/** - * @type {import('../types/client').default} - */ -class Client extends DispatcherBase { - /** - * - * @param {string|URL} url - * @param {import('../types/client').Client.Options} options - */ - constructor (url, { - interceptors, - maxHeaderSize, - headersTimeout, - socketTimeout, - requestTimeout, - connectTimeout, - bodyTimeout, - idleTimeout, - keepAlive, - keepAliveTimeout, - maxKeepAliveTimeout, - keepAliveMaxTimeout, - keepAliveTimeoutThreshold, - socketPath, - pipelining, - tls, - strictContentLength, - maxCachedSessions, - maxRedirections, - connect, - maxRequestsPerClient, - localAddress, - maxResponseSize, - autoSelectFamily, - autoSelectFamilyAttemptTimeout, - // h2 - allowH2, - maxConcurrentStreams - } = {}) { - super() - - if (keepAlive !== undefined) { - throw new InvalidArgumentError('unsupported keepAlive, use pipelining=0 instead') - } - - if (socketTimeout !== undefined) { - throw new InvalidArgumentError('unsupported socketTimeout, use headersTimeout & bodyTimeout instead') - } - - if (requestTimeout !== undefined) { - throw new InvalidArgumentError('unsupported requestTimeout, use headersTimeout & bodyTimeout instead') - } - - if (idleTimeout !== undefined) { - throw new InvalidArgumentError('unsupported idleTimeout, use keepAliveTimeout instead') - } - - if (maxKeepAliveTimeout !== undefined) { - throw new InvalidArgumentError('unsupported maxKeepAliveTimeout, use keepAliveMaxTimeout instead') - } - - if (maxHeaderSize != null && !Number.isFinite(maxHeaderSize)) { - throw new InvalidArgumentError('invalid maxHeaderSize') - } - - if (socketPath != null && typeof socketPath !== 'string') { - throw new InvalidArgumentError('invalid socketPath') - } - - if (connectTimeout != null && (!Number.isFinite(connectTimeout) || connectTimeout < 0)) { - throw new InvalidArgumentError('invalid connectTimeout') - } - - if (keepAliveTimeout != null && (!Number.isFinite(keepAliveTimeout) || keepAliveTimeout <= 0)) { - throw new InvalidArgumentError('invalid keepAliveTimeout') - } - - if (keepAliveMaxTimeout != null && (!Number.isFinite(keepAliveMaxTimeout) || keepAliveMaxTimeout <= 0)) { - throw new InvalidArgumentError('invalid keepAliveMaxTimeout') - } - - if (keepAliveTimeoutThreshold != null && !Number.isFinite(keepAliveTimeoutThreshold)) { - throw new InvalidArgumentError('invalid keepAliveTimeoutThreshold') - } - - if (headersTimeout != null && (!Number.isInteger(headersTimeout) || headersTimeout < 0)) { - throw new InvalidArgumentError('headersTimeout must be a positive integer or zero') - } - - if (bodyTimeout != null && (!Number.isInteger(bodyTimeout) || bodyTimeout < 0)) { - throw new InvalidArgumentError('bodyTimeout must be a positive integer or zero') - } - - if (connect != null && typeof connect !== 'function' && typeof connect !== 'object') { - throw new InvalidArgumentError('connect must be a function or an object') - } - - if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) { - throw new InvalidArgumentError('maxRedirections must be a positive number') - } - - if (maxRequestsPerClient != null && (!Number.isInteger(maxRequestsPerClient) || maxRequestsPerClient < 0)) { - throw new InvalidArgumentError('maxRequestsPerClient must be a positive number') - } - - if (localAddress != null && (typeof localAddress !== 'string' || net.isIP(localAddress) === 0)) { - throw new InvalidArgumentError('localAddress must be valid string IP address') - } - - if (maxResponseSize != null && (!Number.isInteger(maxResponseSize) || maxResponseSize < -1)) { - throw new InvalidArgumentError('maxResponseSize must be a positive number') - } - - if ( - autoSelectFamilyAttemptTimeout != null && - (!Number.isInteger(autoSelectFamilyAttemptTimeout) || autoSelectFamilyAttemptTimeout < -1) - ) { - throw new InvalidArgumentError('autoSelectFamilyAttemptTimeout must be a positive number') - } - - // h2 - if (allowH2 != null && typeof allowH2 !== 'boolean') { - throw new InvalidArgumentError('allowH2 must be a valid boolean value') - } - - if (maxConcurrentStreams != null && (typeof maxConcurrentStreams !== 'number' || maxConcurrentStreams < 1)) { - throw new InvalidArgumentError('maxConcurrentStreams must be a possitive integer, greater than 0') - } - - if (typeof connect !== 'function') { - connect = buildConnector({ - ...tls, - maxCachedSessions, - allowH2, - socketPath, - timeout: connectTimeout, - ...(util.nodeHasAutoSelectFamily && autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined), - ...connect - }) - } - - this[kInterceptors] = interceptors && interceptors.Client && Array.isArray(interceptors.Client) - ? interceptors.Client - : [createRedirectInterceptor({ maxRedirections })] - this[kUrl] = util.parseOrigin(url) - this[kConnector] = connect - this[kSocket] = null - this[kPipelining] = pipelining != null ? pipelining : 1 - this[kMaxHeadersSize] = maxHeaderSize || http.maxHeaderSize - this[kKeepAliveDefaultTimeout] = keepAliveTimeout == null ? 4e3 : keepAliveTimeout - this[kKeepAliveMaxTimeout] = keepAliveMaxTimeout == null ? 600e3 : keepAliveMaxTimeout - this[kKeepAliveTimeoutThreshold] = keepAliveTimeoutThreshold == null ? 1e3 : keepAliveTimeoutThreshold - this[kKeepAliveTimeoutValue] = this[kKeepAliveDefaultTimeout] - this[kServerName] = null - this[kLocalAddress] = localAddress != null ? localAddress : null - this[kResuming] = 0 // 0, idle, 1, scheduled, 2 resuming - this[kNeedDrain] = 0 // 0, idle, 1, scheduled, 2 resuming - this[kHostHeader] = `host: ${this[kUrl].hostname}${this[kUrl].port ? `:${this[kUrl].port}` : ''}\r\n` - this[kBodyTimeout] = bodyTimeout != null ? bodyTimeout : 300e3 - this[kHeadersTimeout] = headersTimeout != null ? headersTimeout : 300e3 - this[kStrictContentLength] = strictContentLength == null ? true : strictContentLength - this[kMaxRedirections] = maxRedirections - this[kMaxRequests] = maxRequestsPerClient - this[kClosedResolve] = null - this[kMaxResponseSize] = maxResponseSize > -1 ? maxResponseSize : -1 - this[kHTTPConnVersion] = 'h1' - - // HTTP/2 - this[kHTTP2Session] = null - this[kHTTP2SessionState] = !allowH2 - ? null - : { - // streams: null, // Fixed queue of streams - For future support of `push` - openStreams: 0, // Keep track of them to decide wether or not unref the session - maxConcurrentStreams: maxConcurrentStreams != null ? maxConcurrentStreams : 100 // Max peerConcurrentStreams for a Node h2 server - } - this[kHost] = `${this[kUrl].hostname}${this[kUrl].port ? `:${this[kUrl].port}` : ''}` - - // kQueue is built up of 3 sections separated by - // the kRunningIdx and kPendingIdx indices. - // | complete | running | pending | - // ^ kRunningIdx ^ kPendingIdx ^ kQueue.length - // kRunningIdx points to the first running element. - // kPendingIdx points to the first pending element. - // This implements a fast queue with an amortized - // time of O(1). - - this[kQueue] = [] - this[kRunningIdx] = 0 - this[kPendingIdx] = 0 - } - - get pipelining () { - return this[kPipelining] - } - - set pipelining (value) { - this[kPipelining] = value - resume(this, true) - } - - get [kPending] () { - return this[kQueue].length - this[kPendingIdx] - } - - get [kRunning] () { - return this[kPendingIdx] - this[kRunningIdx] - } - - get [kSize] () { - return this[kQueue].length - this[kRunningIdx] - } - - get [kConnected] () { - return !!this[kSocket] && !this[kConnecting] && !this[kSocket].destroyed - } - - get [kBusy] () { - const socket = this[kSocket] - return ( - (socket && (socket[kReset] || socket[kWriting] || socket[kBlocking])) || - (this[kSize] >= (this[kPipelining] || 1)) || - this[kPending] > 0 - ) - } - - /* istanbul ignore: only used for test */ - [kConnect] (cb) { - connect(this) - this.once('connect', cb) - } - - [kDispatch] (opts, handler) { - const origin = opts.origin || this[kUrl].origin - - const request = this[kHTTPConnVersion] === 'h2' - ? Request[kHTTP2BuildRequest](origin, opts, handler) - : Request[kHTTP1BuildRequest](origin, opts, handler) - - this[kQueue].push(request) - if (this[kResuming]) { - // Do nothing. - } else if (util.bodyLength(request.body) == null && util.isIterable(request.body)) { - // Wait a tick in case stream/iterator is ended in the same tick. - this[kResuming] = 1 - process.nextTick(resume, this) - } else { - resume(this, true) - } - - if (this[kResuming] && this[kNeedDrain] !== 2 && this[kBusy]) { - this[kNeedDrain] = 2 - } - - return this[kNeedDrain] < 2 - } - - async [kClose] () { - // TODO: for H2 we need to gracefully flush the remaining enqueued - // request and close each stream. - return new Promise((resolve) => { - if (!this[kSize]) { - resolve(null) - } else { - this[kClosedResolve] = resolve - } - }) - } - - async [kDestroy] (err) { - return new Promise((resolve) => { - const requests = this[kQueue].splice(this[kPendingIdx]) - for (let i = 0; i < requests.length; i++) { - const request = requests[i] - errorRequest(this, request, err) - } - - const callback = () => { - if (this[kClosedResolve]) { - // TODO (fix): Should we error here with ClientDestroyedError? - this[kClosedResolve]() - this[kClosedResolve] = null - } - resolve() - } - - if (this[kHTTP2Session] != null) { - util.destroy(this[kHTTP2Session], err) - this[kHTTP2Session] = null - this[kHTTP2SessionState] = null - } - - if (!this[kSocket]) { - queueMicrotask(callback) - } else { - util.destroy(this[kSocket].on('close', callback), err) - } - - resume(this) - }) - } -} - -function onHttp2SessionError (err) { - assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID') - - this[kSocket][kError] = err - - onError(this[kClient], err) -} - -function onHttp2FrameError (type, code, id) { - const err = new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`) - - if (id === 0) { - this[kSocket][kError] = err - onError(this[kClient], err) - } -} - -function onHttp2SessionEnd () { - util.destroy(this, new SocketError('other side closed')) - util.destroy(this[kSocket], new SocketError('other side closed')) -} - -function onHTTP2GoAway (code) { - const client = this[kClient] - const err = new InformationalError(`HTTP/2: "GOAWAY" frame received with code ${code}`) - client[kSocket] = null - client[kHTTP2Session] = null - - if (client.destroyed) { - assert(this[kPending] === 0) - - // Fail entire queue. - const requests = client[kQueue].splice(client[kRunningIdx]) - for (let i = 0; i < requests.length; i++) { - const request = requests[i] - errorRequest(this, request, err) - } - } else if (client[kRunning] > 0) { - // Fail head of pipeline. - const request = client[kQueue][client[kRunningIdx]] - client[kQueue][client[kRunningIdx]++] = null - - errorRequest(client, request, err) - } - - client[kPendingIdx] = client[kRunningIdx] - - assert(client[kRunning] === 0) - - client.emit('disconnect', - client[kUrl], - [client], - err - ) - - resume(client) -} - -const constants = __nccwpck_require__(6744) -const createRedirectInterceptor = __nccwpck_require__(9095) -const EMPTY_BUF = Buffer.alloc(0) - -async function lazyllhttp () { - const llhttpWasmData = process.env.JEST_WORKER_ID ? __nccwpck_require__(7445) : undefined - - let mod - try { - mod = await WebAssembly.compile(Buffer.from(__nccwpck_require__(6442), 'base64')) - } catch (e) { - /* istanbul ignore next */ - - // We could check if the error was caused by the simd option not - // being enabled, but the occurring of this other error - // * https://github.com/emscripten-core/emscripten/issues/11495 - // got me to remove that check to avoid breaking Node 12. - mod = await WebAssembly.compile(Buffer.from(llhttpWasmData || __nccwpck_require__(7445), 'base64')) - } - - return await WebAssembly.instantiate(mod, { - env: { - /* eslint-disable camelcase */ - - wasm_on_url: (p, at, len) => { - /* istanbul ignore next */ - return 0 - }, - wasm_on_status: (p, at, len) => { - assert.strictEqual(currentParser.ptr, p) - const start = at - currentBufferPtr + currentBufferRef.byteOffset - return currentParser.onStatus(new FastBuffer(currentBufferRef.buffer, start, len)) || 0 - }, - wasm_on_message_begin: (p) => { - assert.strictEqual(currentParser.ptr, p) - return currentParser.onMessageBegin() || 0 - }, - wasm_on_header_field: (p, at, len) => { - assert.strictEqual(currentParser.ptr, p) - const start = at - currentBufferPtr + currentBufferRef.byteOffset - return currentParser.onHeaderField(new FastBuffer(currentBufferRef.buffer, start, len)) || 0 - }, - wasm_on_header_value: (p, at, len) => { - assert.strictEqual(currentParser.ptr, p) - const start = at - currentBufferPtr + currentBufferRef.byteOffset - return currentParser.onHeaderValue(new FastBuffer(currentBufferRef.buffer, start, len)) || 0 - }, - wasm_on_headers_complete: (p, statusCode, upgrade, shouldKeepAlive) => { - assert.strictEqual(currentParser.ptr, p) - return currentParser.onHeadersComplete(statusCode, Boolean(upgrade), Boolean(shouldKeepAlive)) || 0 - }, - wasm_on_body: (p, at, len) => { - assert.strictEqual(currentParser.ptr, p) - const start = at - currentBufferPtr + currentBufferRef.byteOffset - return currentParser.onBody(new FastBuffer(currentBufferRef.buffer, start, len)) || 0 - }, - wasm_on_message_complete: (p) => { - assert.strictEqual(currentParser.ptr, p) - return currentParser.onMessageComplete() || 0 - } - - /* eslint-enable camelcase */ - } - }) -} - -let llhttpInstance = null -let llhttpPromise = lazyllhttp() -llhttpPromise.catch() - -let currentParser = null -let currentBufferRef = null -let currentBufferSize = 0 -let currentBufferPtr = null - -const TIMEOUT_HEADERS = 1 -const TIMEOUT_BODY = 2 -const TIMEOUT_IDLE = 3 - -class Parser { - constructor (client, socket, { exports }) { - assert(Number.isFinite(client[kMaxHeadersSize]) && client[kMaxHeadersSize] > 0) - - this.llhttp = exports - this.ptr = this.llhttp.llhttp_alloc(constants.TYPE.RESPONSE) - this.client = client - this.socket = socket - this.timeout = null - this.timeoutValue = null - this.timeoutType = null - this.statusCode = null - this.statusText = '' - this.upgrade = false - this.headers = [] - this.headersSize = 0 - this.headersMaxSize = client[kMaxHeadersSize] - this.shouldKeepAlive = false - this.paused = false - this.resume = this.resume.bind(this) - - this.bytesRead = 0 - - this.keepAlive = '' - this.contentLength = '' - this.connection = '' - this.maxResponseSize = client[kMaxResponseSize] - } - - setTimeout (value, type) { - this.timeoutType = type - if (value !== this.timeoutValue) { - timers.clearTimeout(this.timeout) - if (value) { - this.timeout = timers.setTimeout(onParserTimeout, value, this) - // istanbul ignore else: only for jest - if (this.timeout.unref) { - this.timeout.unref() - } - } else { - this.timeout = null - } - this.timeoutValue = value - } else if (this.timeout) { - // istanbul ignore else: only for jest - if (this.timeout.refresh) { - this.timeout.refresh() - } - } - } - - resume () { - if (this.socket.destroyed || !this.paused) { - return - } - - assert(this.ptr != null) - assert(currentParser == null) - - this.llhttp.llhttp_resume(this.ptr) - - assert(this.timeoutType === TIMEOUT_BODY) - if (this.timeout) { - // istanbul ignore else: only for jest - if (this.timeout.refresh) { - this.timeout.refresh() - } - } - - this.paused = false - this.execute(this.socket.read() || EMPTY_BUF) // Flush parser. - this.readMore() - } - - readMore () { - while (!this.paused && this.ptr) { - const chunk = this.socket.read() - if (chunk === null) { - break - } - this.execute(chunk) - } - } - - execute (data) { - assert(this.ptr != null) - assert(currentParser == null) - assert(!this.paused) - - const { socket, llhttp } = this - - if (data.length > currentBufferSize) { - if (currentBufferPtr) { - llhttp.free(currentBufferPtr) - } - currentBufferSize = Math.ceil(data.length / 4096) * 4096 - currentBufferPtr = llhttp.malloc(currentBufferSize) - } - - new Uint8Array(llhttp.memory.buffer, currentBufferPtr, currentBufferSize).set(data) - - // Call `execute` on the wasm parser. - // We pass the `llhttp_parser` pointer address, the pointer address of buffer view data, - // and finally the length of bytes to parse. - // The return value is an error code or `constants.ERROR.OK`. - try { - let ret - - try { - currentBufferRef = data - currentParser = this - ret = llhttp.llhttp_execute(this.ptr, currentBufferPtr, data.length) - /* eslint-disable-next-line no-useless-catch */ - } catch (err) { - /* istanbul ignore next: difficult to make a test case for */ - throw err - } finally { - currentParser = null - currentBufferRef = null - } - - const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr - - if (ret === constants.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(data.slice(offset)) - } else if (ret === constants.ERROR.PAUSED) { - this.paused = true - socket.unshift(data.slice(offset)) - } else if (ret !== constants.ERROR.OK) { - const ptr = llhttp.llhttp_get_error_reason(this.ptr) - let message = '' - /* istanbul ignore else: difficult to make a test case for */ - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0) - message = - 'Response does not match the HTTP/1.1 protocol (' + - Buffer.from(llhttp.memory.buffer, ptr, len).toString() + - ')' - } - throw new HTTPParserError(message, constants.ERROR[ret], data.slice(offset)) - } - } catch (err) { - util.destroy(socket, err) - } - } - - destroy () { - assert(this.ptr != null) - assert(currentParser == null) - - this.llhttp.llhttp_free(this.ptr) - this.ptr = null - - timers.clearTimeout(this.timeout) - this.timeout = null - this.timeoutValue = null - this.timeoutType = null - - this.paused = false - } - - onStatus (buf) { - this.statusText = buf.toString() - } - - onMessageBegin () { - const { socket, client } = this - - /* istanbul ignore next: difficult to make a test case for */ - if (socket.destroyed) { - return -1 - } - - const request = client[kQueue][client[kRunningIdx]] - if (!request) { - return -1 - } - } - - onHeaderField (buf) { - const len = this.headers.length - - if ((len & 1) === 0) { - this.headers.push(buf) - } else { - this.headers[len - 1] = Buffer.concat([this.headers[len - 1], buf]) - } - - this.trackHeader(buf.length) - } - - onHeaderValue (buf) { - let len = this.headers.length - - if ((len & 1) === 1) { - this.headers.push(buf) - len += 1 - } else { - this.headers[len - 1] = Buffer.concat([this.headers[len - 1], buf]) - } - - const key = this.headers[len - 2] - if (key.length === 10 && key.toString().toLowerCase() === 'keep-alive') { - this.keepAlive += buf.toString() - } else if (key.length === 10 && key.toString().toLowerCase() === 'connection') { - this.connection += buf.toString() - } else if (key.length === 14 && key.toString().toLowerCase() === 'content-length') { - this.contentLength += buf.toString() - } - - this.trackHeader(buf.length) - } - - trackHeader (len) { - this.headersSize += len - if (this.headersSize >= this.headersMaxSize) { - util.destroy(this.socket, new HeadersOverflowError()) - } - } - - onUpgrade (head) { - const { upgrade, client, socket, headers, statusCode } = this - - assert(upgrade) - - const request = client[kQueue][client[kRunningIdx]] - assert(request) - - assert(!socket.destroyed) - assert(socket === client[kSocket]) - assert(!this.paused) - assert(request.upgrade || request.method === 'CONNECT') - - this.statusCode = null - this.statusText = '' - this.shouldKeepAlive = null - - assert(this.headers.length % 2 === 0) - this.headers = [] - this.headersSize = 0 - - socket.unshift(head) - - socket[kParser].destroy() - socket[kParser] = null - - socket[kClient] = null - socket[kError] = null - socket - .removeListener('error', onSocketError) - .removeListener('readable', onSocketReadable) - .removeListener('end', onSocketEnd) - .removeListener('close', onSocketClose) - - client[kSocket] = null - client[kQueue][client[kRunningIdx]++] = null - client.emit('disconnect', client[kUrl], [client], new InformationalError('upgrade')) - - try { - request.onUpgrade(statusCode, headers, socket) - } catch (err) { - util.destroy(socket, err) - } - - resume(client) - } - - onHeadersComplete (statusCode, upgrade, shouldKeepAlive) { - const { client, socket, headers, statusText } = this - - /* istanbul ignore next: difficult to make a test case for */ - if (socket.destroyed) { - return -1 - } - - const request = client[kQueue][client[kRunningIdx]] - - /* istanbul ignore next: difficult to make a test case for */ - if (!request) { - return -1 - } - - assert(!this.upgrade) - assert(this.statusCode < 200) - - if (statusCode === 100) { - util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket))) - return -1 - } - - /* this can only happen if server is misbehaving */ - if (upgrade && !request.upgrade) { - util.destroy(socket, new SocketError('bad upgrade', util.getSocketInfo(socket))) - return -1 - } - - assert.strictEqual(this.timeoutType, TIMEOUT_HEADERS) - - this.statusCode = statusCode - this.shouldKeepAlive = ( - shouldKeepAlive || - // Override llhttp value which does not allow keepAlive for HEAD. - (request.method === 'HEAD' && !socket[kReset] && this.connection.toLowerCase() === 'keep-alive') - ) - - if (this.statusCode >= 200) { - const bodyTimeout = request.bodyTimeout != null - ? request.bodyTimeout - : client[kBodyTimeout] - this.setTimeout(bodyTimeout, TIMEOUT_BODY) - } else if (this.timeout) { - // istanbul ignore else: only for jest - if (this.timeout.refresh) { - this.timeout.refresh() - } - } - - if (request.method === 'CONNECT') { - assert(client[kRunning] === 1) - this.upgrade = true - return 2 - } - - if (upgrade) { - assert(client[kRunning] === 1) - this.upgrade = true - return 2 - } - - assert(this.headers.length % 2 === 0) - this.headers = [] - this.headersSize = 0 - - if (this.shouldKeepAlive && client[kPipelining]) { - const keepAliveTimeout = this.keepAlive ? util.parseKeepAliveTimeout(this.keepAlive) : null - - if (keepAliveTimeout != null) { - const timeout = Math.min( - keepAliveTimeout - client[kKeepAliveTimeoutThreshold], - client[kKeepAliveMaxTimeout] - ) - if (timeout <= 0) { - socket[kReset] = true - } else { - client[kKeepAliveTimeoutValue] = timeout - } - } else { - client[kKeepAliveTimeoutValue] = client[kKeepAliveDefaultTimeout] - } - } else { - // Stop more requests from being dispatched. - socket[kReset] = true - } - - let pause - try { - pause = request.onHeaders(statusCode, headers, this.resume, statusText) === false - } catch (err) { - util.destroy(socket, err) - return -1 - } - - if (request.method === 'HEAD') { - return 1 - } - - if (statusCode < 200) { - return 1 - } - - if (socket[kBlocking]) { - socket[kBlocking] = false - resume(client) - } - - return pause ? constants.ERROR.PAUSED : 0 - } - - onBody (buf) { - const { client, socket, statusCode, maxResponseSize } = this - - if (socket.destroyed) { - return -1 - } - - const request = client[kQueue][client[kRunningIdx]] - assert(request) - - assert.strictEqual(this.timeoutType, TIMEOUT_BODY) - if (this.timeout) { - // istanbul ignore else: only for jest - if (this.timeout.refresh) { - this.timeout.refresh() - } - } - - assert(statusCode >= 200) - - if (maxResponseSize > -1 && this.bytesRead + buf.length > maxResponseSize) { - util.destroy(socket, new ResponseExceededMaxSizeError()) - return -1 - } - - this.bytesRead += buf.length - - try { - if (request.onData(buf) === false) { - return constants.ERROR.PAUSED - } - } catch (err) { - util.destroy(socket, err) - return -1 - } - } - - onMessageComplete () { - const { client, socket, statusCode, upgrade, headers, contentLength, bytesRead, shouldKeepAlive } = this - - if (socket.destroyed && (!statusCode || shouldKeepAlive)) { - return -1 - } - - if (upgrade) { - return - } - - const request = client[kQueue][client[kRunningIdx]] - assert(request) - - assert(statusCode >= 100) - - this.statusCode = null - this.statusText = '' - this.bytesRead = 0 - this.contentLength = '' - this.keepAlive = '' - this.connection = '' - - assert(this.headers.length % 2 === 0) - this.headers = [] - this.headersSize = 0 - - if (statusCode < 200) { - return - } - - /* istanbul ignore next: should be handled by llhttp? */ - if (request.method !== 'HEAD' && contentLength && bytesRead !== parseInt(contentLength, 10)) { - util.destroy(socket, new ResponseContentLengthMismatchError()) - return -1 - } - - try { - request.onComplete(headers) - } catch (err) { - errorRequest(client, request, err) - } - - client[kQueue][client[kRunningIdx]++] = null - - if (socket[kWriting]) { - assert.strictEqual(client[kRunning], 0) - // Response completed before request. - util.destroy(socket, new InformationalError('reset')) - return constants.ERROR.PAUSED - } else if (!shouldKeepAlive) { - util.destroy(socket, new InformationalError('reset')) - return constants.ERROR.PAUSED - } else if (socket[kReset] && client[kRunning] === 0) { - // Destroy socket once all requests have completed. - // The request at the tail of the pipeline is the one - // that requested reset and no further requests should - // have been queued since then. - util.destroy(socket, new InformationalError('reset')) - return constants.ERROR.PAUSED - } else if (client[kPipelining] === 1) { - // We must wait a full event loop cycle to reuse this socket to make sure - // that non-spec compliant servers are not closing the connection even if they - // said they won't. - setImmediate(resume, client) - } else { - resume(client) - } - } -} - -function onParserTimeout (parser) { - const { socket, timeoutType, client } = parser - - /* istanbul ignore else */ - if (timeoutType === TIMEOUT_HEADERS) { - if (!socket[kWriting] || socket.writableNeedDrain || client[kRunning] > 1) { - assert(!parser.paused, 'cannot be paused while waiting for headers') - util.destroy(socket, new HeadersTimeoutError()) - } - } else if (timeoutType === TIMEOUT_BODY) { - if (!parser.paused) { - util.destroy(socket, new BodyTimeoutError()) - } - } else if (timeoutType === TIMEOUT_IDLE) { - assert(client[kRunning] === 0 && client[kKeepAliveTimeoutValue]) - util.destroy(socket, new InformationalError('socket idle timeout')) - } -} - -function onSocketReadable () { - const { [kParser]: parser } = this - if (parser) { - parser.readMore() - } -} - -function onSocketError (err) { - const { [kClient]: client, [kParser]: parser } = this - - assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID') - - if (client[kHTTPConnVersion] !== 'h2') { - // On Mac OS, we get an ECONNRESET even if there is a full body to be forwarded - // to the user. - if (err.code === 'ECONNRESET' && parser.statusCode && !parser.shouldKeepAlive) { - // We treat all incoming data so for as a valid response. - parser.onMessageComplete() - return - } - } - - this[kError] = err - - onError(this[kClient], err) -} - -function onError (client, err) { - if ( - client[kRunning] === 0 && - err.code !== 'UND_ERR_INFO' && - err.code !== 'UND_ERR_SOCKET' - ) { - // Error is not caused by running request and not a recoverable - // socket error. - - assert(client[kPendingIdx] === client[kRunningIdx]) - - const requests = client[kQueue].splice(client[kRunningIdx]) - for (let i = 0; i < requests.length; i++) { - const request = requests[i] - errorRequest(client, request, err) - } - assert(client[kSize] === 0) - } -} - -function onSocketEnd () { - const { [kParser]: parser, [kClient]: client } = this - - if (client[kHTTPConnVersion] !== 'h2') { - if (parser.statusCode && !parser.shouldKeepAlive) { - // We treat all incoming data so far as a valid response. - parser.onMessageComplete() - return - } - } - - util.destroy(this, new SocketError('other side closed', util.getSocketInfo(this))) -} - -function onSocketClose () { - const { [kClient]: client, [kParser]: parser } = this - - if (client[kHTTPConnVersion] === 'h1' && parser) { - if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - // We treat all incoming data so far as a valid response. - parser.onMessageComplete() - } - - this[kParser].destroy() - this[kParser] = null - } - - const err = this[kError] || new SocketError('closed', util.getSocketInfo(this)) - - client[kSocket] = null - - if (client.destroyed) { - assert(client[kPending] === 0) - - // Fail entire queue. - const requests = client[kQueue].splice(client[kRunningIdx]) - for (let i = 0; i < requests.length; i++) { - const request = requests[i] - errorRequest(client, request, err) - } - } else if (client[kRunning] > 0 && err.code !== 'UND_ERR_INFO') { - // Fail head of pipeline. - const request = client[kQueue][client[kRunningIdx]] - client[kQueue][client[kRunningIdx]++] = null - - errorRequest(client, request, err) - } - - client[kPendingIdx] = client[kRunningIdx] - - assert(client[kRunning] === 0) - - client.emit('disconnect', client[kUrl], [client], err) - - resume(client) -} - -async function connect (client) { - assert(!client[kConnecting]) - assert(!client[kSocket]) - - let { host, hostname, protocol, port } = client[kUrl] - - // Resolve ipv6 - if (hostname[0] === '[') { - const idx = hostname.indexOf(']') - - assert(idx !== -1) - const ip = hostname.substr(1, idx - 1) - - assert(net.isIP(ip)) - hostname = ip - } - - client[kConnecting] = true - - if (channels.beforeConnect.hasSubscribers) { - channels.beforeConnect.publish({ - connectParams: { - host, - hostname, - protocol, - port, - servername: client[kServerName], - localAddress: client[kLocalAddress] - }, - connector: client[kConnector] - }) - } - - try { - const socket = await new Promise((resolve, reject) => { - client[kConnector]({ - host, - hostname, - protocol, - port, - servername: client[kServerName], - localAddress: client[kLocalAddress] - }, (err, socket) => { - if (err) { - reject(err) - } else { - resolve(socket) - } - }) - }) - - if (client.destroyed) { - util.destroy(socket.on('error', () => {}), new ClientDestroyedError()) - return - } - - client[kConnecting] = false - - assert(socket) - - const isH2 = socket.alpnProtocol === 'h2' - if (isH2) { - if (!h2ExperimentalWarned) { - h2ExperimentalWarned = true - process.emitWarning('H2 support is experimental, expect them to change at any time.', { - code: 'UNDICI-H2' - }) - } - - const session = http2.connect(client[kUrl], { - createConnection: () => socket, - peerMaxConcurrentStreams: client[kHTTP2SessionState].maxConcurrentStreams - }) - - client[kHTTPConnVersion] = 'h2' - session[kClient] = client - session[kSocket] = socket - session.on('error', onHttp2SessionError) - session.on('frameError', onHttp2FrameError) - session.on('end', onHttp2SessionEnd) - session.on('goaway', onHTTP2GoAway) - session.on('close', onSocketClose) - session.unref() - - client[kHTTP2Session] = session - socket[kHTTP2Session] = session - } else { - if (!llhttpInstance) { - llhttpInstance = await llhttpPromise - llhttpPromise = null - } - - socket[kNoRef] = false - socket[kWriting] = false - socket[kReset] = false - socket[kBlocking] = false - socket[kParser] = new Parser(client, socket, llhttpInstance) - } - - socket[kCounter] = 0 - socket[kMaxRequests] = client[kMaxRequests] - socket[kClient] = client - socket[kError] = null - - socket - .on('error', onSocketError) - .on('readable', onSocketReadable) - .on('end', onSocketEnd) - .on('close', onSocketClose) - - client[kSocket] = socket - - if (channels.connected.hasSubscribers) { - channels.connected.publish({ - connectParams: { - host, - hostname, - protocol, - port, - servername: client[kServerName], - localAddress: client[kLocalAddress] - }, - connector: client[kConnector], - socket - }) - } - client.emit('connect', client[kUrl], [client]) - } catch (err) { - if (client.destroyed) { - return - } - - client[kConnecting] = false - - if (channels.connectError.hasSubscribers) { - channels.connectError.publish({ - connectParams: { - host, - hostname, - protocol, - port, - servername: client[kServerName], - localAddress: client[kLocalAddress] - }, - connector: client[kConnector], - error: err - }) - } - - if (err.code === 'ERR_TLS_CERT_ALTNAME_INVALID') { - assert(client[kRunning] === 0) - while (client[kPending] > 0 && client[kQueue][client[kPendingIdx]].servername === client[kServerName]) { - const request = client[kQueue][client[kPendingIdx]++] - errorRequest(client, request, err) - } - } else { - onError(client, err) - } - - client.emit('connectionError', client[kUrl], [client], err) - } - - resume(client) -} - -function emitDrain (client) { - client[kNeedDrain] = 0 - client.emit('drain', client[kUrl], [client]) -} - -function resume (client, sync) { - if (client[kResuming] === 2) { - return - } - - client[kResuming] = 2 - - _resume(client, sync) - client[kResuming] = 0 - - if (client[kRunningIdx] > 256) { - client[kQueue].splice(0, client[kRunningIdx]) - client[kPendingIdx] -= client[kRunningIdx] - client[kRunningIdx] = 0 - } -} - -function _resume (client, sync) { - while (true) { - if (client.destroyed) { - assert(client[kPending] === 0) - return - } - - if (client[kClosedResolve] && !client[kSize]) { - client[kClosedResolve]() - client[kClosedResolve] = null - return - } - - const socket = client[kSocket] - - if (socket && !socket.destroyed && socket.alpnProtocol !== 'h2') { - if (client[kSize] === 0) { - if (!socket[kNoRef] && socket.unref) { - socket.unref() - socket[kNoRef] = true - } - } else if (socket[kNoRef] && socket.ref) { - socket.ref() - socket[kNoRef] = false - } - - if (client[kSize] === 0) { - if (socket[kParser].timeoutType !== TIMEOUT_IDLE) { - socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_IDLE) - } - } else if (client[kRunning] > 0 && socket[kParser].statusCode < 200) { - if (socket[kParser].timeoutType !== TIMEOUT_HEADERS) { - const request = client[kQueue][client[kRunningIdx]] - const headersTimeout = request.headersTimeout != null - ? request.headersTimeout - : client[kHeadersTimeout] - socket[kParser].setTimeout(headersTimeout, TIMEOUT_HEADERS) - } - } - } - - if (client[kBusy]) { - client[kNeedDrain] = 2 - } else if (client[kNeedDrain] === 2) { - if (sync) { - client[kNeedDrain] = 1 - process.nextTick(emitDrain, client) - } else { - emitDrain(client) - } - continue - } - - if (client[kPending] === 0) { - return - } - - if (client[kRunning] >= (client[kPipelining] || 1)) { - return - } - - const request = client[kQueue][client[kPendingIdx]] - - if (client[kUrl].protocol === 'https:' && client[kServerName] !== request.servername) { - if (client[kRunning] > 0) { - return - } - - client[kServerName] = request.servername - - if (socket && socket.servername !== request.servername) { - util.destroy(socket, new InformationalError('servername changed')) - return - } - } - - if (client[kConnecting]) { - return - } - - if (!socket && !client[kHTTP2Session]) { - connect(client) - return - } - - if (socket.destroyed || socket[kWriting] || socket[kReset] || socket[kBlocking]) { - return - } - - if (client[kRunning] > 0 && !request.idempotent) { - // Non-idempotent request cannot be retried. - // Ensure that no other requests are inflight and - // could cause failure. - return - } - - if (client[kRunning] > 0 && (request.upgrade || request.method === 'CONNECT')) { - // Don't dispatch an upgrade until all preceding requests have completed. - // A misbehaving server might upgrade the connection before all pipelined - // request has completed. - return - } - - if (client[kRunning] > 0 && util.bodyLength(request.body) !== 0 && - (util.isStream(request.body) || util.isAsyncIterable(request.body))) { - // Request with stream or iterator body can error while other requests - // are inflight and indirectly error those as well. - // Ensure this doesn't happen by waiting for inflight - // to complete before dispatching. - - // Request with stream or iterator body cannot be retried. - // Ensure that no other requests are inflight and - // could cause failure. - return - } - - if (!request.aborted && write(client, request)) { - client[kPendingIdx]++ - } else { - client[kQueue].splice(client[kPendingIdx], 1) - } - } -} - -// https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2 -function shouldSendContentLength (method) { - return method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && method !== 'TRACE' && method !== 'CONNECT' -} - -function write (client, request) { - if (client[kHTTPConnVersion] === 'h2') { - writeH2(client, client[kHTTP2Session], request) - return - } - - const { body, method, path, host, upgrade, headers, blocking, reset } = request - - // https://tools.ietf.org/html/rfc7231#section-4.3.1 - // https://tools.ietf.org/html/rfc7231#section-4.3.2 - // https://tools.ietf.org/html/rfc7231#section-4.3.5 - - // Sending a payload body on a request that does not - // expect it can cause undefined behavior on some - // servers and corrupt connection state. Do not - // re-use the connection for further requests. - - const expectsPayload = ( - method === 'PUT' || - method === 'POST' || - method === 'PATCH' - ) - - if (body && typeof body.read === 'function') { - // Try to read EOF in order to get length. - body.read(0) - } - - const bodyLength = util.bodyLength(body) - - let contentLength = bodyLength - - if (contentLength === null) { - contentLength = request.contentLength - } - - if (contentLength === 0 && !expectsPayload) { - // https://tools.ietf.org/html/rfc7230#section-3.3.2 - // A user agent SHOULD NOT send a Content-Length header field when - // the request message does not contain a payload body and the method - // semantics do not anticipate such a body. - - contentLength = null - } - - // https://github.com/nodejs/undici/issues/2046 - // A user agent may send a Content-Length header with 0 value, this should be allowed. - if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength !== null && request.contentLength !== contentLength) { - if (client[kStrictContentLength]) { - errorRequest(client, request, new RequestContentLengthMismatchError()) - return false - } - - process.emitWarning(new RequestContentLengthMismatchError()) - } - - const socket = client[kSocket] - - try { - request.onConnect((err) => { - if (request.aborted || request.completed) { - return - } - - errorRequest(client, request, err || new RequestAbortedError()) - - util.destroy(socket, new InformationalError('aborted')) - }) - } catch (err) { - errorRequest(client, request, err) - } - - if (request.aborted) { - return false - } - - if (method === 'HEAD') { - // https://github.com/mcollina/undici/issues/258 - // Close after a HEAD request to interop with misbehaving servers - // that may send a body in the response. - - socket[kReset] = true - } - - if (upgrade || method === 'CONNECT') { - // On CONNECT or upgrade, block pipeline from dispatching further - // requests on this connection. - - socket[kReset] = true - } - - if (reset != null) { - socket[kReset] = reset - } - - if (client[kMaxRequests] && socket[kCounter]++ >= client[kMaxRequests]) { - socket[kReset] = true - } - - if (blocking) { - socket[kBlocking] = true - } - - let header = `${method} ${path} HTTP/1.1\r\n` - - if (typeof host === 'string') { - header += `host: ${host}\r\n` - } else { - header += client[kHostHeader] - } - - if (upgrade) { - header += `connection: upgrade\r\nupgrade: ${upgrade}\r\n` - } else if (client[kPipelining] && !socket[kReset]) { - header += 'connection: keep-alive\r\n' - } else { - header += 'connection: close\r\n' - } - - if (headers) { - header += headers - } - - if (channels.sendHeaders.hasSubscribers) { - channels.sendHeaders.publish({ request, headers: header, socket }) - } - - /* istanbul ignore else: assertion */ - if (!body || bodyLength === 0) { - if (contentLength === 0) { - socket.write(`${header}content-length: 0\r\n\r\n`, 'latin1') - } else { - assert(contentLength === null, 'no body must not have content length') - socket.write(`${header}\r\n`, 'latin1') - } - request.onRequestSent() - } else if (util.isBuffer(body)) { - assert(contentLength === body.byteLength, 'buffer body must have content length') - - socket.cork() - socket.write(`${header}content-length: ${contentLength}\r\n\r\n`, 'latin1') - socket.write(body) - socket.uncork() - request.onBodySent(body) - request.onRequestSent() - if (!expectsPayload) { - socket[kReset] = true - } - } else if (util.isBlobLike(body)) { - if (typeof body.stream === 'function') { - writeIterable({ body: body.stream(), client, request, socket, contentLength, header, expectsPayload }) - } else { - writeBlob({ body, client, request, socket, contentLength, header, expectsPayload }) - } - } else if (util.isStream(body)) { - writeStream({ body, client, request, socket, contentLength, header, expectsPayload }) - } else if (util.isIterable(body)) { - writeIterable({ body, client, request, socket, contentLength, header, expectsPayload }) - } else { - assert(false) - } - - return true -} - -function writeH2 (client, session, request) { - const { body, method, path, host, upgrade, expectContinue, signal, headers: reqHeaders } = request - - let headers - if (typeof reqHeaders === 'string') headers = Request[kHTTP2CopyHeaders](reqHeaders.trim()) - else headers = reqHeaders - - if (upgrade) { - errorRequest(client, request, new Error('Upgrade not supported for H2')) - return false - } - - try { - // TODO(HTTP/2): Should we call onConnect immediately or on stream ready event? - request.onConnect((err) => { - if (request.aborted || request.completed) { - return - } - - errorRequest(client, request, err || new RequestAbortedError()) - }) - } catch (err) { - errorRequest(client, request, err) - } - - if (request.aborted) { - return false - } - - let stream - const h2State = client[kHTTP2SessionState] - - headers[HTTP2_HEADER_AUTHORITY] = host || client[kHost] - headers[HTTP2_HEADER_METHOD] = method - - if (method === 'CONNECT') { - session.ref() - // we are already connected, streams are pending, first request - // will create a new stream. We trigger a request to create the stream and wait until - // `ready` event is triggered - // We disabled endStream to allow the user to write to the stream - stream = session.request(headers, { endStream: false, signal }) - - if (stream.id && !stream.pending) { - request.onUpgrade(null, null, stream) - ++h2State.openStreams - } else { - stream.once('ready', () => { - request.onUpgrade(null, null, stream) - ++h2State.openStreams - }) - } - - stream.once('close', () => { - h2State.openStreams -= 1 - // TODO(HTTP/2): unref only if current streams count is 0 - if (h2State.openStreams === 0) session.unref() - }) - - return true - } - - // https://tools.ietf.org/html/rfc7540#section-8.3 - // :path and :scheme headers must be omited when sending CONNECT - - headers[HTTP2_HEADER_PATH] = path - headers[HTTP2_HEADER_SCHEME] = 'https' - - // https://tools.ietf.org/html/rfc7231#section-4.3.1 - // https://tools.ietf.org/html/rfc7231#section-4.3.2 - // https://tools.ietf.org/html/rfc7231#section-4.3.5 - - // Sending a payload body on a request that does not - // expect it can cause undefined behavior on some - // servers and corrupt connection state. Do not - // re-use the connection for further requests. - - const expectsPayload = ( - method === 'PUT' || - method === 'POST' || - method === 'PATCH' - ) - - if (body && typeof body.read === 'function') { - // Try to read EOF in order to get length. - body.read(0) - } - - let contentLength = util.bodyLength(body) - - if (contentLength == null) { - contentLength = request.contentLength - } - - if (contentLength === 0 || !expectsPayload) { - // https://tools.ietf.org/html/rfc7230#section-3.3.2 - // A user agent SHOULD NOT send a Content-Length header field when - // the request message does not contain a payload body and the method - // semantics do not anticipate such a body. - - contentLength = null - } - - // https://github.com/nodejs/undici/issues/2046 - // A user agent may send a Content-Length header with 0 value, this should be allowed. - if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength != null && request.contentLength !== contentLength) { - if (client[kStrictContentLength]) { - errorRequest(client, request, new RequestContentLengthMismatchError()) - return false - } - - process.emitWarning(new RequestContentLengthMismatchError()) - } - - if (contentLength != null) { - assert(body, 'no body must not have content length') - headers[HTTP2_HEADER_CONTENT_LENGTH] = `${contentLength}` - } - - session.ref() - - const shouldEndStream = method === 'GET' || method === 'HEAD' - if (expectContinue) { - headers[HTTP2_HEADER_EXPECT] = '100-continue' - /** - * @type {import('node:http2').ClientHttp2Stream} - */ - stream = session.request(headers, { endStream: shouldEndStream, signal }) - - stream.once('continue', writeBodyH2) - } else { - /** @type {import('node:http2').ClientHttp2Stream} */ - stream = session.request(headers, { - endStream: shouldEndStream, - signal - }) - writeBodyH2() - } - - // Increment counter as we have new several streams open - ++h2State.openStreams - - stream.once('response', headers => { - if (request.onHeaders(Number(headers[HTTP2_HEADER_STATUS]), headers, stream.resume.bind(stream), '') === false) { - stream.pause() - } - }) - - stream.once('end', () => { - request.onComplete([]) - }) - - stream.on('data', (chunk) => { - if (request.onData(chunk) === false) stream.pause() - }) - - stream.once('close', () => { - h2State.openStreams -= 1 - // TODO(HTTP/2): unref only if current streams count is 0 - if (h2State.openStreams === 0) session.unref() - }) - - stream.once('error', function (err) { - if (client[kHTTP2Session] && !client[kHTTP2Session].destroyed && !this.closed && !this.destroyed) { - h2State.streams -= 1 - util.destroy(stream, err) - } - }) - - stream.once('frameError', (type, code) => { - const err = new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`) - errorRequest(client, request, err) - - if (client[kHTTP2Session] && !client[kHTTP2Session].destroyed && !this.closed && !this.destroyed) { - h2State.streams -= 1 - util.destroy(stream, err) - } - }) - - // stream.on('aborted', () => { - // // TODO(HTTP/2): Support aborted - // }) - - // stream.on('timeout', () => { - // // TODO(HTTP/2): Support timeout - // }) - - // stream.on('push', headers => { - // // TODO(HTTP/2): Suppor push - // }) - - // stream.on('trailers', headers => { - // // TODO(HTTP/2): Support trailers - // }) - - return true - - function writeBodyH2 () { - /* istanbul ignore else: assertion */ - if (!body) { - request.onRequestSent() - } else if (util.isBuffer(body)) { - assert(contentLength === body.byteLength, 'buffer body must have content length') - stream.cork() - stream.write(body) - stream.uncork() - stream.end() - request.onBodySent(body) - request.onRequestSent() - } else if (util.isBlobLike(body)) { - if (typeof body.stream === 'function') { - writeIterable({ - client, - request, - contentLength, - h2stream: stream, - expectsPayload, - body: body.stream(), - socket: client[kSocket], - header: '' - }) - } else { - writeBlob({ - body, - client, - request, - contentLength, - expectsPayload, - h2stream: stream, - header: '', - socket: client[kSocket] - }) - } - } else if (util.isStream(body)) { - writeStream({ - body, - client, - request, - contentLength, - expectsPayload, - socket: client[kSocket], - h2stream: stream, - header: '' - }) - } else if (util.isIterable(body)) { - writeIterable({ - body, - client, - request, - contentLength, - expectsPayload, - header: '', - h2stream: stream, - socket: client[kSocket] - }) - } else { - assert(false) - } - } -} - -function writeStream ({ h2stream, body, client, request, socket, contentLength, header, expectsPayload }) { - assert(contentLength !== 0 || client[kRunning] === 0, 'stream body cannot be pipelined') - - if (client[kHTTPConnVersion] === 'h2') { - // For HTTP/2, is enough to pipe the stream - const pipe = pipeline( - body, - h2stream, - (err) => { - if (err) { - util.destroy(body, err) - util.destroy(h2stream, err) - } else { - request.onRequestSent() - } - } - ) - - pipe.on('data', onPipeData) - pipe.once('end', () => { - pipe.removeListener('data', onPipeData) - util.destroy(pipe) - }) - - function onPipeData (chunk) { - request.onBodySent(chunk) - } - - return - } - - let finished = false - - const writer = new AsyncWriter({ socket, request, contentLength, client, expectsPayload, header }) - - const onData = function (chunk) { - if (finished) { - return - } - - try { - if (!writer.write(chunk) && this.pause) { - this.pause() - } - } catch (err) { - util.destroy(this, err) - } - } - const onDrain = function () { - if (finished) { - return - } - - if (body.resume) { - body.resume() - } - } - const onAbort = function () { - onFinished(new RequestAbortedError()) - } - const onFinished = function (err) { - if (finished) { - return - } - - finished = true - - assert(socket.destroyed || (socket[kWriting] && client[kRunning] <= 1)) - - socket - .off('drain', onDrain) - .off('error', onFinished) - - body - .removeListener('data', onData) - .removeListener('end', onFinished) - .removeListener('error', onFinished) - .removeListener('close', onAbort) - - if (!err) { - try { - writer.end() - } catch (er) { - err = er - } - } - - writer.destroy(err) - - if (err && (err.code !== 'UND_ERR_INFO' || err.message !== 'reset')) { - util.destroy(body, err) - } else { - util.destroy(body) - } - } - - body - .on('data', onData) - .on('end', onFinished) - .on('error', onFinished) - .on('close', onAbort) - - if (body.resume) { - body.resume() - } - - socket - .on('drain', onDrain) - .on('error', onFinished) -} - -async function writeBlob ({ h2stream, body, client, request, socket, contentLength, header, expectsPayload }) { - assert(contentLength === body.size, 'blob body must have content length') - - const isH2 = client[kHTTPConnVersion] === 'h2' - try { - if (contentLength != null && contentLength !== body.size) { - throw new RequestContentLengthMismatchError() - } - - const buffer = Buffer.from(await body.arrayBuffer()) - - if (isH2) { - h2stream.cork() - h2stream.write(buffer) - h2stream.uncork() - } else { - socket.cork() - socket.write(`${header}content-length: ${contentLength}\r\n\r\n`, 'latin1') - socket.write(buffer) - socket.uncork() - } - - request.onBodySent(buffer) - request.onRequestSent() - - if (!expectsPayload) { - socket[kReset] = true - } - - resume(client) - } catch (err) { - util.destroy(isH2 ? h2stream : socket, err) - } -} - -async function writeIterable ({ h2stream, body, client, request, socket, contentLength, header, expectsPayload }) { - assert(contentLength !== 0 || client[kRunning] === 0, 'iterator body cannot be pipelined') - - let callback = null - function onDrain () { - if (callback) { - const cb = callback - callback = null - cb() - } - } - - const waitForDrain = () => new Promise((resolve, reject) => { - assert(callback === null) - - if (socket[kError]) { - reject(socket[kError]) - } else { - callback = resolve - } - }) - - if (client[kHTTPConnVersion] === 'h2') { - h2stream - .on('close', onDrain) - .on('drain', onDrain) - - try { - // It's up to the user to somehow abort the async iterable. - for await (const chunk of body) { - if (socket[kError]) { - throw socket[kError] - } - - const res = h2stream.write(chunk) - request.onBodySent(chunk) - if (!res) { - await waitForDrain() - } - } - } catch (err) { - h2stream.destroy(err) - } finally { - request.onRequestSent() - h2stream.end() - h2stream - .off('close', onDrain) - .off('drain', onDrain) - } - - return - } - - socket - .on('close', onDrain) - .on('drain', onDrain) - - const writer = new AsyncWriter({ socket, request, contentLength, client, expectsPayload, header }) - try { - // It's up to the user to somehow abort the async iterable. - for await (const chunk of body) { - if (socket[kError]) { - throw socket[kError] - } - - if (!writer.write(chunk)) { - await waitForDrain() - } - } - - writer.end() - } catch (err) { - writer.destroy(err) - } finally { - socket - .off('close', onDrain) - .off('drain', onDrain) - } -} - -class AsyncWriter { - constructor ({ socket, request, contentLength, client, expectsPayload, header }) { - this.socket = socket - this.request = request - this.contentLength = contentLength - this.client = client - this.bytesWritten = 0 - this.expectsPayload = expectsPayload - this.header = header - - socket[kWriting] = true - } - - write (chunk) { - const { socket, request, contentLength, client, bytesWritten, expectsPayload, header } = this - - if (socket[kError]) { - throw socket[kError] - } - - if (socket.destroyed) { - return false - } - - const len = Buffer.byteLength(chunk) - if (!len) { - return true - } - - // We should defer writing chunks. - if (contentLength !== null && bytesWritten + len > contentLength) { - if (client[kStrictContentLength]) { - throw new RequestContentLengthMismatchError() - } - - process.emitWarning(new RequestContentLengthMismatchError()) - } - - socket.cork() - - if (bytesWritten === 0) { - if (!expectsPayload) { - socket[kReset] = true - } - - if (contentLength === null) { - socket.write(`${header}transfer-encoding: chunked\r\n`, 'latin1') - } else { - socket.write(`${header}content-length: ${contentLength}\r\n\r\n`, 'latin1') - } - } - - if (contentLength === null) { - socket.write(`\r\n${len.toString(16)}\r\n`, 'latin1') - } - - this.bytesWritten += len - - const ret = socket.write(chunk) - - socket.uncork() - - request.onBodySent(chunk) - - if (!ret) { - if (socket[kParser].timeout && socket[kParser].timeoutType === TIMEOUT_HEADERS) { - // istanbul ignore else: only for jest - if (socket[kParser].timeout.refresh) { - socket[kParser].timeout.refresh() - } - } - } - - return ret - } - - end () { - const { socket, contentLength, client, bytesWritten, expectsPayload, header, request } = this - request.onRequestSent() - - socket[kWriting] = false - - if (socket[kError]) { - throw socket[kError] - } - - if (socket.destroyed) { - return - } - - if (bytesWritten === 0) { - if (expectsPayload) { - // https://tools.ietf.org/html/rfc7230#section-3.3.2 - // A user agent SHOULD send a Content-Length in a request message when - // no Transfer-Encoding is sent and the request method defines a meaning - // for an enclosed payload body. - - socket.write(`${header}content-length: 0\r\n\r\n`, 'latin1') - } else { - socket.write(`${header}\r\n`, 'latin1') - } - } else if (contentLength === null) { - socket.write('\r\n0\r\n\r\n', 'latin1') - } - - if (contentLength !== null && bytesWritten !== contentLength) { - if (client[kStrictContentLength]) { - throw new RequestContentLengthMismatchError() - } else { - process.emitWarning(new RequestContentLengthMismatchError()) - } - } - - if (socket[kParser].timeout && socket[kParser].timeoutType === TIMEOUT_HEADERS) { - // istanbul ignore else: only for jest - if (socket[kParser].timeout.refresh) { - socket[kParser].timeout.refresh() - } - } - - resume(client) - } - - destroy (err) { - const { socket, client } = this - - socket[kWriting] = false - - if (err) { - assert(client[kRunning] <= 1, 'pipeline should only contain this request') - util.destroy(socket, err) - } - } -} - -function errorRequest (client, request, err) { - try { - request.onError(err) - assert(request.aborted) - } catch (err) { - client.emit('error', err) - } -} - -module.exports = Client - - -/***/ }), - -/***/ 7905: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -/* istanbul ignore file: only for Node 12 */ - -const { kConnected, kSize } = __nccwpck_require__(1439) - -class CompatWeakRef { - constructor (value) { - this.value = value - } - - deref () { - return this.value[kConnected] === 0 && this.value[kSize] === 0 - ? undefined - : this.value - } -} - -class CompatFinalizer { - constructor (finalizer) { - this.finalizer = finalizer - } - - register (dispatcher, key) { - if (dispatcher.on) { - dispatcher.on('disconnect', () => { - if (dispatcher[kConnected] === 0 && dispatcher[kSize] === 0) { - this.finalizer(key) - } - }) - } - } -} - -module.exports = function () { - // FIXME: remove workaround when the Node bug is fixed - // https://github.com/nodejs/node/issues/49344#issuecomment-1741776308 - if (process.env.NODE_V8_COVERAGE) { - return { - WeakRef: CompatWeakRef, - FinalizationRegistry: CompatFinalizer - } - } - return { - WeakRef: global.WeakRef || CompatWeakRef, - FinalizationRegistry: global.FinalizationRegistry || CompatFinalizer - } -} - - -/***/ }), - -/***/ 8709: -/***/ ((module) => { - -"use strict"; - - -// https://wicg.github.io/cookie-store/#cookie-maximum-attribute-value-size -const maxAttributeValueSize = 1024 - -// https://wicg.github.io/cookie-store/#cookie-maximum-name-value-pair-size -const maxNameValuePairSize = 4096 - -module.exports = { - maxAttributeValueSize, - maxNameValuePairSize -} - - -/***/ }), - -/***/ 30: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { parseSetCookie } = __nccwpck_require__(1915) -const { stringify, getHeadersList } = __nccwpck_require__(7318) -const { webidl } = __nccwpck_require__(5337) -const { Headers } = __nccwpck_require__(7967) - -/** - * @typedef {Object} Cookie - * @property {string} name - * @property {string} value - * @property {Date|number|undefined} expires - * @property {number|undefined} maxAge - * @property {string|undefined} domain - * @property {string|undefined} path - * @property {boolean|undefined} secure - * @property {boolean|undefined} httpOnly - * @property {'Strict'|'Lax'|'None'} sameSite - * @property {string[]} unparsed - */ - -/** - * @param {Headers} headers - * @returns {Record<string, string>} - */ -function getCookies (headers) { - webidl.argumentLengthCheck(arguments, 1, { header: 'getCookies' }) - - webidl.brandCheck(headers, Headers, { strict: false }) - - const cookie = headers.get('cookie') - const out = {} - - if (!cookie) { - return out - } - - for (const piece of cookie.split(';')) { - const [name, ...value] = piece.split('=') - - out[name.trim()] = value.join('=') - } - - return out -} - -/** - * @param {Headers} headers - * @param {string} name - * @param {{ path?: string, domain?: string }|undefined} attributes - * @returns {void} - */ -function deleteCookie (headers, name, attributes) { - webidl.argumentLengthCheck(arguments, 2, { header: 'deleteCookie' }) - - webidl.brandCheck(headers, Headers, { strict: false }) - - name = webidl.converters.DOMString(name) - attributes = webidl.converters.DeleteCookieAttributes(attributes) - - // Matches behavior of - // https://github.com/denoland/deno_std/blob/63827b16330b82489a04614027c33b7904e08be5/http/cookie.ts#L278 - setCookie(headers, { - name, - value: '', - expires: new Date(0), - ...attributes - }) -} - -/** - * @param {Headers} headers - * @returns {Cookie[]} - */ -function getSetCookies (headers) { - webidl.argumentLengthCheck(arguments, 1, { header: 'getSetCookies' }) - - webidl.brandCheck(headers, Headers, { strict: false }) - - const cookies = getHeadersList(headers).cookies - - if (!cookies) { - return [] - } - - // In older versions of undici, cookies is a list of name:value. - return cookies.map((pair) => parseSetCookie(Array.isArray(pair) ? pair[1] : pair)) -} - -/** - * @param {Headers} headers - * @param {Cookie} cookie - * @returns {void} - */ -function setCookie (headers, cookie) { - webidl.argumentLengthCheck(arguments, 2, { header: 'setCookie' }) - - webidl.brandCheck(headers, Headers, { strict: false }) - - cookie = webidl.converters.Cookie(cookie) - - const str = stringify(cookie) - - if (str) { - headers.append('Set-Cookie', stringify(cookie)) - } -} - -webidl.converters.DeleteCookieAttributes = webidl.dictionaryConverter([ - { - converter: webidl.nullableConverter(webidl.converters.DOMString), - key: 'path', - defaultValue: null - }, - { - converter: webidl.nullableConverter(webidl.converters.DOMString), - key: 'domain', - defaultValue: null - } -]) - -webidl.converters.Cookie = webidl.dictionaryConverter([ - { - converter: webidl.converters.DOMString, - key: 'name' - }, - { - converter: webidl.converters.DOMString, - key: 'value' - }, - { - converter: webidl.nullableConverter((value) => { - if (typeof value === 'number') { - return webidl.converters['unsigned long long'](value) - } - - return new Date(value) - }), - key: 'expires', - defaultValue: null - }, - { - converter: webidl.nullableConverter(webidl.converters['long long']), - key: 'maxAge', - defaultValue: null - }, - { - converter: webidl.nullableConverter(webidl.converters.DOMString), - key: 'domain', - defaultValue: null - }, - { - converter: webidl.nullableConverter(webidl.converters.DOMString), - key: 'path', - defaultValue: null - }, - { - converter: webidl.nullableConverter(webidl.converters.boolean), - key: 'secure', - defaultValue: null - }, - { - converter: webidl.nullableConverter(webidl.converters.boolean), - key: 'httpOnly', - defaultValue: null - }, - { - converter: webidl.converters.USVString, - key: 'sameSite', - allowedValues: ['Strict', 'Lax', 'None'] - }, - { - converter: webidl.sequenceConverter(webidl.converters.DOMString), - key: 'unparsed', - defaultValue: [] - } -]) - -module.exports = { - getCookies, - deleteCookie, - getSetCookies, - setCookie -} - - -/***/ }), - -/***/ 1915: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { maxNameValuePairSize, maxAttributeValueSize } = __nccwpck_require__(8709) -const { isCTLExcludingHtab } = __nccwpck_require__(7318) -const { collectASequenceOfCodePointsFast } = __nccwpck_require__(6822) -const assert = __nccwpck_require__(9491) - -/** - * @description Parses the field-value attributes of a set-cookie header string. - * @see https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4 - * @param {string} header - * @returns if the header is invalid, null will be returned - */ -function parseSetCookie (header) { - // 1. If the set-cookie-string contains a %x00-08 / %x0A-1F / %x7F - // character (CTL characters excluding HTAB): Abort these steps and - // ignore the set-cookie-string entirely. - if (isCTLExcludingHtab(header)) { - return null - } - - let nameValuePair = '' - let unparsedAttributes = '' - let name = '' - let value = '' - - // 2. If the set-cookie-string contains a %x3B (";") character: - if (header.includes(';')) { - // 1. The name-value-pair string consists of the characters up to, - // but not including, the first %x3B (";"), and the unparsed- - // attributes consist of the remainder of the set-cookie-string - // (including the %x3B (";") in question). - const position = { position: 0 } - - nameValuePair = collectASequenceOfCodePointsFast(';', header, position) - unparsedAttributes = header.slice(position.position) - } else { - // Otherwise: - - // 1. The name-value-pair string consists of all the characters - // contained in the set-cookie-string, and the unparsed- - // attributes is the empty string. - nameValuePair = header - } - - // 3. If the name-value-pair string lacks a %x3D ("=") character, then - // the name string is empty, and the value string is the value of - // name-value-pair. - if (!nameValuePair.includes('=')) { - value = nameValuePair - } else { - // Otherwise, the name string consists of the characters up to, but - // not including, the first %x3D ("=") character, and the (possibly - // empty) value string consists of the characters after the first - // %x3D ("=") character. - const position = { position: 0 } - name = collectASequenceOfCodePointsFast( - '=', - nameValuePair, - position - ) - value = nameValuePair.slice(position.position + 1) - } - - // 4. Remove any leading or trailing WSP characters from the name - // string and the value string. - name = name.trim() - value = value.trim() - - // 5. If the sum of the lengths of the name string and the value string - // is more than 4096 octets, abort these steps and ignore the set- - // cookie-string entirely. - if (name.length + value.length > maxNameValuePairSize) { - return null - } - - // 6. The cookie-name is the name string, and the cookie-value is the - // value string. - return { - name, value, ...parseUnparsedAttributes(unparsedAttributes) - } -} - -/** - * Parses the remaining attributes of a set-cookie header - * @see https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4 - * @param {string} unparsedAttributes - * @param {[Object.<string, unknown>]={}} cookieAttributeList - */ -function parseUnparsedAttributes (unparsedAttributes, cookieAttributeList = {}) { - // 1. If the unparsed-attributes string is empty, skip the rest of - // these steps. - if (unparsedAttributes.length === 0) { - return cookieAttributeList - } - - // 2. Discard the first character of the unparsed-attributes (which - // will be a %x3B (";") character). - assert(unparsedAttributes[0] === ';') - unparsedAttributes = unparsedAttributes.slice(1) - - let cookieAv = '' - - // 3. If the remaining unparsed-attributes contains a %x3B (";") - // character: - if (unparsedAttributes.includes(';')) { - // 1. Consume the characters of the unparsed-attributes up to, but - // not including, the first %x3B (";") character. - cookieAv = collectASequenceOfCodePointsFast( - ';', - unparsedAttributes, - { position: 0 } - ) - unparsedAttributes = unparsedAttributes.slice(cookieAv.length) - } else { - // Otherwise: - - // 1. Consume the remainder of the unparsed-attributes. - cookieAv = unparsedAttributes - unparsedAttributes = '' - } - - // Let the cookie-av string be the characters consumed in this step. - - let attributeName = '' - let attributeValue = '' - - // 4. If the cookie-av string contains a %x3D ("=") character: - if (cookieAv.includes('=')) { - // 1. The (possibly empty) attribute-name string consists of the - // characters up to, but not including, the first %x3D ("=") - // character, and the (possibly empty) attribute-value string - // consists of the characters after the first %x3D ("=") - // character. - const position = { position: 0 } - - attributeName = collectASequenceOfCodePointsFast( - '=', - cookieAv, - position - ) - attributeValue = cookieAv.slice(position.position + 1) - } else { - // Otherwise: - - // 1. The attribute-name string consists of the entire cookie-av - // string, and the attribute-value string is empty. - attributeName = cookieAv - } - - // 5. Remove any leading or trailing WSP characters from the attribute- - // name string and the attribute-value string. - attributeName = attributeName.trim() - attributeValue = attributeValue.trim() - - // 6. If the attribute-value is longer than 1024 octets, ignore the - // cookie-av string and return to Step 1 of this algorithm. - if (attributeValue.length > maxAttributeValueSize) { - return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList) - } - - // 7. Process the attribute-name and attribute-value according to the - // requirements in the following subsections. (Notice that - // attributes with unrecognized attribute-names are ignored.) - const attributeNameLowercase = attributeName.toLowerCase() - - // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.1 - // If the attribute-name case-insensitively matches the string - // "Expires", the user agent MUST process the cookie-av as follows. - if (attributeNameLowercase === 'expires') { - // 1. Let the expiry-time be the result of parsing the attribute-value - // as cookie-date (see Section 5.1.1). - const expiryTime = new Date(attributeValue) - - // 2. If the attribute-value failed to parse as a cookie date, ignore - // the cookie-av. - - cookieAttributeList.expires = expiryTime - } else if (attributeNameLowercase === 'max-age') { - // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.2 - // If the attribute-name case-insensitively matches the string "Max- - // Age", the user agent MUST process the cookie-av as follows. - - // 1. If the first character of the attribute-value is not a DIGIT or a - // "-" character, ignore the cookie-av. - const charCode = attributeValue.charCodeAt(0) - - if ((charCode < 48 || charCode > 57) && attributeValue[0] !== '-') { - return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList) - } - - // 2. If the remainder of attribute-value contains a non-DIGIT - // character, ignore the cookie-av. - if (!/^\d+$/.test(attributeValue)) { - return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList) - } - - // 3. Let delta-seconds be the attribute-value converted to an integer. - const deltaSeconds = Number(attributeValue) - - // 4. Let cookie-age-limit be the maximum age of the cookie (which - // SHOULD be 400 days or less, see Section 4.1.2.2). - - // 5. Set delta-seconds to the smaller of its present value and cookie- - // age-limit. - // deltaSeconds = Math.min(deltaSeconds * 1000, maxExpiresMs) - - // 6. If delta-seconds is less than or equal to zero (0), let expiry- - // time be the earliest representable date and time. Otherwise, let - // the expiry-time be the current date and time plus delta-seconds - // seconds. - // const expiryTime = deltaSeconds <= 0 ? Date.now() : Date.now() + deltaSeconds - - // 7. Append an attribute to the cookie-attribute-list with an - // attribute-name of Max-Age and an attribute-value of expiry-time. - cookieAttributeList.maxAge = deltaSeconds - } else if (attributeNameLowercase === 'domain') { - // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.3 - // If the attribute-name case-insensitively matches the string "Domain", - // the user agent MUST process the cookie-av as follows. - - // 1. Let cookie-domain be the attribute-value. - let cookieDomain = attributeValue - - // 2. If cookie-domain starts with %x2E ("."), let cookie-domain be - // cookie-domain without its leading %x2E ("."). - if (cookieDomain[0] === '.') { - cookieDomain = cookieDomain.slice(1) - } - - // 3. Convert the cookie-domain to lower case. - cookieDomain = cookieDomain.toLowerCase() - - // 4. Append an attribute to the cookie-attribute-list with an - // attribute-name of Domain and an attribute-value of cookie-domain. - cookieAttributeList.domain = cookieDomain - } else if (attributeNameLowercase === 'path') { - // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.4 - // If the attribute-name case-insensitively matches the string "Path", - // the user agent MUST process the cookie-av as follows. - - // 1. If the attribute-value is empty or if the first character of the - // attribute-value is not %x2F ("/"): - let cookiePath = '' - if (attributeValue.length === 0 || attributeValue[0] !== '/') { - // 1. Let cookie-path be the default-path. - cookiePath = '/' - } else { - // Otherwise: - - // 1. Let cookie-path be the attribute-value. - cookiePath = attributeValue - } - - // 2. Append an attribute to the cookie-attribute-list with an - // attribute-name of Path and an attribute-value of cookie-path. - cookieAttributeList.path = cookiePath - } else if (attributeNameLowercase === 'secure') { - // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.5 - // If the attribute-name case-insensitively matches the string "Secure", - // the user agent MUST append an attribute to the cookie-attribute-list - // with an attribute-name of Secure and an empty attribute-value. - - cookieAttributeList.secure = true - } else if (attributeNameLowercase === 'httponly') { - // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.6 - // If the attribute-name case-insensitively matches the string - // "HttpOnly", the user agent MUST append an attribute to the cookie- - // attribute-list with an attribute-name of HttpOnly and an empty - // attribute-value. - - cookieAttributeList.httpOnly = true - } else if (attributeNameLowercase === 'samesite') { - // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.7 - // If the attribute-name case-insensitively matches the string - // "SameSite", the user agent MUST process the cookie-av as follows: - - // 1. Let enforcement be "Default". - let enforcement = 'Default' - - const attributeValueLowercase = attributeValue.toLowerCase() - // 2. If cookie-av's attribute-value is a case-insensitive match for - // "None", set enforcement to "None". - if (attributeValueLowercase.includes('none')) { - enforcement = 'None' - } - - // 3. If cookie-av's attribute-value is a case-insensitive match for - // "Strict", set enforcement to "Strict". - if (attributeValueLowercase.includes('strict')) { - enforcement = 'Strict' - } - - // 4. If cookie-av's attribute-value is a case-insensitive match for - // "Lax", set enforcement to "Lax". - if (attributeValueLowercase.includes('lax')) { - enforcement = 'Lax' - } - - // 5. Append an attribute to the cookie-attribute-list with an - // attribute-name of "SameSite" and an attribute-value of - // enforcement. - cookieAttributeList.sameSite = enforcement - } else { - cookieAttributeList.unparsed ??= [] - - cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`) - } - - // 8. Return to Step 1 of this algorithm. - return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList) -} - -module.exports = { - parseSetCookie, - parseUnparsedAttributes -} - - -/***/ }), - -/***/ 7318: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const assert = __nccwpck_require__(9491) -const { kHeadersList } = __nccwpck_require__(1439) - -function isCTLExcludingHtab (value) { - if (value.length === 0) { - return false - } - - for (const char of value) { - const code = char.charCodeAt(0) - - if ( - (code >= 0x00 || code <= 0x08) || - (code >= 0x0A || code <= 0x1F) || - code === 0x7F - ) { - return false - } - } -} - -/** - CHAR = <any US-ASCII character (octets 0 - 127)> - token = 1*<any CHAR except CTLs or separators> - separators = "(" | ")" | "<" | ">" | "@" - | "," | ";" | ":" | "\" | <"> - | "/" | "[" | "]" | "?" | "=" - | "{" | "}" | SP | HT - * @param {string} name - */ -function validateCookieName (name) { - for (const char of name) { - const code = char.charCodeAt(0) - - if ( - (code <= 0x20 || code > 0x7F) || - char === '(' || - char === ')' || - char === '>' || - char === '<' || - char === '@' || - char === ',' || - char === ';' || - char === ':' || - char === '\\' || - char === '"' || - char === '/' || - char === '[' || - char === ']' || - char === '?' || - char === '=' || - char === '{' || - char === '}' - ) { - throw new Error('Invalid cookie name') - } - } -} - -/** - cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) - cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E - ; US-ASCII characters excluding CTLs, - ; whitespace DQUOTE, comma, semicolon, - ; and backslash - * @param {string} value - */ -function validateCookieValue (value) { - for (const char of value) { - const code = char.charCodeAt(0) - - if ( - code < 0x21 || // exclude CTLs (0-31) - code === 0x22 || - code === 0x2C || - code === 0x3B || - code === 0x5C || - code > 0x7E // non-ascii - ) { - throw new Error('Invalid header value') - } - } -} - -/** - * path-value = <any CHAR except CTLs or ";"> - * @param {string} path - */ -function validateCookiePath (path) { - for (const char of path) { - const code = char.charCodeAt(0) - - if (code < 0x21 || char === ';') { - throw new Error('Invalid cookie path') - } - } -} - -/** - * I have no idea why these values aren't allowed to be honest, - * but Deno tests these. - Khafra - * @param {string} domain - */ -function validateCookieDomain (domain) { - if ( - domain.startsWith('-') || - domain.endsWith('.') || - domain.endsWith('-') - ) { - throw new Error('Invalid cookie domain') - } -} - -/** - * @see https://www.rfc-editor.org/rfc/rfc7231#section-7.1.1.1 - * @param {number|Date} date - IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT - ; fixed length/zone/capitalization subset of the format - ; see Section 3.3 of [RFC5322] - - day-name = %x4D.6F.6E ; "Mon", case-sensitive - / %x54.75.65 ; "Tue", case-sensitive - / %x57.65.64 ; "Wed", case-sensitive - / %x54.68.75 ; "Thu", case-sensitive - / %x46.72.69 ; "Fri", case-sensitive - / %x53.61.74 ; "Sat", case-sensitive - / %x53.75.6E ; "Sun", case-sensitive - date1 = day SP month SP year - ; e.g., 02 Jun 1982 - - day = 2DIGIT - month = %x4A.61.6E ; "Jan", case-sensitive - / %x46.65.62 ; "Feb", case-sensitive - / %x4D.61.72 ; "Mar", case-sensitive - / %x41.70.72 ; "Apr", case-sensitive - / %x4D.61.79 ; "May", case-sensitive - / %x4A.75.6E ; "Jun", case-sensitive - / %x4A.75.6C ; "Jul", case-sensitive - / %x41.75.67 ; "Aug", case-sensitive - / %x53.65.70 ; "Sep", case-sensitive - / %x4F.63.74 ; "Oct", case-sensitive - / %x4E.6F.76 ; "Nov", case-sensitive - / %x44.65.63 ; "Dec", case-sensitive - year = 4DIGIT - - GMT = %x47.4D.54 ; "GMT", case-sensitive - - time-of-day = hour ":" minute ":" second - ; 00:00:00 - 23:59:60 (leap second) - - hour = 2DIGIT - minute = 2DIGIT - second = 2DIGIT - */ -function toIMFDate (date) { - if (typeof date === 'number') { - date = new Date(date) - } - - const days = [ - 'Sun', 'Mon', 'Tue', 'Wed', - 'Thu', 'Fri', 'Sat' - ] - - const months = [ - 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' - ] - - const dayName = days[date.getUTCDay()] - const day = date.getUTCDate().toString().padStart(2, '0') - const month = months[date.getUTCMonth()] - const year = date.getUTCFullYear() - const hour = date.getUTCHours().toString().padStart(2, '0') - const minute = date.getUTCMinutes().toString().padStart(2, '0') - const second = date.getUTCSeconds().toString().padStart(2, '0') - - return `${dayName}, ${day} ${month} ${year} ${hour}:${minute}:${second} GMT` -} - -/** - max-age-av = "Max-Age=" non-zero-digit *DIGIT - ; In practice, both expires-av and max-age-av - ; are limited to dates representable by the - ; user agent. - * @param {number} maxAge - */ -function validateCookieMaxAge (maxAge) { - if (maxAge < 0) { - throw new Error('Invalid cookie max-age') - } -} - -/** - * @see https://www.rfc-editor.org/rfc/rfc6265#section-4.1.1 - * @param {import('./index').Cookie} cookie - */ -function stringify (cookie) { - if (cookie.name.length === 0) { - return null - } - - validateCookieName(cookie.name) - validateCookieValue(cookie.value) - - const out = [`${cookie.name}=${cookie.value}`] - - // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-cookie-prefixes-00#section-3.1 - // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-cookie-prefixes-00#section-3.2 - if (cookie.name.startsWith('__Secure-')) { - cookie.secure = true - } - - if (cookie.name.startsWith('__Host-')) { - cookie.secure = true - cookie.domain = null - cookie.path = '/' - } - - if (cookie.secure) { - out.push('Secure') - } - - if (cookie.httpOnly) { - out.push('HttpOnly') - } - - if (typeof cookie.maxAge === 'number') { - validateCookieMaxAge(cookie.maxAge) - out.push(`Max-Age=${cookie.maxAge}`) - } - - if (cookie.domain) { - validateCookieDomain(cookie.domain) - out.push(`Domain=${cookie.domain}`) - } - - if (cookie.path) { - validateCookiePath(cookie.path) - out.push(`Path=${cookie.path}`) - } - - if (cookie.expires && cookie.expires.toString() !== 'Invalid Date') { - out.push(`Expires=${toIMFDate(cookie.expires)}`) - } - - if (cookie.sameSite) { - out.push(`SameSite=${cookie.sameSite}`) - } - - for (const part of cookie.unparsed) { - if (!part.includes('=')) { - throw new Error('Invalid unparsed') - } - - const [key, ...value] = part.split('=') - - out.push(`${key.trim()}=${value.join('=')}`) - } - - return out.join('; ') -} - -let kHeadersListNode - -function getHeadersList (headers) { - if (headers[kHeadersList]) { - return headers[kHeadersList] - } - - if (!kHeadersListNode) { - kHeadersListNode = Object.getOwnPropertySymbols(headers).find( - (symbol) => symbol.description === 'headers list' - ) - - assert(kHeadersListNode, 'Headers cannot be parsed') - } - - const headersList = headers[kHeadersListNode] - assert(headersList) - - return headersList -} - -module.exports = { - isCTLExcludingHtab, - stringify, - getHeadersList -} - - -/***/ }), - -/***/ 3311: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const net = __nccwpck_require__(1808) -const assert = __nccwpck_require__(9491) -const util = __nccwpck_require__(6223) -const { InvalidArgumentError, ConnectTimeoutError } = __nccwpck_require__(5767) - -let tls // include tls conditionally since it is not always available - -// TODO: session re-use does not wait for the first -// connection to resolve the session and might therefore -// resolve the same servername multiple times even when -// re-use is enabled. - -let SessionCache -// FIXME: remove workaround when the Node bug is fixed -// https://github.com/nodejs/node/issues/49344#issuecomment-1741776308 -if (global.FinalizationRegistry && !process.env.NODE_V8_COVERAGE) { - SessionCache = class WeakSessionCache { - constructor (maxCachedSessions) { - this._maxCachedSessions = maxCachedSessions - this._sessionCache = new Map() - this._sessionRegistry = new global.FinalizationRegistry((key) => { - if (this._sessionCache.size < this._maxCachedSessions) { - return - } - - const ref = this._sessionCache.get(key) - if (ref !== undefined && ref.deref() === undefined) { - this._sessionCache.delete(key) - } - }) - } - - get (sessionKey) { - const ref = this._sessionCache.get(sessionKey) - return ref ? ref.deref() : null - } - - set (sessionKey, session) { - if (this._maxCachedSessions === 0) { - return - } - - this._sessionCache.set(sessionKey, new WeakRef(session)) - this._sessionRegistry.register(session, sessionKey) - } - } -} else { - SessionCache = class SimpleSessionCache { - constructor (maxCachedSessions) { - this._maxCachedSessions = maxCachedSessions - this._sessionCache = new Map() - } - - get (sessionKey) { - return this._sessionCache.get(sessionKey) - } - - set (sessionKey, session) { - if (this._maxCachedSessions === 0) { - return - } - - if (this._sessionCache.size >= this._maxCachedSessions) { - // remove the oldest session - const { value: oldestKey } = this._sessionCache.keys().next() - this._sessionCache.delete(oldestKey) - } - - this._sessionCache.set(sessionKey, session) - } - } -} - -function buildConnector ({ allowH2, maxCachedSessions, socketPath, timeout, ...opts }) { - if (maxCachedSessions != null && (!Number.isInteger(maxCachedSessions) || maxCachedSessions < 0)) { - throw new InvalidArgumentError('maxCachedSessions must be a positive integer or zero') - } - - const options = { path: socketPath, ...opts } - const sessionCache = new SessionCache(maxCachedSessions == null ? 100 : maxCachedSessions) - timeout = timeout == null ? 10e3 : timeout - allowH2 = allowH2 != null ? allowH2 : false - return function connect ({ hostname, host, protocol, port, servername, localAddress, httpSocket }, callback) { - let socket - if (protocol === 'https:') { - if (!tls) { - tls = __nccwpck_require__(4404) - } - servername = servername || options.servername || util.getServerName(host) || null - - const sessionKey = servername || hostname - const session = sessionCache.get(sessionKey) || null - - assert(sessionKey) - - socket = tls.connect({ - highWaterMark: 16384, // TLS in node can't have bigger HWM anyway... - ...options, - servername, - session, - localAddress, - // TODO(HTTP/2): Add support for h2c - ALPNProtocols: allowH2 ? ['http/1.1', 'h2'] : ['http/1.1'], - socket: httpSocket, // upgrade socket connection - port: port || 443, - host: hostname - }) - - socket - .on('session', function (session) { - // TODO (fix): Can a session become invalid once established? Don't think so? - sessionCache.set(sessionKey, session) - }) - } else { - assert(!httpSocket, 'httpSocket can only be sent on TLS update') - socket = net.connect({ - highWaterMark: 64 * 1024, // Same as nodejs fs streams. - ...options, - localAddress, - port: port || 80, - host: hostname - }) - } - - // Set TCP keep alive options on the socket here instead of in connect() for the case of assigning the socket - if (options.keepAlive == null || options.keepAlive) { - const keepAliveInitialDelay = options.keepAliveInitialDelay === undefined ? 60e3 : options.keepAliveInitialDelay - socket.setKeepAlive(true, keepAliveInitialDelay) - } - - const cancelTimeout = setupTimeout(() => onConnectTimeout(socket), timeout) - - socket - .setNoDelay(true) - .once(protocol === 'https:' ? 'secureConnect' : 'connect', function () { - cancelTimeout() - - if (callback) { - const cb = callback - callback = null - cb(null, this) - } - }) - .on('error', function (err) { - cancelTimeout() - - if (callback) { - const cb = callback - callback = null - cb(err) - } - }) - - return socket - } -} - -function setupTimeout (onConnectTimeout, timeout) { - if (!timeout) { - return () => {} - } - - let s1 = null - let s2 = null - const timeoutId = setTimeout(() => { - // setImmediate is added to make sure that we priotorise socket error events over timeouts - s1 = setImmediate(() => { - if (process.platform === 'win32') { - // Windows needs an extra setImmediate probably due to implementation differences in the socket logic - s2 = setImmediate(() => onConnectTimeout()) - } else { - onConnectTimeout() - } - }) - }, timeout) - return () => { - clearTimeout(timeoutId) - clearImmediate(s1) - clearImmediate(s2) - } -} - -function onConnectTimeout (socket) { - util.destroy(socket, new ConnectTimeoutError()) -} - -module.exports = buildConnector - - -/***/ }), - -/***/ 5767: -/***/ ((module) => { - -"use strict"; - - -class UndiciError extends Error { - constructor (message) { - super(message) - this.name = 'UndiciError' - this.code = 'UND_ERR' - } -} - -class ConnectTimeoutError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, ConnectTimeoutError) - this.name = 'ConnectTimeoutError' - this.message = message || 'Connect Timeout Error' - this.code = 'UND_ERR_CONNECT_TIMEOUT' - } -} - -class HeadersTimeoutError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, HeadersTimeoutError) - this.name = 'HeadersTimeoutError' - this.message = message || 'Headers Timeout Error' - this.code = 'UND_ERR_HEADERS_TIMEOUT' - } -} - -class HeadersOverflowError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, HeadersOverflowError) - this.name = 'HeadersOverflowError' - this.message = message || 'Headers Overflow Error' - this.code = 'UND_ERR_HEADERS_OVERFLOW' - } -} - -class BodyTimeoutError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, BodyTimeoutError) - this.name = 'BodyTimeoutError' - this.message = message || 'Body Timeout Error' - this.code = 'UND_ERR_BODY_TIMEOUT' - } -} - -class ResponseStatusCodeError extends UndiciError { - constructor (message, statusCode, headers, body) { - super(message) - Error.captureStackTrace(this, ResponseStatusCodeError) - this.name = 'ResponseStatusCodeError' - this.message = message || 'Response Status Code Error' - this.code = 'UND_ERR_RESPONSE_STATUS_CODE' - this.body = body - this.status = statusCode - this.statusCode = statusCode - this.headers = headers - } -} - -class InvalidArgumentError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, InvalidArgumentError) - this.name = 'InvalidArgumentError' - this.message = message || 'Invalid Argument Error' - this.code = 'UND_ERR_INVALID_ARG' - } -} - -class InvalidReturnValueError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, InvalidReturnValueError) - this.name = 'InvalidReturnValueError' - this.message = message || 'Invalid Return Value Error' - this.code = 'UND_ERR_INVALID_RETURN_VALUE' - } -} - -class RequestAbortedError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, RequestAbortedError) - this.name = 'AbortError' - this.message = message || 'Request aborted' - this.code = 'UND_ERR_ABORTED' - } -} - -class InformationalError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, InformationalError) - this.name = 'InformationalError' - this.message = message || 'Request information' - this.code = 'UND_ERR_INFO' - } -} - -class RequestContentLengthMismatchError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, RequestContentLengthMismatchError) - this.name = 'RequestContentLengthMismatchError' - this.message = message || 'Request body length does not match content-length header' - this.code = 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH' - } -} - -class ResponseContentLengthMismatchError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, ResponseContentLengthMismatchError) - this.name = 'ResponseContentLengthMismatchError' - this.message = message || 'Response body length does not match content-length header' - this.code = 'UND_ERR_RES_CONTENT_LENGTH_MISMATCH' - } -} - -class ClientDestroyedError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, ClientDestroyedError) - this.name = 'ClientDestroyedError' - this.message = message || 'The client is destroyed' - this.code = 'UND_ERR_DESTROYED' - } -} - -class ClientClosedError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, ClientClosedError) - this.name = 'ClientClosedError' - this.message = message || 'The client is closed' - this.code = 'UND_ERR_CLOSED' - } -} - -class SocketError extends UndiciError { - constructor (message, socket) { - super(message) - Error.captureStackTrace(this, SocketError) - this.name = 'SocketError' - this.message = message || 'Socket error' - this.code = 'UND_ERR_SOCKET' - this.socket = socket - } -} - -class NotSupportedError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, NotSupportedError) - this.name = 'NotSupportedError' - this.message = message || 'Not supported error' - this.code = 'UND_ERR_NOT_SUPPORTED' - } -} - -class BalancedPoolMissingUpstreamError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, NotSupportedError) - this.name = 'MissingUpstreamError' - this.message = message || 'No upstream has been added to the BalancedPool' - this.code = 'UND_ERR_BPL_MISSING_UPSTREAM' - } -} - -class HTTPParserError extends Error { - constructor (message, code, data) { - super(message) - Error.captureStackTrace(this, HTTPParserError) - this.name = 'HTTPParserError' - this.code = code ? `HPE_${code}` : undefined - this.data = data ? data.toString() : undefined - } -} - -class ResponseExceededMaxSizeError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, ResponseExceededMaxSizeError) - this.name = 'ResponseExceededMaxSizeError' - this.message = message || 'Response content exceeded max size' - this.code = 'UND_ERR_RES_EXCEEDED_MAX_SIZE' - } -} - -module.exports = { - HTTPParserError, - UndiciError, - HeadersTimeoutError, - HeadersOverflowError, - BodyTimeoutError, - RequestContentLengthMismatchError, - ConnectTimeoutError, - ResponseStatusCodeError, - InvalidArgumentError, - InvalidReturnValueError, - RequestAbortedError, - ClientDestroyedError, - ClientClosedError, - InformationalError, - SocketError, - NotSupportedError, - ResponseContentLengthMismatchError, - BalancedPoolMissingUpstreamError, - ResponseExceededMaxSizeError -} - - -/***/ }), - -/***/ 1562: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { - InvalidArgumentError, - NotSupportedError -} = __nccwpck_require__(5767) -const assert = __nccwpck_require__(9491) -const { kHTTP2BuildRequest, kHTTP2CopyHeaders, kHTTP1BuildRequest } = __nccwpck_require__(1439) -const util = __nccwpck_require__(6223) - -// tokenRegExp and headerCharRegex have been lifted from -// https://github.com/nodejs/node/blob/main/lib/_http_common.js - -/** - * Verifies that the given val is a valid HTTP token - * per the rules defined in RFC 7230 - * See https://tools.ietf.org/html/rfc7230#section-3.2.6 - */ -const tokenRegExp = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/ - -/** - * Matches if val contains an invalid field-vchar - * field-value = *( field-content / obs-fold ) - * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] - * field-vchar = VCHAR / obs-text - */ -const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/ - -// Verifies that a given path is valid does not contain control chars \x00 to \x20 -const invalidPathRegex = /[^\u0021-\u00ff]/ - -const kHandler = Symbol('handler') - -const channels = {} - -let extractBody - -try { - const diagnosticsChannel = __nccwpck_require__(7643) - channels.create = diagnosticsChannel.channel('undici:request:create') - channels.bodySent = diagnosticsChannel.channel('undici:request:bodySent') - channels.headers = diagnosticsChannel.channel('undici:request:headers') - channels.trailers = diagnosticsChannel.channel('undici:request:trailers') - channels.error = diagnosticsChannel.channel('undici:request:error') -} catch { - channels.create = { hasSubscribers: false } - channels.bodySent = { hasSubscribers: false } - channels.headers = { hasSubscribers: false } - channels.trailers = { hasSubscribers: false } - channels.error = { hasSubscribers: false } -} - -class Request { - constructor (origin, { - path, - method, - body, - headers, - query, - idempotent, - blocking, - upgrade, - headersTimeout, - bodyTimeout, - reset, - throwOnError, - expectContinue - }, handler) { - if (typeof path !== 'string') { - throw new InvalidArgumentError('path must be a string') - } else if ( - path[0] !== '/' && - !(path.startsWith('http://') || path.startsWith('https://')) && - method !== 'CONNECT' - ) { - throw new InvalidArgumentError('path must be an absolute URL or start with a slash') - } else if (invalidPathRegex.exec(path) !== null) { - throw new InvalidArgumentError('invalid request path') - } - - if (typeof method !== 'string') { - throw new InvalidArgumentError('method must be a string') - } else if (tokenRegExp.exec(method) === null) { - throw new InvalidArgumentError('invalid request method') - } - - if (upgrade && typeof upgrade !== 'string') { - throw new InvalidArgumentError('upgrade must be a string') - } - - if (headersTimeout != null && (!Number.isFinite(headersTimeout) || headersTimeout < 0)) { - throw new InvalidArgumentError('invalid headersTimeout') - } - - if (bodyTimeout != null && (!Number.isFinite(bodyTimeout) || bodyTimeout < 0)) { - throw new InvalidArgumentError('invalid bodyTimeout') - } - - if (reset != null && typeof reset !== 'boolean') { - throw new InvalidArgumentError('invalid reset') - } - - if (expectContinue != null && typeof expectContinue !== 'boolean') { - throw new InvalidArgumentError('invalid expectContinue') - } - - this.headersTimeout = headersTimeout - - this.bodyTimeout = bodyTimeout - - this.throwOnError = throwOnError === true - - this.method = method - - this.abort = null - - if (body == null) { - this.body = null - } else if (util.isStream(body)) { - this.body = body - - const rState = this.body._readableState - if (!rState || !rState.autoDestroy) { - this.endHandler = function autoDestroy () { - util.destroy(this) - } - this.body.on('end', this.endHandler) - } - - this.errorHandler = err => { - if (this.abort) { - this.abort(err) - } else { - this.error = err - } - } - this.body.on('error', this.errorHandler) - } else if (util.isBuffer(body)) { - this.body = body.byteLength ? body : null - } else if (ArrayBuffer.isView(body)) { - this.body = body.buffer.byteLength ? Buffer.from(body.buffer, body.byteOffset, body.byteLength) : null - } else if (body instanceof ArrayBuffer) { - this.body = body.byteLength ? Buffer.from(body) : null - } else if (typeof body === 'string') { - this.body = body.length ? Buffer.from(body) : null - } else if (util.isFormDataLike(body) || util.isIterable(body) || util.isBlobLike(body)) { - this.body = body - } else { - throw new InvalidArgumentError('body must be a string, a Buffer, a Readable stream, an iterable, or an async iterable') - } - - this.completed = false - - this.aborted = false - - this.upgrade = upgrade || null - - this.path = query ? util.buildURL(path, query) : path - - this.origin = origin - - this.idempotent = idempotent == null - ? method === 'HEAD' || method === 'GET' - : idempotent - - this.blocking = blocking == null ? false : blocking - - this.reset = reset == null ? null : reset - - this.host = null - - this.contentLength = null - - this.contentType = null - - this.headers = '' - - // Only for H2 - this.expectContinue = expectContinue != null ? expectContinue : false - - if (Array.isArray(headers)) { - if (headers.length % 2 !== 0) { - throw new InvalidArgumentError('headers array must be even') - } - for (let i = 0; i < headers.length; i += 2) { - processHeader(this, headers[i], headers[i + 1]) - } - } else if (headers && typeof headers === 'object') { - const keys = Object.keys(headers) - for (let i = 0; i < keys.length; i++) { - const key = keys[i] - processHeader(this, key, headers[key]) - } - } else if (headers != null) { - throw new InvalidArgumentError('headers must be an object or an array') - } - - if (util.isFormDataLike(this.body)) { - if (util.nodeMajor < 16 || (util.nodeMajor === 16 && util.nodeMinor < 8)) { - throw new InvalidArgumentError('Form-Data bodies are only supported in node v16.8 and newer.') - } - - if (!extractBody) { - extractBody = (__nccwpck_require__(6770).extractBody) - } - - const [bodyStream, contentType] = extractBody(body) - if (this.contentType == null) { - this.contentType = contentType - this.headers += `content-type: ${contentType}\r\n` - } - this.body = bodyStream.stream - this.contentLength = bodyStream.length - } else if (util.isBlobLike(body) && this.contentType == null && body.type) { - this.contentType = body.type - this.headers += `content-type: ${body.type}\r\n` - } - - util.validateHandler(handler, method, upgrade) - - this.servername = util.getServerName(this.host) - - this[kHandler] = handler - - if (channels.create.hasSubscribers) { - channels.create.publish({ request: this }) - } - } - - onBodySent (chunk) { - if (this[kHandler].onBodySent) { - try { - this[kHandler].onBodySent(chunk) - } catch (err) { - this.onError(err) - } - } - } - - onRequestSent () { - if (channels.bodySent.hasSubscribers) { - channels.bodySent.publish({ request: this }) - } - - if (this[kHandler].onRequestSent) { - try { - this[kHandler].onRequestSent() - } catch (err) { - this.onError(err) - } - } - } - - onConnect (abort) { - assert(!this.aborted) - assert(!this.completed) - - if (this.error) { - abort(this.error) - } else { - this.abort = abort - return this[kHandler].onConnect(abort) - } - } - - onHeaders (statusCode, headers, resume, statusText) { - assert(!this.aborted) - assert(!this.completed) - - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }) - } - - return this[kHandler].onHeaders(statusCode, headers, resume, statusText) - } - - onData (chunk) { - assert(!this.aborted) - assert(!this.completed) - - return this[kHandler].onData(chunk) - } - - onUpgrade (statusCode, headers, socket) { - assert(!this.aborted) - assert(!this.completed) - - return this[kHandler].onUpgrade(statusCode, headers, socket) - } - - onComplete (trailers) { - this.onFinally() - - assert(!this.aborted) - - this.completed = true - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers }) - } - return this[kHandler].onComplete(trailers) - } - - onError (error) { - this.onFinally() - - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error }) - } - - if (this.aborted) { - return - } - this.aborted = true - return this[kHandler].onError(error) - } - - onFinally () { - if (this.errorHandler) { - this.body.off('error', this.errorHandler) - this.errorHandler = null - } - - if (this.endHandler) { - this.body.off('end', this.endHandler) - this.endHandler = null - } - } - - // TODO: adjust to support H2 - addHeader (key, value) { - processHeader(this, key, value) - return this - } - - static [kHTTP1BuildRequest] (origin, opts, handler) { - // TODO: Migrate header parsing here, to make Requests - // HTTP agnostic - return new Request(origin, opts, handler) - } - - static [kHTTP2BuildRequest] (origin, opts, handler) { - const headers = opts.headers - opts = { ...opts, headers: null } - - const request = new Request(origin, opts, handler) - - request.headers = {} - - if (Array.isArray(headers)) { - if (headers.length % 2 !== 0) { - throw new InvalidArgumentError('headers array must be even') - } - for (let i = 0; i < headers.length; i += 2) { - processHeader(request, headers[i], headers[i + 1], true) - } - } else if (headers && typeof headers === 'object') { - const keys = Object.keys(headers) - for (let i = 0; i < keys.length; i++) { - const key = keys[i] - processHeader(request, key, headers[key], true) - } - } else if (headers != null) { - throw new InvalidArgumentError('headers must be an object or an array') - } - - return request - } - - static [kHTTP2CopyHeaders] (raw) { - const rawHeaders = raw.split('\r\n') - const headers = {} - - for (const header of rawHeaders) { - const [key, value] = header.split(': ') - - if (value == null || value.length === 0) continue - - if (headers[key]) headers[key] += `,${value}` - else headers[key] = value - } - - return headers - } -} - -function processHeaderValue (key, val, skipAppend) { - if (val && typeof val === 'object') { - throw new InvalidArgumentError(`invalid ${key} header`) - } - - val = val != null ? `${val}` : '' - - if (headerCharRegex.exec(val) !== null) { - throw new InvalidArgumentError(`invalid ${key} header`) - } - - return skipAppend ? val : `${key}: ${val}\r\n` -} - -function processHeader (request, key, val, skipAppend = false) { - if (val && (typeof val === 'object' && !Array.isArray(val))) { - throw new InvalidArgumentError(`invalid ${key} header`) - } else if (val === undefined) { - return - } - - if ( - request.host === null && - key.length === 4 && - key.toLowerCase() === 'host' - ) { - if (headerCharRegex.exec(val) !== null) { - throw new InvalidArgumentError(`invalid ${key} header`) - } - // Consumed by Client - request.host = val - } else if ( - request.contentLength === null && - key.length === 14 && - key.toLowerCase() === 'content-length' - ) { - request.contentLength = parseInt(val, 10) - if (!Number.isFinite(request.contentLength)) { - throw new InvalidArgumentError('invalid content-length header') - } - } else if ( - request.contentType === null && - key.length === 12 && - key.toLowerCase() === 'content-type' - ) { - request.contentType = val - if (skipAppend) request.headers[key] = processHeaderValue(key, val, skipAppend) - else request.headers += processHeaderValue(key, val) - } else if ( - key.length === 17 && - key.toLowerCase() === 'transfer-encoding' - ) { - throw new InvalidArgumentError('invalid transfer-encoding header') - } else if ( - key.length === 10 && - key.toLowerCase() === 'connection' - ) { - const value = typeof val === 'string' ? val.toLowerCase() : null - if (value !== 'close' && value !== 'keep-alive') { - throw new InvalidArgumentError('invalid connection header') - } else if (value === 'close') { - request.reset = true - } - } else if ( - key.length === 10 && - key.toLowerCase() === 'keep-alive' - ) { - throw new InvalidArgumentError('invalid keep-alive header') - } else if ( - key.length === 7 && - key.toLowerCase() === 'upgrade' - ) { - throw new InvalidArgumentError('invalid upgrade header') - } else if ( - key.length === 6 && - key.toLowerCase() === 'expect' - ) { - throw new NotSupportedError('expect header not supported') - } else if (tokenRegExp.exec(key) === null) { - throw new InvalidArgumentError('invalid header key') - } else { - if (Array.isArray(val)) { - for (let i = 0; i < val.length; i++) { - if (skipAppend) { - if (request.headers[key]) request.headers[key] += `,${processHeaderValue(key, val[i], skipAppend)}` - else request.headers[key] = processHeaderValue(key, val[i], skipAppend) - } else { - request.headers += processHeaderValue(key, val[i]) - } - } - } else { - if (skipAppend) request.headers[key] = processHeaderValue(key, val, skipAppend) - else request.headers += processHeaderValue(key, val) - } - } -} - -module.exports = Request - - -/***/ }), - -/***/ 1439: -/***/ ((module) => { - -module.exports = { - kClose: Symbol('close'), - kDestroy: Symbol('destroy'), - kDispatch: Symbol('dispatch'), - kUrl: Symbol('url'), - kWriting: Symbol('writing'), - kResuming: Symbol('resuming'), - kQueue: Symbol('queue'), - kConnect: Symbol('connect'), - kConnecting: Symbol('connecting'), - kHeadersList: Symbol('headers list'), - kKeepAliveDefaultTimeout: Symbol('default keep alive timeout'), - kKeepAliveMaxTimeout: Symbol('max keep alive timeout'), - kKeepAliveTimeoutThreshold: Symbol('keep alive timeout threshold'), - kKeepAliveTimeoutValue: Symbol('keep alive timeout'), - kKeepAlive: Symbol('keep alive'), - kHeadersTimeout: Symbol('headers timeout'), - kBodyTimeout: Symbol('body timeout'), - kServerName: Symbol('server name'), - kLocalAddress: Symbol('local address'), - kHost: Symbol('host'), - kNoRef: Symbol('no ref'), - kBodyUsed: Symbol('used'), - kRunning: Symbol('running'), - kBlocking: Symbol('blocking'), - kPending: Symbol('pending'), - kSize: Symbol('size'), - kBusy: Symbol('busy'), - kQueued: Symbol('queued'), - kFree: Symbol('free'), - kConnected: Symbol('connected'), - kClosed: Symbol('closed'), - kNeedDrain: Symbol('need drain'), - kReset: Symbol('reset'), - kDestroyed: Symbol.for('nodejs.stream.destroyed'), - kMaxHeadersSize: Symbol('max headers size'), - kRunningIdx: Symbol('running index'), - kPendingIdx: Symbol('pending index'), - kError: Symbol('error'), - kClients: Symbol('clients'), - kClient: Symbol('client'), - kParser: Symbol('parser'), - kOnDestroyed: Symbol('destroy callbacks'), - kPipelining: Symbol('pipelining'), - kSocket: Symbol('socket'), - kHostHeader: Symbol('host header'), - kConnector: Symbol('connector'), - kStrictContentLength: Symbol('strict content length'), - kMaxRedirections: Symbol('maxRedirections'), - kMaxRequests: Symbol('maxRequestsPerClient'), - kProxy: Symbol('proxy agent options'), - kCounter: Symbol('socket request counter'), - kInterceptors: Symbol('dispatch interceptors'), - kMaxResponseSize: Symbol('max response size'), - kHTTP2Session: Symbol('http2Session'), - kHTTP2SessionState: Symbol('http2Session state'), - kHTTP2BuildRequest: Symbol('http2 build request'), - kHTTP1BuildRequest: Symbol('http1 build request'), - kHTTP2CopyHeaders: Symbol('http2 copy headers'), - kHTTPConnVersion: Symbol('http connection version') -} - - -/***/ }), - -/***/ 6223: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const assert = __nccwpck_require__(9491) -const { kDestroyed, kBodyUsed } = __nccwpck_require__(1439) -const { IncomingMessage } = __nccwpck_require__(3685) -const stream = __nccwpck_require__(2781) -const net = __nccwpck_require__(1808) -const { InvalidArgumentError } = __nccwpck_require__(5767) -const { Blob } = __nccwpck_require__(4300) -const nodeUtil = __nccwpck_require__(3837) -const { stringify } = __nccwpck_require__(3477) - -const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(v => Number(v)) - -function nop () {} - -function isStream (obj) { - return obj && typeof obj === 'object' && typeof obj.pipe === 'function' && typeof obj.on === 'function' -} - -// based on https://github.com/node-fetch/fetch-blob/blob/8ab587d34080de94140b54f07168451e7d0b655e/index.js#L229-L241 (MIT License) -function isBlobLike (object) { - return (Blob && object instanceof Blob) || ( - object && - typeof object === 'object' && - (typeof object.stream === 'function' || - typeof object.arrayBuffer === 'function') && - /^(Blob|File)$/.test(object[Symbol.toStringTag]) - ) -} - -function buildURL (url, queryParams) { - if (url.includes('?') || url.includes('#')) { - throw new Error('Query params cannot be passed when url already contains "?" or "#".') - } - - const stringified = stringify(queryParams) - - if (stringified) { - url += '?' + stringified - } - - return url -} - -function parseURL (url) { - if (typeof url === 'string') { - url = new URL(url) - - if (!/^https?:/.test(url.origin || url.protocol)) { - throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.') - } - - return url - } - - if (!url || typeof url !== 'object') { - throw new InvalidArgumentError('Invalid URL: The URL argument must be a non-null object.') - } - - if (!/^https?:/.test(url.origin || url.protocol)) { - throw new InvalidArgumentError('Invalid URL protocol: the URL must start with `http:` or `https:`.') - } - - if (!(url instanceof URL)) { - if (url.port != null && url.port !== '' && !Number.isFinite(parseInt(url.port))) { - throw new InvalidArgumentError('Invalid URL: port must be a valid integer or a string representation of an integer.') - } - - if (url.path != null && typeof url.path !== 'string') { - throw new InvalidArgumentError('Invalid URL path: the path must be a string or null/undefined.') - } - - if (url.pathname != null && typeof url.pathname !== 'string') { - throw new InvalidArgumentError('Invalid URL pathname: the pathname must be a string or null/undefined.') - } - - if (url.hostname != null && typeof url.hostname !== 'string') { - throw new InvalidArgumentError('Invalid URL hostname: the hostname must be a string or null/undefined.') - } - - if (url.origin != null && typeof url.origin !== 'string') { - throw new InvalidArgumentError('Invalid URL origin: the origin must be a string or null/undefined.') - } - - const port = url.port != null - ? url.port - : (url.protocol === 'https:' ? 443 : 80) - let origin = url.origin != null - ? url.origin - : `${url.protocol}//${url.hostname}:${port}` - let path = url.path != null - ? url.path - : `${url.pathname || ''}${url.search || ''}` - - if (origin.endsWith('/')) { - origin = origin.substring(0, origin.length - 1) - } - - if (path && !path.startsWith('/')) { - path = `/${path}` - } - // new URL(path, origin) is unsafe when `path` contains an absolute URL - // From https://developer.mozilla.org/en-US/docs/Web/API/URL/URL: - // If first parameter is a relative URL, second param is required, and will be used as the base URL. - // If first parameter is an absolute URL, a given second param will be ignored. - url = new URL(origin + path) - } - - return url -} - -function parseOrigin (url) { - url = parseURL(url) - - if (url.pathname !== '/' || url.search || url.hash) { - throw new InvalidArgumentError('invalid url') - } - - return url -} - -function getHostname (host) { - if (host[0] === '[') { - const idx = host.indexOf(']') - - assert(idx !== -1) - return host.substr(1, idx - 1) - } - - const idx = host.indexOf(':') - if (idx === -1) return host - - return host.substr(0, idx) -} - -// IP addresses are not valid server names per RFC6066 -// > Currently, the only server names supported are DNS hostnames -function getServerName (host) { - if (!host) { - return null - } - - assert.strictEqual(typeof host, 'string') - - const servername = getHostname(host) - if (net.isIP(servername)) { - return '' - } - - return servername -} - -function deepClone (obj) { - return JSON.parse(JSON.stringify(obj)) -} - -function isAsyncIterable (obj) { - return !!(obj != null && typeof obj[Symbol.asyncIterator] === 'function') -} - -function isIterable (obj) { - return !!(obj != null && (typeof obj[Symbol.iterator] === 'function' || typeof obj[Symbol.asyncIterator] === 'function')) -} - -function bodyLength (body) { - if (body == null) { - return 0 - } else if (isStream(body)) { - const state = body._readableState - return state && state.objectMode === false && state.ended === true && Number.isFinite(state.length) - ? state.length - : null - } else if (isBlobLike(body)) { - return body.size != null ? body.size : null - } else if (isBuffer(body)) { - return body.byteLength - } - - return null -} - -function isDestroyed (stream) { - return !stream || !!(stream.destroyed || stream[kDestroyed]) -} - -function isReadableAborted (stream) { - const state = stream && stream._readableState - return isDestroyed(stream) && state && !state.endEmitted -} - -function destroy (stream, err) { - if (stream == null || !isStream(stream) || isDestroyed(stream)) { - return - } - - if (typeof stream.destroy === 'function') { - if (Object.getPrototypeOf(stream).constructor === IncomingMessage) { - // See: https://github.com/nodejs/node/pull/38505/files - stream.socket = null - } - - stream.destroy(err) - } else if (err) { - process.nextTick((stream, err) => { - stream.emit('error', err) - }, stream, err) - } - - if (stream.destroyed !== true) { - stream[kDestroyed] = true - } -} - -const KEEPALIVE_TIMEOUT_EXPR = /timeout=(\d+)/ -function parseKeepAliveTimeout (val) { - const m = val.toString().match(KEEPALIVE_TIMEOUT_EXPR) - return m ? parseInt(m[1], 10) * 1000 : null -} - -function parseHeaders (headers, obj = {}) { - // For H2 support - if (!Array.isArray(headers)) return headers - - for (let i = 0; i < headers.length; i += 2) { - const key = headers[i].toString().toLowerCase() - let val = obj[key] - - if (!val) { - if (Array.isArray(headers[i + 1])) { - obj[key] = headers[i + 1] - } else { - obj[key] = headers[i + 1].toString('utf8') - } - } else { - if (!Array.isArray(val)) { - val = [val] - obj[key] = val - } - val.push(headers[i + 1].toString('utf8')) - } - } - - // See https://github.com/nodejs/node/pull/46528 - if ('content-length' in obj && 'content-disposition' in obj) { - obj['content-disposition'] = Buffer.from(obj['content-disposition']).toString('latin1') - } - - return obj -} - -function parseRawHeaders (headers) { - const ret = [] - let hasContentLength = false - let contentDispositionIdx = -1 - - for (let n = 0; n < headers.length; n += 2) { - const key = headers[n + 0].toString() - const val = headers[n + 1].toString('utf8') - - if (key.length === 14 && (key === 'content-length' || key.toLowerCase() === 'content-length')) { - ret.push(key, val) - hasContentLength = true - } else if (key.length === 19 && (key === 'content-disposition' || key.toLowerCase() === 'content-disposition')) { - contentDispositionIdx = ret.push(key, val) - 1 - } else { - ret.push(key, val) - } - } - - // See https://github.com/nodejs/node/pull/46528 - if (hasContentLength && contentDispositionIdx !== -1) { - ret[contentDispositionIdx] = Buffer.from(ret[contentDispositionIdx]).toString('latin1') - } - - return ret -} - -function isBuffer (buffer) { - // See, https://github.com/mcollina/undici/pull/319 - return buffer instanceof Uint8Array || Buffer.isBuffer(buffer) -} - -function validateHandler (handler, method, upgrade) { - if (!handler || typeof handler !== 'object') { - throw new InvalidArgumentError('handler must be an object') - } - - if (typeof handler.onConnect !== 'function') { - throw new InvalidArgumentError('invalid onConnect method') - } - - if (typeof handler.onError !== 'function') { - throw new InvalidArgumentError('invalid onError method') - } - - if (typeof handler.onBodySent !== 'function' && handler.onBodySent !== undefined) { - throw new InvalidArgumentError('invalid onBodySent method') - } - - if (upgrade || method === 'CONNECT') { - if (typeof handler.onUpgrade !== 'function') { - throw new InvalidArgumentError('invalid onUpgrade method') - } - } else { - if (typeof handler.onHeaders !== 'function') { - throw new InvalidArgumentError('invalid onHeaders method') - } - - if (typeof handler.onData !== 'function') { - throw new InvalidArgumentError('invalid onData method') - } - - if (typeof handler.onComplete !== 'function') { - throw new InvalidArgumentError('invalid onComplete method') - } - } -} - -// A body is disturbed if it has been read from and it cannot -// be re-used without losing state or data. -function isDisturbed (body) { - return !!(body && ( - stream.isDisturbed - ? stream.isDisturbed(body) || body[kBodyUsed] // TODO (fix): Why is body[kBodyUsed] needed? - : body[kBodyUsed] || - body.readableDidRead || - (body._readableState && body._readableState.dataEmitted) || - isReadableAborted(body) - )) -} - -function isErrored (body) { - return !!(body && ( - stream.isErrored - ? stream.isErrored(body) - : /state: 'errored'/.test(nodeUtil.inspect(body) - ))) -} - -function isReadable (body) { - return !!(body && ( - stream.isReadable - ? stream.isReadable(body) - : /state: 'readable'/.test(nodeUtil.inspect(body) - ))) -} - -function getSocketInfo (socket) { - return { - localAddress: socket.localAddress, - localPort: socket.localPort, - remoteAddress: socket.remoteAddress, - remotePort: socket.remotePort, - remoteFamily: socket.remoteFamily, - timeout: socket.timeout, - bytesWritten: socket.bytesWritten, - bytesRead: socket.bytesRead - } -} - -async function * convertIterableToBuffer (iterable) { - for await (const chunk of iterable) { - yield Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk) - } -} - -let ReadableStream -function ReadableStreamFrom (iterable) { - if (!ReadableStream) { - ReadableStream = (__nccwpck_require__(5356).ReadableStream) - } - - if (ReadableStream.from) { - return ReadableStream.from(convertIterableToBuffer(iterable)) - } - - let iterator - return new ReadableStream( - { - async start () { - iterator = iterable[Symbol.asyncIterator]() - }, - async pull (controller) { - const { done, value } = await iterator.next() - if (done) { - queueMicrotask(() => { - controller.close() - }) - } else { - const buf = Buffer.isBuffer(value) ? value : Buffer.from(value) - controller.enqueue(new Uint8Array(buf)) - } - return controller.desiredSize > 0 - }, - async cancel (reason) { - await iterator.return() - } - }, - 0 - ) -} - -// The chunk should be a FormData instance and contains -// all the required methods. -function isFormDataLike (object) { - return ( - object && - typeof object === 'object' && - typeof object.append === 'function' && - typeof object.delete === 'function' && - typeof object.get === 'function' && - typeof object.getAll === 'function' && - typeof object.has === 'function' && - typeof object.set === 'function' && - object[Symbol.toStringTag] === 'FormData' - ) -} - -function throwIfAborted (signal) { - if (!signal) { return } - if (typeof signal.throwIfAborted === 'function') { - signal.throwIfAborted() - } else { - if (signal.aborted) { - // DOMException not available < v17.0.0 - const err = new Error('The operation was aborted') - err.name = 'AbortError' - throw err - } - } -} - -let events -function addAbortListener (signal, listener) { - if (typeof Symbol.dispose === 'symbol') { - if (!events) { - events = __nccwpck_require__(2361) - } - if (typeof events.addAbortListener === 'function' && 'aborted' in signal) { - return events.addAbortListener(signal, listener) - } - } - if ('addEventListener' in signal) { - signal.addEventListener('abort', listener, { once: true }) - return () => signal.removeEventListener('abort', listener) - } - signal.addListener('abort', listener) - return () => signal.removeListener('abort', listener) -} - -const hasToWellFormed = !!String.prototype.toWellFormed - -/** - * @param {string} val - */ -function toUSVString (val) { - if (hasToWellFormed) { - return `${val}`.toWellFormed() - } else if (nodeUtil.toUSVString) { - return nodeUtil.toUSVString(val) - } - - return `${val}` -} - -const kEnumerableProperty = Object.create(null) -kEnumerableProperty.enumerable = true - -module.exports = { - kEnumerableProperty, - nop, - isDisturbed, - isErrored, - isReadable, - toUSVString, - isReadableAborted, - isBlobLike, - parseOrigin, - parseURL, - getServerName, - isStream, - isIterable, - isAsyncIterable, - isDestroyed, - parseRawHeaders, - parseHeaders, - parseKeepAliveTimeout, - destroy, - bodyLength, - deepClone, - ReadableStreamFrom, - isBuffer, - validateHandler, - getSocketInfo, - isFormDataLike, - buildURL, - throwIfAborted, - addAbortListener, - nodeMajor, - nodeMinor, - nodeHasAutoSelectFamily: nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 13) -} - - -/***/ }), - -/***/ 8188: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const Dispatcher = __nccwpck_require__(1312) -const { - ClientDestroyedError, - ClientClosedError, - InvalidArgumentError -} = __nccwpck_require__(5767) -const { kDestroy, kClose, kDispatch, kInterceptors } = __nccwpck_require__(1439) - -const kDestroyed = Symbol('destroyed') -const kClosed = Symbol('closed') -const kOnDestroyed = Symbol('onDestroyed') -const kOnClosed = Symbol('onClosed') -const kInterceptedDispatch = Symbol('Intercepted Dispatch') - -class DispatcherBase extends Dispatcher { - constructor () { - super() - - this[kDestroyed] = false - this[kOnDestroyed] = null - this[kClosed] = false - this[kOnClosed] = [] - } - - get destroyed () { - return this[kDestroyed] - } - - get closed () { - return this[kClosed] - } - - get interceptors () { - return this[kInterceptors] - } - - set interceptors (newInterceptors) { - if (newInterceptors) { - for (let i = newInterceptors.length - 1; i >= 0; i--) { - const interceptor = this[kInterceptors][i] - if (typeof interceptor !== 'function') { - throw new InvalidArgumentError('interceptor must be an function') - } - } - } - - this[kInterceptors] = newInterceptors - } - - close (callback) { - if (callback === undefined) { - return new Promise((resolve, reject) => { - this.close((err, data) => { - return err ? reject(err) : resolve(data) - }) - }) - } - - if (typeof callback !== 'function') { - throw new InvalidArgumentError('invalid callback') - } - - if (this[kDestroyed]) { - queueMicrotask(() => callback(new ClientDestroyedError(), null)) - return - } - - if (this[kClosed]) { - if (this[kOnClosed]) { - this[kOnClosed].push(callback) - } else { - queueMicrotask(() => callback(null, null)) - } - return - } - - this[kClosed] = true - this[kOnClosed].push(callback) - - const onClosed = () => { - const callbacks = this[kOnClosed] - this[kOnClosed] = null - for (let i = 0; i < callbacks.length; i++) { - callbacks[i](null, null) - } - } - - // Should not error. - this[kClose]() - .then(() => this.destroy()) - .then(() => { - queueMicrotask(onClosed) - }) - } - - destroy (err, callback) { - if (typeof err === 'function') { - callback = err - err = null - } - - if (callback === undefined) { - return new Promise((resolve, reject) => { - this.destroy(err, (err, data) => { - return err ? /* istanbul ignore next: should never error */ reject(err) : resolve(data) - }) - }) - } - - if (typeof callback !== 'function') { - throw new InvalidArgumentError('invalid callback') - } - - if (this[kDestroyed]) { - if (this[kOnDestroyed]) { - this[kOnDestroyed].push(callback) - } else { - queueMicrotask(() => callback(null, null)) - } - return - } - - if (!err) { - err = new ClientDestroyedError() - } - - this[kDestroyed] = true - this[kOnDestroyed] = this[kOnDestroyed] || [] - this[kOnDestroyed].push(callback) - - const onDestroyed = () => { - const callbacks = this[kOnDestroyed] - this[kOnDestroyed] = null - for (let i = 0; i < callbacks.length; i++) { - callbacks[i](null, null) - } - } - - // Should not error. - this[kDestroy](err).then(() => { - queueMicrotask(onDestroyed) - }) - } - - [kInterceptedDispatch] (opts, handler) { - if (!this[kInterceptors] || this[kInterceptors].length === 0) { - this[kInterceptedDispatch] = this[kDispatch] - return this[kDispatch](opts, handler) - } - - let dispatch = this[kDispatch].bind(this) - for (let i = this[kInterceptors].length - 1; i >= 0; i--) { - dispatch = this[kInterceptors][i](dispatch) - } - this[kInterceptedDispatch] = dispatch - return dispatch(opts, handler) - } - - dispatch (opts, handler) { - if (!handler || typeof handler !== 'object') { - throw new InvalidArgumentError('handler must be an object') - } - - try { - if (!opts || typeof opts !== 'object') { - throw new InvalidArgumentError('opts must be an object.') - } - - if (this[kDestroyed] || this[kOnDestroyed]) { - throw new ClientDestroyedError() - } - - if (this[kClosed]) { - throw new ClientClosedError() - } - - return this[kInterceptedDispatch](opts, handler) - } catch (err) { - if (typeof handler.onError !== 'function') { - throw new InvalidArgumentError('invalid onError method') - } - - handler.onError(err) - - return false - } - } -} - -module.exports = DispatcherBase - - -/***/ }), - -/***/ 1312: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const EventEmitter = __nccwpck_require__(2361) - -class Dispatcher extends EventEmitter { - dispatch () { - throw new Error('not implemented') - } - - close () { - throw new Error('not implemented') - } - - destroy () { - throw new Error('not implemented') - } -} - -module.exports = Dispatcher - - -/***/ }), - -/***/ 6770: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const Busboy = __nccwpck_require__(1702) -const util = __nccwpck_require__(6223) -const { - ReadableStreamFrom, - isBlobLike, - isReadableStreamLike, - readableStreamClose, - createDeferredPromise, - fullyReadBody -} = __nccwpck_require__(6913) -const { FormData } = __nccwpck_require__(4595) -const { kState } = __nccwpck_require__(1048) -const { webidl } = __nccwpck_require__(5337) -const { DOMException, structuredClone } = __nccwpck_require__(7213) -const { Blob, File: NativeFile } = __nccwpck_require__(4300) -const { kBodyUsed } = __nccwpck_require__(1439) -const assert = __nccwpck_require__(9491) -const { isErrored } = __nccwpck_require__(6223) -const { isUint8Array, isArrayBuffer } = __nccwpck_require__(9830) -const { File: UndiciFile } = __nccwpck_require__(9072) -const { parseMIMEType, serializeAMimeType } = __nccwpck_require__(6822) - -let ReadableStream = globalThis.ReadableStream - -/** @type {globalThis['File']} */ -const File = NativeFile ?? UndiciFile -const textEncoder = new TextEncoder() -const textDecoder = new TextDecoder() - -// https://fetch.spec.whatwg.org/#concept-bodyinit-extract -function extractBody (object, keepalive = false) { - if (!ReadableStream) { - ReadableStream = (__nccwpck_require__(5356).ReadableStream) - } - - // 1. Let stream be null. - let stream = null - - // 2. If object is a ReadableStream object, then set stream to object. - if (object instanceof ReadableStream) { - stream = object - } else if (isBlobLike(object)) { - // 3. Otherwise, if object is a Blob object, set stream to the - // result of running object’s get stream. - stream = object.stream() - } else { - // 4. Otherwise, set stream to a new ReadableStream object, and set - // up stream. - stream = new ReadableStream({ - async pull (controller) { - controller.enqueue( - typeof source === 'string' ? textEncoder.encode(source) : source - ) - queueMicrotask(() => readableStreamClose(controller)) - }, - start () {}, - type: undefined - }) - } - - // 5. Assert: stream is a ReadableStream object. - assert(isReadableStreamLike(stream)) - - // 6. Let action be null. - let action = null - - // 7. Let source be null. - let source = null - - // 8. Let length be null. - let length = null - - // 9. Let type be null. - let type = null - - // 10. Switch on object: - if (typeof object === 'string') { - // Set source to the UTF-8 encoding of object. - // Note: setting source to a Uint8Array here breaks some mocking assumptions. - source = object - - // Set type to `text/plain;charset=UTF-8`. - type = 'text/plain;charset=UTF-8' - } else if (object instanceof URLSearchParams) { - // URLSearchParams - - // spec says to run application/x-www-form-urlencoded on body.list - // this is implemented in Node.js as apart of an URLSearchParams instance toString method - // See: https://github.com/nodejs/node/blob/e46c680bf2b211bbd52cf959ca17ee98c7f657f5/lib/internal/url.js#L490 - // and https://github.com/nodejs/node/blob/e46c680bf2b211bbd52cf959ca17ee98c7f657f5/lib/internal/url.js#L1100 - - // Set source to the result of running the application/x-www-form-urlencoded serializer with object’s list. - source = object.toString() - - // Set type to `application/x-www-form-urlencoded;charset=UTF-8`. - type = 'application/x-www-form-urlencoded;charset=UTF-8' - } else if (isArrayBuffer(object)) { - // BufferSource/ArrayBuffer - - // Set source to a copy of the bytes held by object. - source = new Uint8Array(object.slice()) - } else if (ArrayBuffer.isView(object)) { - // BufferSource/ArrayBufferView - - // Set source to a copy of the bytes held by object. - source = new Uint8Array(object.buffer.slice(object.byteOffset, object.byteOffset + object.byteLength)) - } else if (util.isFormDataLike(object)) { - const boundary = `----formdata-undici-0${`${Math.floor(Math.random() * 1e11)}`.padStart(11, '0')}` - const prefix = `--${boundary}\r\nContent-Disposition: form-data` - - /*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */ - const escape = (str) => - str.replace(/\n/g, '%0A').replace(/\r/g, '%0D').replace(/"/g, '%22') - const normalizeLinefeeds = (value) => value.replace(/\r?\n|\r/g, '\r\n') - - // Set action to this step: run the multipart/form-data - // encoding algorithm, with object’s entry list and UTF-8. - // - This ensures that the body is immutable and can't be changed afterwords - // - That the content-length is calculated in advance. - // - And that all parts are pre-encoded and ready to be sent. - - const blobParts = [] - const rn = new Uint8Array([13, 10]) // '\r\n' - length = 0 - let hasUnknownSizeValue = false - - for (const [name, value] of object) { - if (typeof value === 'string') { - const chunk = textEncoder.encode(prefix + - `; name="${escape(normalizeLinefeeds(name))}"` + - `\r\n\r\n${normalizeLinefeeds(value)}\r\n`) - blobParts.push(chunk) - length += chunk.byteLength - } else { - const chunk = textEncoder.encode(`${prefix}; name="${escape(normalizeLinefeeds(name))}"` + - (value.name ? `; filename="${escape(value.name)}"` : '') + '\r\n' + - `Content-Type: ${ - value.type || 'application/octet-stream' - }\r\n\r\n`) - blobParts.push(chunk, value, rn) - if (typeof value.size === 'number') { - length += chunk.byteLength + value.size + rn.byteLength - } else { - hasUnknownSizeValue = true - } - } - } - - const chunk = textEncoder.encode(`--${boundary}--`) - blobParts.push(chunk) - length += chunk.byteLength - if (hasUnknownSizeValue) { - length = null - } - - // Set source to object. - source = object - - action = async function * () { - for (const part of blobParts) { - if (part.stream) { - yield * part.stream() - } else { - yield part - } - } - } - - // Set type to `multipart/form-data; boundary=`, - // followed by the multipart/form-data boundary string generated - // by the multipart/form-data encoding algorithm. - type = 'multipart/form-data; boundary=' + boundary - } else if (isBlobLike(object)) { - // Blob - - // Set source to object. - source = object - - // Set length to object’s size. - length = object.size - - // If object’s type attribute is not the empty byte sequence, set - // type to its value. - if (object.type) { - type = object.type - } - } else if (typeof object[Symbol.asyncIterator] === 'function') { - // If keepalive is true, then throw a TypeError. - if (keepalive) { - throw new TypeError('keepalive') - } - - // If object is disturbed or locked, then throw a TypeError. - if (util.isDisturbed(object) || object.locked) { - throw new TypeError( - 'Response body object should not be disturbed or locked' - ) - } - - stream = - object instanceof ReadableStream ? object : ReadableStreamFrom(object) - } - - // 11. If source is a byte sequence, then set action to a - // step that returns source and length to source’s length. - if (typeof source === 'string' || util.isBuffer(source)) { - length = Buffer.byteLength(source) - } - - // 12. If action is non-null, then run these steps in in parallel: - if (action != null) { - // Run action. - let iterator - stream = new ReadableStream({ - async start () { - iterator = action(object)[Symbol.asyncIterator]() - }, - async pull (controller) { - const { value, done } = await iterator.next() - if (done) { - // When running action is done, close stream. - queueMicrotask(() => { - controller.close() - }) - } else { - // Whenever one or more bytes are available and stream is not errored, - // enqueue a Uint8Array wrapping an ArrayBuffer containing the available - // bytes into stream. - if (!isErrored(stream)) { - controller.enqueue(new Uint8Array(value)) - } - } - return controller.desiredSize > 0 - }, - async cancel (reason) { - await iterator.return() - }, - type: undefined - }) - } - - // 13. Let body be a body whose stream is stream, source is source, - // and length is length. - const body = { stream, source, length } - - // 14. Return (body, type). - return [body, type] -} - -// https://fetch.spec.whatwg.org/#bodyinit-safely-extract -function safelyExtractBody (object, keepalive = false) { - if (!ReadableStream) { - // istanbul ignore next - ReadableStream = (__nccwpck_require__(5356).ReadableStream) - } - - // To safely extract a body and a `Content-Type` value from - // a byte sequence or BodyInit object object, run these steps: - - // 1. If object is a ReadableStream object, then: - if (object instanceof ReadableStream) { - // Assert: object is neither disturbed nor locked. - // istanbul ignore next - assert(!util.isDisturbed(object), 'The body has already been consumed.') - // istanbul ignore next - assert(!object.locked, 'The stream is locked.') - } - - // 2. Return the results of extracting object. - return extractBody(object, keepalive) -} - -function cloneBody (body) { - // To clone a body body, run these steps: - - // https://fetch.spec.whatwg.org/#concept-body-clone - - // 1. Let « out1, out2 » be the result of teeing body’s stream. - const [out1, out2] = body.stream.tee() - const out2Clone = structuredClone(out2, { transfer: [out2] }) - // This, for whatever reasons, unrefs out2Clone which allows - // the process to exit by itself. - const [, finalClone] = out2Clone.tee() - - // 2. Set body’s stream to out1. - body.stream = out1 - - // 3. Return a body whose stream is out2 and other members are copied from body. - return { - stream: finalClone, - length: body.length, - source: body.source - } -} - -async function * consumeBody (body) { - if (body) { - if (isUint8Array(body)) { - yield body - } else { - const stream = body.stream - - if (util.isDisturbed(stream)) { - throw new TypeError('The body has already been consumed.') - } - - if (stream.locked) { - throw new TypeError('The stream is locked.') - } - - // Compat. - stream[kBodyUsed] = true - - yield * stream - } - } -} - -function throwIfAborted (state) { - if (state.aborted) { - throw new DOMException('The operation was aborted.', 'AbortError') - } -} - -function bodyMixinMethods (instance) { - const methods = { - blob () { - // The blob() method steps are to return the result of - // running consume body with this and the following step - // given a byte sequence bytes: return a Blob whose - // contents are bytes and whose type attribute is this’s - // MIME type. - return specConsumeBody(this, (bytes) => { - let mimeType = bodyMimeType(this) - - if (mimeType === 'failure') { - mimeType = '' - } else if (mimeType) { - mimeType = serializeAMimeType(mimeType) - } - - // Return a Blob whose contents are bytes and type attribute - // is mimeType. - return new Blob([bytes], { type: mimeType }) - }, instance) - }, - - arrayBuffer () { - // The arrayBuffer() method steps are to return the result - // of running consume body with this and the following step - // given a byte sequence bytes: return a new ArrayBuffer - // whose contents are bytes. - return specConsumeBody(this, (bytes) => { - return new Uint8Array(bytes).buffer - }, instance) - }, - - text () { - // The text() method steps are to return the result of running - // consume body with this and UTF-8 decode. - return specConsumeBody(this, utf8DecodeBytes, instance) - }, - - json () { - // The json() method steps are to return the result of running - // consume body with this and parse JSON from bytes. - return specConsumeBody(this, parseJSONFromBytes, instance) - }, - - async formData () { - webidl.brandCheck(this, instance) - - throwIfAborted(this[kState]) - - const contentType = this.headers.get('Content-Type') - - // If mimeType’s essence is "multipart/form-data", then: - if (/multipart\/form-data/.test(contentType)) { - const headers = {} - for (const [key, value] of this.headers) headers[key.toLowerCase()] = value - - const responseFormData = new FormData() - - let busboy - - try { - busboy = new Busboy({ - headers, - preservePath: true - }) - } catch (err) { - throw new DOMException(`${err}`, 'AbortError') - } - - busboy.on('field', (name, value) => { - responseFormData.append(name, value) - }) - busboy.on('file', (name, value, filename, encoding, mimeType) => { - const chunks = [] - - if (encoding === 'base64' || encoding.toLowerCase() === 'base64') { - let base64chunk = '' - - value.on('data', (chunk) => { - base64chunk += chunk.toString().replace(/[\r\n]/gm, '') - - const end = base64chunk.length - base64chunk.length % 4 - chunks.push(Buffer.from(base64chunk.slice(0, end), 'base64')) - - base64chunk = base64chunk.slice(end) - }) - value.on('end', () => { - chunks.push(Buffer.from(base64chunk, 'base64')) - responseFormData.append(name, new File(chunks, filename, { type: mimeType })) - }) - } else { - value.on('data', (chunk) => { - chunks.push(chunk) - }) - value.on('end', () => { - responseFormData.append(name, new File(chunks, filename, { type: mimeType })) - }) - } - }) - - const busboyResolve = new Promise((resolve, reject) => { - busboy.on('finish', resolve) - busboy.on('error', (err) => reject(new TypeError(err))) - }) - - if (this.body !== null) for await (const chunk of consumeBody(this[kState].body)) busboy.write(chunk) - busboy.end() - await busboyResolve - - return responseFormData - } else if (/application\/x-www-form-urlencoded/.test(contentType)) { - // Otherwise, if mimeType’s essence is "application/x-www-form-urlencoded", then: - - // 1. Let entries be the result of parsing bytes. - let entries - try { - let text = '' - // application/x-www-form-urlencoded parser will keep the BOM. - // https://url.spec.whatwg.org/#concept-urlencoded-parser - // Note that streaming decoder is stateful and cannot be reused - const streamingDecoder = new TextDecoder('utf-8', { ignoreBOM: true }) - - for await (const chunk of consumeBody(this[kState].body)) { - if (!isUint8Array(chunk)) { - throw new TypeError('Expected Uint8Array chunk') - } - text += streamingDecoder.decode(chunk, { stream: true }) - } - text += streamingDecoder.decode() - entries = new URLSearchParams(text) - } catch (err) { - // istanbul ignore next: Unclear when new URLSearchParams can fail on a string. - // 2. If entries is failure, then throw a TypeError. - throw Object.assign(new TypeError(), { cause: err }) - } - - // 3. Return a new FormData object whose entries are entries. - const formData = new FormData() - for (const [name, value] of entries) { - formData.append(name, value) - } - return formData - } else { - // Wait a tick before checking if the request has been aborted. - // Otherwise, a TypeError can be thrown when an AbortError should. - await Promise.resolve() - - throwIfAborted(this[kState]) - - // Otherwise, throw a TypeError. - throw webidl.errors.exception({ - header: `${instance.name}.formData`, - message: 'Could not parse content as FormData.' - }) - } - } - } - - return methods -} - -function mixinBody (prototype) { - Object.assign(prototype.prototype, bodyMixinMethods(prototype)) -} - -/** - * @see https://fetch.spec.whatwg.org/#concept-body-consume-body - * @param {Response|Request} object - * @param {(value: unknown) => unknown} convertBytesToJSValue - * @param {Response|Request} instance - */ -async function specConsumeBody (object, convertBytesToJSValue, instance) { - webidl.brandCheck(object, instance) - - throwIfAborted(object[kState]) - - // 1. If object is unusable, then return a promise rejected - // with a TypeError. - if (bodyUnusable(object[kState].body)) { - throw new TypeError('Body is unusable') - } - - // 2. Let promise be a new promise. - const promise = createDeferredPromise() - - // 3. Let errorSteps given error be to reject promise with error. - const errorSteps = (error) => promise.reject(error) - - // 4. Let successSteps given a byte sequence data be to resolve - // promise with the result of running convertBytesToJSValue - // with data. If that threw an exception, then run errorSteps - // with that exception. - const successSteps = (data) => { - try { - promise.resolve(convertBytesToJSValue(data)) - } catch (e) { - errorSteps(e) - } - } - - // 5. If object’s body is null, then run successSteps with an - // empty byte sequence. - if (object[kState].body == null) { - successSteps(new Uint8Array()) - return promise.promise - } - - // 6. Otherwise, fully read object’s body given successSteps, - // errorSteps, and object’s relevant global object. - await fullyReadBody(object[kState].body, successSteps, errorSteps) - - // 7. Return promise. - return promise.promise -} - -// https://fetch.spec.whatwg.org/#body-unusable -function bodyUnusable (body) { - // An object including the Body interface mixin is - // said to be unusable if its body is non-null and - // its body’s stream is disturbed or locked. - return body != null && (body.stream.locked || util.isDisturbed(body.stream)) -} - -/** - * @see https://encoding.spec.whatwg.org/#utf-8-decode - * @param {Buffer} buffer - */ -function utf8DecodeBytes (buffer) { - if (buffer.length === 0) { - return '' - } - - // 1. Let buffer be the result of peeking three bytes from - // ioQueue, converted to a byte sequence. - - // 2. If buffer is 0xEF 0xBB 0xBF, then read three - // bytes from ioQueue. (Do nothing with those bytes.) - if (buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) { - buffer = buffer.subarray(3) - } - - // 3. Process a queue with an instance of UTF-8’s - // decoder, ioQueue, output, and "replacement". - const output = textDecoder.decode(buffer) - - // 4. Return output. - return output -} - -/** - * @see https://infra.spec.whatwg.org/#parse-json-bytes-to-a-javascript-value - * @param {Uint8Array} bytes - */ -function parseJSONFromBytes (bytes) { - return JSON.parse(utf8DecodeBytes(bytes)) -} - -/** - * @see https://fetch.spec.whatwg.org/#concept-body-mime-type - * @param {import('./response').Response|import('./request').Request} object - */ -function bodyMimeType (object) { - const { headersList } = object[kState] - const contentType = headersList.get('content-type') - - if (contentType === null) { - return 'failure' - } - - return parseMIMEType(contentType) -} - -module.exports = { - extractBody, - safelyExtractBody, - cloneBody, - mixinBody -} - - -/***/ }), - -/***/ 7213: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { MessageChannel, receiveMessageOnPort } = __nccwpck_require__(1267) - -const corsSafeListedMethods = ['GET', 'HEAD', 'POST'] -const corsSafeListedMethodsSet = new Set(corsSafeListedMethods) - -const nullBodyStatus = [101, 204, 205, 304] - -const redirectStatus = [301, 302, 303, 307, 308] -const redirectStatusSet = new Set(redirectStatus) - -// https://fetch.spec.whatwg.org/#block-bad-port -const badPorts = [ - '1', '7', '9', '11', '13', '15', '17', '19', '20', '21', '22', '23', '25', '37', '42', '43', '53', '69', '77', '79', - '87', '95', '101', '102', '103', '104', '109', '110', '111', '113', '115', '117', '119', '123', '135', '137', - '139', '143', '161', '179', '389', '427', '465', '512', '513', '514', '515', '526', '530', '531', '532', - '540', '548', '554', '556', '563', '587', '601', '636', '989', '990', '993', '995', '1719', '1720', '1723', - '2049', '3659', '4045', '5060', '5061', '6000', '6566', '6665', '6666', '6667', '6668', '6669', '6697', - '10080' -] - -const badPortsSet = new Set(badPorts) - -// https://w3c.github.io/webappsec-referrer-policy/#referrer-policies -const referrerPolicy = [ - '', - 'no-referrer', - 'no-referrer-when-downgrade', - 'same-origin', - 'origin', - 'strict-origin', - 'origin-when-cross-origin', - 'strict-origin-when-cross-origin', - 'unsafe-url' -] -const referrerPolicySet = new Set(referrerPolicy) - -const requestRedirect = ['follow', 'manual', 'error'] - -const safeMethods = ['GET', 'HEAD', 'OPTIONS', 'TRACE'] -const safeMethodsSet = new Set(safeMethods) - -const requestMode = ['navigate', 'same-origin', 'no-cors', 'cors'] - -const requestCredentials = ['omit', 'same-origin', 'include'] - -const requestCache = [ - 'default', - 'no-store', - 'reload', - 'no-cache', - 'force-cache', - 'only-if-cached' -] - -// https://fetch.spec.whatwg.org/#request-body-header-name -const requestBodyHeader = [ - 'content-encoding', - 'content-language', - 'content-location', - 'content-type', - // See https://github.com/nodejs/undici/issues/2021 - // 'Content-Length' is a forbidden header name, which is typically - // removed in the Headers implementation. However, undici doesn't - // filter out headers, so we add it here. - 'content-length' -] - -// https://fetch.spec.whatwg.org/#enumdef-requestduplex -const requestDuplex = [ - 'half' -] - -// http://fetch.spec.whatwg.org/#forbidden-method -const forbiddenMethods = ['CONNECT', 'TRACE', 'TRACK'] -const forbiddenMethodsSet = new Set(forbiddenMethods) - -const subresource = [ - 'audio', - 'audioworklet', - 'font', - 'image', - 'manifest', - 'paintworklet', - 'script', - 'style', - 'track', - 'video', - 'xslt', - '' -] -const subresourceSet = new Set(subresource) - -/** @type {globalThis['DOMException']} */ -const DOMException = globalThis.DOMException ?? (() => { - // DOMException was only made a global in Node v17.0.0, - // but fetch supports >= v16.8. - try { - atob('~') - } catch (err) { - return Object.getPrototypeOf(err).constructor - } -})() - -let channel - -/** @type {globalThis['structuredClone']} */ -const structuredClone = - globalThis.structuredClone ?? - // https://github.com/nodejs/node/blob/b27ae24dcc4251bad726d9d84baf678d1f707fed/lib/internal/structured_clone.js - // structuredClone was added in v17.0.0, but fetch supports v16.8 - function structuredClone (value, options = undefined) { - if (arguments.length === 0) { - throw new TypeError('missing argument') - } - - if (!channel) { - channel = new MessageChannel() - } - channel.port1.unref() - channel.port2.unref() - channel.port1.postMessage(value, options?.transfer) - return receiveMessageOnPort(channel.port2).message - } - -module.exports = { - DOMException, - structuredClone, - subresource, - forbiddenMethods, - requestBodyHeader, - referrerPolicy, - requestRedirect, - requestMode, - requestCredentials, - requestCache, - redirectStatus, - corsSafeListedMethods, - nullBodyStatus, - safeMethods, - badPorts, - requestDuplex, - subresourceSet, - badPortsSet, - redirectStatusSet, - corsSafeListedMethodsSet, - safeMethodsSet, - forbiddenMethodsSet, - referrerPolicySet -} - - -/***/ }), - -/***/ 6822: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -const assert = __nccwpck_require__(9491) -const { atob } = __nccwpck_require__(4300) -const { isomorphicDecode } = __nccwpck_require__(6913) - -const encoder = new TextEncoder() - -/** - * @see https://mimesniff.spec.whatwg.org/#http-token-code-point - */ -const HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+-.^_|~A-Za-z0-9]+$/ -const HTTP_WHITESPACE_REGEX = /(\u000A|\u000D|\u0009|\u0020)/ // eslint-disable-line -/** - * @see https://mimesniff.spec.whatwg.org/#http-quoted-string-token-code-point - */ -const HTTP_QUOTED_STRING_TOKENS = /[\u0009|\u0020-\u007E|\u0080-\u00FF]/ // eslint-disable-line - -// https://fetch.spec.whatwg.org/#data-url-processor -/** @param {URL} dataURL */ -function dataURLProcessor (dataURL) { - // 1. Assert: dataURL’s scheme is "data". - assert(dataURL.protocol === 'data:') - - // 2. Let input be the result of running the URL - // serializer on dataURL with exclude fragment - // set to true. - let input = URLSerializer(dataURL, true) - - // 3. Remove the leading "data:" string from input. - input = input.slice(5) - - // 4. Let position point at the start of input. - const position = { position: 0 } - - // 5. Let mimeType be the result of collecting a - // sequence of code points that are not equal - // to U+002C (,), given position. - let mimeType = collectASequenceOfCodePointsFast( - ',', - input, - position - ) - - // 6. Strip leading and trailing ASCII whitespace - // from mimeType. - // Undici implementation note: we need to store the - // length because if the mimetype has spaces removed, - // the wrong amount will be sliced from the input in - // step #9 - const mimeTypeLength = mimeType.length - mimeType = removeASCIIWhitespace(mimeType, true, true) - - // 7. If position is past the end of input, then - // return failure - if (position.position >= input.length) { - return 'failure' - } - - // 8. Advance position by 1. - position.position++ - - // 9. Let encodedBody be the remainder of input. - const encodedBody = input.slice(mimeTypeLength + 1) - - // 10. Let body be the percent-decoding of encodedBody. - let body = stringPercentDecode(encodedBody) - - // 11. If mimeType ends with U+003B (;), followed by - // zero or more U+0020 SPACE, followed by an ASCII - // case-insensitive match for "base64", then: - if (/;(\u0020){0,}base64$/i.test(mimeType)) { - // 1. Let stringBody be the isomorphic decode of body. - const stringBody = isomorphicDecode(body) - - // 2. Set body to the forgiving-base64 decode of - // stringBody. - body = forgivingBase64(stringBody) - - // 3. If body is failure, then return failure. - if (body === 'failure') { - return 'failure' - } - - // 4. Remove the last 6 code points from mimeType. - mimeType = mimeType.slice(0, -6) - - // 5. Remove trailing U+0020 SPACE code points from mimeType, - // if any. - mimeType = mimeType.replace(/(\u0020)+$/, '') - - // 6. Remove the last U+003B (;) code point from mimeType. - mimeType = mimeType.slice(0, -1) - } - - // 12. If mimeType starts with U+003B (;), then prepend - // "text/plain" to mimeType. - if (mimeType.startsWith(';')) { - mimeType = 'text/plain' + mimeType - } - - // 13. Let mimeTypeRecord be the result of parsing - // mimeType. - let mimeTypeRecord = parseMIMEType(mimeType) - - // 14. If mimeTypeRecord is failure, then set - // mimeTypeRecord to text/plain;charset=US-ASCII. - if (mimeTypeRecord === 'failure') { - mimeTypeRecord = parseMIMEType('text/plain;charset=US-ASCII') - } - - // 15. Return a new data: URL struct whose MIME - // type is mimeTypeRecord and body is body. - // https://fetch.spec.whatwg.org/#data-url-struct - return { mimeType: mimeTypeRecord, body } -} - -// https://url.spec.whatwg.org/#concept-url-serializer -/** - * @param {URL} url - * @param {boolean} excludeFragment - */ -function URLSerializer (url, excludeFragment = false) { - const href = url.href - - if (!excludeFragment) { - return href - } - - const hash = href.lastIndexOf('#') - if (hash === -1) { - return href - } - return href.slice(0, hash) -} - -// https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points -/** - * @param {(char: string) => boolean} condition - * @param {string} input - * @param {{ position: number }} position - */ -function collectASequenceOfCodePoints (condition, input, position) { - // 1. Let result be the empty string. - let result = '' - - // 2. While position doesn’t point past the end of input and the - // code point at position within input meets the condition condition: - while (position.position < input.length && condition(input[position.position])) { - // 1. Append that code point to the end of result. - result += input[position.position] - - // 2. Advance position by 1. - position.position++ - } - - // 3. Return result. - return result -} - -/** - * A faster collectASequenceOfCodePoints that only works when comparing a single character. - * @param {string} char - * @param {string} input - * @param {{ position: number }} position - */ -function collectASequenceOfCodePointsFast (char, input, position) { - const idx = input.indexOf(char, position.position) - const start = position.position - - if (idx === -1) { - position.position = input.length - return input.slice(start) - } - - position.position = idx - return input.slice(start, position.position) -} - -// https://url.spec.whatwg.org/#string-percent-decode -/** @param {string} input */ -function stringPercentDecode (input) { - // 1. Let bytes be the UTF-8 encoding of input. - const bytes = encoder.encode(input) - - // 2. Return the percent-decoding of bytes. - return percentDecode(bytes) -} - -// https://url.spec.whatwg.org/#percent-decode -/** @param {Uint8Array} input */ -function percentDecode (input) { - // 1. Let output be an empty byte sequence. - /** @type {number[]} */ - const output = [] - - // 2. For each byte byte in input: - for (let i = 0; i < input.length; i++) { - const byte = input[i] - - // 1. If byte is not 0x25 (%), then append byte to output. - if (byte !== 0x25) { - output.push(byte) - - // 2. Otherwise, if byte is 0x25 (%) and the next two bytes - // after byte in input are not in the ranges - // 0x30 (0) to 0x39 (9), 0x41 (A) to 0x46 (F), - // and 0x61 (a) to 0x66 (f), all inclusive, append byte - // to output. - } else if ( - byte === 0x25 && - !/^[0-9A-Fa-f]{2}$/i.test(String.fromCharCode(input[i + 1], input[i + 2])) - ) { - output.push(0x25) - - // 3. Otherwise: - } else { - // 1. Let bytePoint be the two bytes after byte in input, - // decoded, and then interpreted as hexadecimal number. - const nextTwoBytes = String.fromCharCode(input[i + 1], input[i + 2]) - const bytePoint = Number.parseInt(nextTwoBytes, 16) - - // 2. Append a byte whose value is bytePoint to output. - output.push(bytePoint) - - // 3. Skip the next two bytes in input. - i += 2 - } - } - - // 3. Return output. - return Uint8Array.from(output) -} - -// https://mimesniff.spec.whatwg.org/#parse-a-mime-type -/** @param {string} input */ -function parseMIMEType (input) { - // 1. Remove any leading and trailing HTTP whitespace - // from input. - input = removeHTTPWhitespace(input, true, true) - - // 2. Let position be a position variable for input, - // initially pointing at the start of input. - const position = { position: 0 } - - // 3. Let type be the result of collecting a sequence - // of code points that are not U+002F (/) from - // input, given position. - const type = collectASequenceOfCodePointsFast( - '/', - input, - position - ) - - // 4. If type is the empty string or does not solely - // contain HTTP token code points, then return failure. - // https://mimesniff.spec.whatwg.org/#http-token-code-point - if (type.length === 0 || !HTTP_TOKEN_CODEPOINTS.test(type)) { - return 'failure' - } - - // 5. If position is past the end of input, then return - // failure - if (position.position > input.length) { - return 'failure' - } - - // 6. Advance position by 1. (This skips past U+002F (/).) - position.position++ - - // 7. Let subtype be the result of collecting a sequence of - // code points that are not U+003B (;) from input, given - // position. - let subtype = collectASequenceOfCodePointsFast( - ';', - input, - position - ) - - // 8. Remove any trailing HTTP whitespace from subtype. - subtype = removeHTTPWhitespace(subtype, false, true) - - // 9. If subtype is the empty string or does not solely - // contain HTTP token code points, then return failure. - if (subtype.length === 0 || !HTTP_TOKEN_CODEPOINTS.test(subtype)) { - return 'failure' - } - - const typeLowercase = type.toLowerCase() - const subtypeLowercase = subtype.toLowerCase() - - // 10. Let mimeType be a new MIME type record whose type - // is type, in ASCII lowercase, and subtype is subtype, - // in ASCII lowercase. - // https://mimesniff.spec.whatwg.org/#mime-type - const mimeType = { - type: typeLowercase, - subtype: subtypeLowercase, - /** @type {Map<string, string>} */ - parameters: new Map(), - // https://mimesniff.spec.whatwg.org/#mime-type-essence - essence: `${typeLowercase}/${subtypeLowercase}` - } - - // 11. While position is not past the end of input: - while (position.position < input.length) { - // 1. Advance position by 1. (This skips past U+003B (;).) - position.position++ - - // 2. Collect a sequence of code points that are HTTP - // whitespace from input given position. - collectASequenceOfCodePoints( - // https://fetch.spec.whatwg.org/#http-whitespace - char => HTTP_WHITESPACE_REGEX.test(char), - input, - position - ) - - // 3. Let parameterName be the result of collecting a - // sequence of code points that are not U+003B (;) - // or U+003D (=) from input, given position. - let parameterName = collectASequenceOfCodePoints( - (char) => char !== ';' && char !== '=', - input, - position - ) - - // 4. Set parameterName to parameterName, in ASCII - // lowercase. - parameterName = parameterName.toLowerCase() - - // 5. If position is not past the end of input, then: - if (position.position < input.length) { - // 1. If the code point at position within input is - // U+003B (;), then continue. - if (input[position.position] === ';') { - continue - } - - // 2. Advance position by 1. (This skips past U+003D (=).) - position.position++ - } - - // 6. If position is past the end of input, then break. - if (position.position > input.length) { - break - } - - // 7. Let parameterValue be null. - let parameterValue = null - - // 8. If the code point at position within input is - // U+0022 ("), then: - if (input[position.position] === '"') { - // 1. Set parameterValue to the result of collecting - // an HTTP quoted string from input, given position - // and the extract-value flag. - parameterValue = collectAnHTTPQuotedString(input, position, true) - - // 2. Collect a sequence of code points that are not - // U+003B (;) from input, given position. - collectASequenceOfCodePointsFast( - ';', - input, - position - ) - - // 9. Otherwise: - } else { - // 1. Set parameterValue to the result of collecting - // a sequence of code points that are not U+003B (;) - // from input, given position. - parameterValue = collectASequenceOfCodePointsFast( - ';', - input, - position - ) - - // 2. Remove any trailing HTTP whitespace from parameterValue. - parameterValue = removeHTTPWhitespace(parameterValue, false, true) - - // 3. If parameterValue is the empty string, then continue. - if (parameterValue.length === 0) { - continue - } - } - - // 10. If all of the following are true - // - parameterName is not the empty string - // - parameterName solely contains HTTP token code points - // - parameterValue solely contains HTTP quoted-string token code points - // - mimeType’s parameters[parameterName] does not exist - // then set mimeType’s parameters[parameterName] to parameterValue. - if ( - parameterName.length !== 0 && - HTTP_TOKEN_CODEPOINTS.test(parameterName) && - (parameterValue.length === 0 || HTTP_QUOTED_STRING_TOKENS.test(parameterValue)) && - !mimeType.parameters.has(parameterName) - ) { - mimeType.parameters.set(parameterName, parameterValue) - } - } - - // 12. Return mimeType. - return mimeType -} - -// https://infra.spec.whatwg.org/#forgiving-base64-decode -/** @param {string} data */ -function forgivingBase64 (data) { - // 1. Remove all ASCII whitespace from data. - data = data.replace(/[\u0009\u000A\u000C\u000D\u0020]/g, '') // eslint-disable-line - - // 2. If data’s code point length divides by 4 leaving - // no remainder, then: - if (data.length % 4 === 0) { - // 1. If data ends with one or two U+003D (=) code points, - // then remove them from data. - data = data.replace(/=?=$/, '') - } - - // 3. If data’s code point length divides by 4 leaving - // a remainder of 1, then return failure. - if (data.length % 4 === 1) { - return 'failure' - } - - // 4. If data contains a code point that is not one of - // U+002B (+) - // U+002F (/) - // ASCII alphanumeric - // then return failure. - if (/[^+/0-9A-Za-z]/.test(data)) { - return 'failure' - } - - const binary = atob(data) - const bytes = new Uint8Array(binary.length) - - for (let byte = 0; byte < binary.length; byte++) { - bytes[byte] = binary.charCodeAt(byte) - } - - return bytes -} - -// https://fetch.spec.whatwg.org/#collect-an-http-quoted-string -// tests: https://fetch.spec.whatwg.org/#example-http-quoted-string -/** - * @param {string} input - * @param {{ position: number }} position - * @param {boolean?} extractValue - */ -function collectAnHTTPQuotedString (input, position, extractValue) { - // 1. Let positionStart be position. - const positionStart = position.position - - // 2. Let value be the empty string. - let value = '' - - // 3. Assert: the code point at position within input - // is U+0022 ("). - assert(input[position.position] === '"') - - // 4. Advance position by 1. - position.position++ - - // 5. While true: - while (true) { - // 1. Append the result of collecting a sequence of code points - // that are not U+0022 (") or U+005C (\) from input, given - // position, to value. - value += collectASequenceOfCodePoints( - (char) => char !== '"' && char !== '\\', - input, - position - ) - - // 2. If position is past the end of input, then break. - if (position.position >= input.length) { - break - } - - // 3. Let quoteOrBackslash be the code point at position within - // input. - const quoteOrBackslash = input[position.position] - - // 4. Advance position by 1. - position.position++ - - // 5. If quoteOrBackslash is U+005C (\), then: - if (quoteOrBackslash === '\\') { - // 1. If position is past the end of input, then append - // U+005C (\) to value and break. - if (position.position >= input.length) { - value += '\\' - break - } - - // 2. Append the code point at position within input to value. - value += input[position.position] - - // 3. Advance position by 1. - position.position++ - - // 6. Otherwise: - } else { - // 1. Assert: quoteOrBackslash is U+0022 ("). - assert(quoteOrBackslash === '"') - - // 2. Break. - break - } - } - - // 6. If the extract-value flag is set, then return value. - if (extractValue) { - return value - } - - // 7. Return the code points from positionStart to position, - // inclusive, within input. - return input.slice(positionStart, position.position) -} - -/** - * @see https://mimesniff.spec.whatwg.org/#serialize-a-mime-type - */ -function serializeAMimeType (mimeType) { - assert(mimeType !== 'failure') - const { parameters, essence } = mimeType - - // 1. Let serialization be the concatenation of mimeType’s - // type, U+002F (/), and mimeType’s subtype. - let serialization = essence - - // 2. For each name → value of mimeType’s parameters: - for (let [name, value] of parameters.entries()) { - // 1. Append U+003B (;) to serialization. - serialization += ';' - - // 2. Append name to serialization. - serialization += name - - // 3. Append U+003D (=) to serialization. - serialization += '=' - - // 4. If value does not solely contain HTTP token code - // points or value is the empty string, then: - if (!HTTP_TOKEN_CODEPOINTS.test(value)) { - // 1. Precede each occurence of U+0022 (") or - // U+005C (\) in value with U+005C (\). - value = value.replace(/(\\|")/g, '\\$1') - - // 2. Prepend U+0022 (") to value. - value = '"' + value - - // 3. Append U+0022 (") to value. - value += '"' - } - - // 5. Append value to serialization. - serialization += value - } - - // 3. Return serialization. - return serialization -} - -/** - * @see https://fetch.spec.whatwg.org/#http-whitespace - * @param {string} char - */ -function isHTTPWhiteSpace (char) { - return char === '\r' || char === '\n' || char === '\t' || char === ' ' -} - -/** - * @see https://fetch.spec.whatwg.org/#http-whitespace - * @param {string} str - */ -function removeHTTPWhitespace (str, leading = true, trailing = true) { - let lead = 0 - let trail = str.length - 1 - - if (leading) { - for (; lead < str.length && isHTTPWhiteSpace(str[lead]); lead++); - } - - if (trailing) { - for (; trail > 0 && isHTTPWhiteSpace(str[trail]); trail--); - } - - return str.slice(lead, trail + 1) -} - -/** - * @see https://infra.spec.whatwg.org/#ascii-whitespace - * @param {string} char - */ -function isASCIIWhitespace (char) { - return char === '\r' || char === '\n' || char === '\t' || char === '\f' || char === ' ' -} - -/** - * @see https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace - */ -function removeASCIIWhitespace (str, leading = true, trailing = true) { - let lead = 0 - let trail = str.length - 1 - - if (leading) { - for (; lead < str.length && isASCIIWhitespace(str[lead]); lead++); - } - - if (trailing) { - for (; trail > 0 && isASCIIWhitespace(str[trail]); trail--); - } - - return str.slice(lead, trail + 1) -} - -module.exports = { - dataURLProcessor, - URLSerializer, - collectASequenceOfCodePoints, - collectASequenceOfCodePointsFast, - stringPercentDecode, - parseMIMEType, - collectAnHTTPQuotedString, - serializeAMimeType -} - - -/***/ }), - -/***/ 9072: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { Blob, File: NativeFile } = __nccwpck_require__(4300) -const { types } = __nccwpck_require__(3837) -const { kState } = __nccwpck_require__(1048) -const { isBlobLike } = __nccwpck_require__(6913) -const { webidl } = __nccwpck_require__(5337) -const { parseMIMEType, serializeAMimeType } = __nccwpck_require__(6822) -const { kEnumerableProperty } = __nccwpck_require__(6223) -const encoder = new TextEncoder() - -class File extends Blob { - constructor (fileBits, fileName, options = {}) { - // The File constructor is invoked with two or three parameters, depending - // on whether the optional dictionary parameter is used. When the File() - // constructor is invoked, user agents must run the following steps: - webidl.argumentLengthCheck(arguments, 2, { header: 'File constructor' }) - - fileBits = webidl.converters['sequence<BlobPart>'](fileBits) - fileName = webidl.converters.USVString(fileName) - options = webidl.converters.FilePropertyBag(options) - - // 1. Let bytes be the result of processing blob parts given fileBits and - // options. - // Note: Blob handles this for us - - // 2. Let n be the fileName argument to the constructor. - const n = fileName - - // 3. Process FilePropertyBag dictionary argument by running the following - // substeps: - - // 1. If the type member is provided and is not the empty string, let t - // be set to the type dictionary member. If t contains any characters - // outside the range U+0020 to U+007E, then set t to the empty string - // and return from these substeps. - // 2. Convert every character in t to ASCII lowercase. - let t = options.type - let d - - // eslint-disable-next-line no-labels - substep: { - if (t) { - t = parseMIMEType(t) - - if (t === 'failure') { - t = '' - // eslint-disable-next-line no-labels - break substep - } - - t = serializeAMimeType(t).toLowerCase() - } - - // 3. If the lastModified member is provided, let d be set to the - // lastModified dictionary member. If it is not provided, set d to the - // current date and time represented as the number of milliseconds since - // the Unix Epoch (which is the equivalent of Date.now() [ECMA-262]). - d = options.lastModified - } - - // 4. Return a new File object F such that: - // F refers to the bytes byte sequence. - // F.size is set to the number of total bytes in bytes. - // F.name is set to n. - // F.type is set to t. - // F.lastModified is set to d. - - super(processBlobParts(fileBits, options), { type: t }) - this[kState] = { - name: n, - lastModified: d, - type: t - } - } - - get name () { - webidl.brandCheck(this, File) - - return this[kState].name - } - - get lastModified () { - webidl.brandCheck(this, File) - - return this[kState].lastModified - } - - get type () { - webidl.brandCheck(this, File) - - return this[kState].type - } -} - -class FileLike { - constructor (blobLike, fileName, options = {}) { - // TODO: argument idl type check - - // The File constructor is invoked with two or three parameters, depending - // on whether the optional dictionary parameter is used. When the File() - // constructor is invoked, user agents must run the following steps: - - // 1. Let bytes be the result of processing blob parts given fileBits and - // options. - - // 2. Let n be the fileName argument to the constructor. - const n = fileName - - // 3. Process FilePropertyBag dictionary argument by running the following - // substeps: - - // 1. If the type member is provided and is not the empty string, let t - // be set to the type dictionary member. If t contains any characters - // outside the range U+0020 to U+007E, then set t to the empty string - // and return from these substeps. - // TODO - const t = options.type - - // 2. Convert every character in t to ASCII lowercase. - // TODO - - // 3. If the lastModified member is provided, let d be set to the - // lastModified dictionary member. If it is not provided, set d to the - // current date and time represented as the number of milliseconds since - // the Unix Epoch (which is the equivalent of Date.now() [ECMA-262]). - const d = options.lastModified ?? Date.now() - - // 4. Return a new File object F such that: - // F refers to the bytes byte sequence. - // F.size is set to the number of total bytes in bytes. - // F.name is set to n. - // F.type is set to t. - // F.lastModified is set to d. - - this[kState] = { - blobLike, - name: n, - type: t, - lastModified: d - } - } - - stream (...args) { - webidl.brandCheck(this, FileLike) - - return this[kState].blobLike.stream(...args) - } - - arrayBuffer (...args) { - webidl.brandCheck(this, FileLike) - - return this[kState].blobLike.arrayBuffer(...args) - } - - slice (...args) { - webidl.brandCheck(this, FileLike) - - return this[kState].blobLike.slice(...args) - } - - text (...args) { - webidl.brandCheck(this, FileLike) - - return this[kState].blobLike.text(...args) - } - - get size () { - webidl.brandCheck(this, FileLike) - - return this[kState].blobLike.size - } - - get type () { - webidl.brandCheck(this, FileLike) - - return this[kState].blobLike.type - } - - get name () { - webidl.brandCheck(this, FileLike) - - return this[kState].name - } - - get lastModified () { - webidl.brandCheck(this, FileLike) - - return this[kState].lastModified - } - - get [Symbol.toStringTag] () { - return 'File' - } -} - -Object.defineProperties(File.prototype, { - [Symbol.toStringTag]: { - value: 'File', - configurable: true - }, - name: kEnumerableProperty, - lastModified: kEnumerableProperty -}) - -webidl.converters.Blob = webidl.interfaceConverter(Blob) - -webidl.converters.BlobPart = function (V, opts) { - if (webidl.util.Type(V) === 'Object') { - if (isBlobLike(V)) { - return webidl.converters.Blob(V, { strict: false }) - } - - if ( - ArrayBuffer.isView(V) || - types.isAnyArrayBuffer(V) - ) { - return webidl.converters.BufferSource(V, opts) - } - } - - return webidl.converters.USVString(V, opts) -} - -webidl.converters['sequence<BlobPart>'] = webidl.sequenceConverter( - webidl.converters.BlobPart -) - -// https://www.w3.org/TR/FileAPI/#dfn-FilePropertyBag -webidl.converters.FilePropertyBag = webidl.dictionaryConverter([ - { - key: 'lastModified', - converter: webidl.converters['long long'], - get defaultValue () { - return Date.now() - } - }, - { - key: 'type', - converter: webidl.converters.DOMString, - defaultValue: '' - }, - { - key: 'endings', - converter: (value) => { - value = webidl.converters.DOMString(value) - value = value.toLowerCase() - - if (value !== 'native') { - value = 'transparent' - } - - return value - }, - defaultValue: 'transparent' - } -]) - -/** - * @see https://www.w3.org/TR/FileAPI/#process-blob-parts - * @param {(NodeJS.TypedArray|Blob|string)[]} parts - * @param {{ type: string, endings: string }} options - */ -function processBlobParts (parts, options) { - // 1. Let bytes be an empty sequence of bytes. - /** @type {NodeJS.TypedArray[]} */ - const bytes = [] - - // 2. For each element in parts: - for (const element of parts) { - // 1. If element is a USVString, run the following substeps: - if (typeof element === 'string') { - // 1. Let s be element. - let s = element - - // 2. If the endings member of options is "native", set s - // to the result of converting line endings to native - // of element. - if (options.endings === 'native') { - s = convertLineEndingsNative(s) - } - - // 3. Append the result of UTF-8 encoding s to bytes. - bytes.push(encoder.encode(s)) - } else if ( - types.isAnyArrayBuffer(element) || - types.isTypedArray(element) - ) { - // 2. If element is a BufferSource, get a copy of the - // bytes held by the buffer source, and append those - // bytes to bytes. - if (!element.buffer) { // ArrayBuffer - bytes.push(new Uint8Array(element)) - } else { - bytes.push( - new Uint8Array(element.buffer, element.byteOffset, element.byteLength) - ) - } - } else if (isBlobLike(element)) { - // 3. If element is a Blob, append the bytes it represents - // to bytes. - bytes.push(element) - } - } - - // 3. Return bytes. - return bytes -} - -/** - * @see https://www.w3.org/TR/FileAPI/#convert-line-endings-to-native - * @param {string} s - */ -function convertLineEndingsNative (s) { - // 1. Let native line ending be be the code point U+000A LF. - let nativeLineEnding = '\n' - - // 2. If the underlying platform’s conventions are to - // represent newlines as a carriage return and line feed - // sequence, set native line ending to the code point - // U+000D CR followed by the code point U+000A LF. - if (process.platform === 'win32') { - nativeLineEnding = '\r\n' - } - - return s.replace(/\r?\n/g, nativeLineEnding) -} - -// If this function is moved to ./util.js, some tools (such as -// rollup) will warn about circular dependencies. See: -// https://github.com/nodejs/undici/issues/1629 -function isFileLike (object) { - return ( - (NativeFile && object instanceof NativeFile) || - object instanceof File || ( - object && - (typeof object.stream === 'function' || - typeof object.arrayBuffer === 'function') && - object[Symbol.toStringTag] === 'File' - ) - ) -} - -module.exports = { File, FileLike, isFileLike } - - -/***/ }), - -/***/ 4595: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { isBlobLike, toUSVString, makeIterator } = __nccwpck_require__(6913) -const { kState } = __nccwpck_require__(1048) -const { File: UndiciFile, FileLike, isFileLike } = __nccwpck_require__(9072) -const { webidl } = __nccwpck_require__(5337) -const { Blob, File: NativeFile } = __nccwpck_require__(4300) - -/** @type {globalThis['File']} */ -const File = NativeFile ?? UndiciFile - -// https://xhr.spec.whatwg.org/#formdata -class FormData { - constructor (form) { - if (form !== undefined) { - throw webidl.errors.conversionFailed({ - prefix: 'FormData constructor', - argument: 'Argument 1', - types: ['undefined'] - }) - } - - this[kState] = [] - } - - append (name, value, filename = undefined) { - webidl.brandCheck(this, FormData) - - webidl.argumentLengthCheck(arguments, 2, { header: 'FormData.append' }) - - if (arguments.length === 3 && !isBlobLike(value)) { - throw new TypeError( - "Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'" - ) - } - - // 1. Let value be value if given; otherwise blobValue. - - name = webidl.converters.USVString(name) - value = isBlobLike(value) - ? webidl.converters.Blob(value, { strict: false }) - : webidl.converters.USVString(value) - filename = arguments.length === 3 - ? webidl.converters.USVString(filename) - : undefined - - // 2. Let entry be the result of creating an entry with - // name, value, and filename if given. - const entry = makeEntry(name, value, filename) - - // 3. Append entry to this’s entry list. - this[kState].push(entry) - } - - delete (name) { - webidl.brandCheck(this, FormData) - - webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.delete' }) - - name = webidl.converters.USVString(name) - - // The delete(name) method steps are to remove all entries whose name - // is name from this’s entry list. - this[kState] = this[kState].filter(entry => entry.name !== name) - } - - get (name) { - webidl.brandCheck(this, FormData) - - webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.get' }) - - name = webidl.converters.USVString(name) - - // 1. If there is no entry whose name is name in this’s entry list, - // then return null. - const idx = this[kState].findIndex((entry) => entry.name === name) - if (idx === -1) { - return null - } - - // 2. Return the value of the first entry whose name is name from - // this’s entry list. - return this[kState][idx].value - } - - getAll (name) { - webidl.brandCheck(this, FormData) - - webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.getAll' }) - - name = webidl.converters.USVString(name) - - // 1. If there is no entry whose name is name in this’s entry list, - // then return the empty list. - // 2. Return the values of all entries whose name is name, in order, - // from this’s entry list. - return this[kState] - .filter((entry) => entry.name === name) - .map((entry) => entry.value) - } - - has (name) { - webidl.brandCheck(this, FormData) - - webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.has' }) - - name = webidl.converters.USVString(name) - - // The has(name) method steps are to return true if there is an entry - // whose name is name in this’s entry list; otherwise false. - return this[kState].findIndex((entry) => entry.name === name) !== -1 - } - - set (name, value, filename = undefined) { - webidl.brandCheck(this, FormData) - - webidl.argumentLengthCheck(arguments, 2, { header: 'FormData.set' }) - - if (arguments.length === 3 && !isBlobLike(value)) { - throw new TypeError( - "Failed to execute 'set' on 'FormData': parameter 2 is not of type 'Blob'" - ) - } - - // The set(name, value) and set(name, blobValue, filename) method steps - // are: - - // 1. Let value be value if given; otherwise blobValue. - - name = webidl.converters.USVString(name) - value = isBlobLike(value) - ? webidl.converters.Blob(value, { strict: false }) - : webidl.converters.USVString(value) - filename = arguments.length === 3 - ? toUSVString(filename) - : undefined - - // 2. Let entry be the result of creating an entry with name, value, and - // filename if given. - const entry = makeEntry(name, value, filename) - - // 3. If there are entries in this’s entry list whose name is name, then - // replace the first such entry with entry and remove the others. - const idx = this[kState].findIndex((entry) => entry.name === name) - if (idx !== -1) { - this[kState] = [ - ...this[kState].slice(0, idx), - entry, - ...this[kState].slice(idx + 1).filter((entry) => entry.name !== name) - ] - } else { - // 4. Otherwise, append entry to this’s entry list. - this[kState].push(entry) - } - } - - entries () { - webidl.brandCheck(this, FormData) - - return makeIterator( - () => this[kState].map(pair => [pair.name, pair.value]), - 'FormData', - 'key+value' - ) - } - - keys () { - webidl.brandCheck(this, FormData) - - return makeIterator( - () => this[kState].map(pair => [pair.name, pair.value]), - 'FormData', - 'key' - ) - } - - values () { - webidl.brandCheck(this, FormData) - - return makeIterator( - () => this[kState].map(pair => [pair.name, pair.value]), - 'FormData', - 'value' - ) - } - - /** - * @param {(value: string, key: string, self: FormData) => void} callbackFn - * @param {unknown} thisArg - */ - forEach (callbackFn, thisArg = globalThis) { - webidl.brandCheck(this, FormData) - - webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.forEach' }) - - if (typeof callbackFn !== 'function') { - throw new TypeError( - "Failed to execute 'forEach' on 'FormData': parameter 1 is not of type 'Function'." - ) - } - - for (const [key, value] of this) { - callbackFn.apply(thisArg, [value, key, this]) - } - } -} - -FormData.prototype[Symbol.iterator] = FormData.prototype.entries - -Object.defineProperties(FormData.prototype, { - [Symbol.toStringTag]: { - value: 'FormData', - configurable: true - } -}) - -/** - * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#create-an-entry - * @param {string} name - * @param {string|Blob} value - * @param {?string} filename - * @returns - */ -function makeEntry (name, value, filename) { - // 1. Set name to the result of converting name into a scalar value string. - // "To convert a string into a scalar value string, replace any surrogates - // with U+FFFD." - // see: https://nodejs.org/dist/latest-v18.x/docs/api/buffer.html#buftostringencoding-start-end - name = Buffer.from(name).toString('utf8') - - // 2. If value is a string, then set value to the result of converting - // value into a scalar value string. - if (typeof value === 'string') { - value = Buffer.from(value).toString('utf8') - } else { - // 3. Otherwise: - - // 1. If value is not a File object, then set value to a new File object, - // representing the same bytes, whose name attribute value is "blob" - if (!isFileLike(value)) { - value = value instanceof Blob - ? new File([value], 'blob', { type: value.type }) - : new FileLike(value, 'blob', { type: value.type }) - } - - // 2. If filename is given, then set value to a new File object, - // representing the same bytes, whose name attribute is filename. - if (filename !== undefined) { - /** @type {FilePropertyBag} */ - const options = { - type: value.type, - lastModified: value.lastModified - } - - value = (NativeFile && value instanceof NativeFile) || value instanceof UndiciFile - ? new File([value], filename, options) - : new FileLike(value, filename, options) - } - } - - // 4. Return an entry whose name is name and whose value is value. - return { name, value } -} - -module.exports = { FormData } - - -/***/ }), - -/***/ 4428: -/***/ ((module) => { - -"use strict"; - - -// In case of breaking changes, increase the version -// number to avoid conflicts. -const globalOrigin = Symbol.for('undici.globalOrigin.1') - -function getGlobalOrigin () { - return globalThis[globalOrigin] -} - -function setGlobalOrigin (newOrigin) { - if (newOrigin === undefined) { - Object.defineProperty(globalThis, globalOrigin, { - value: undefined, - writable: true, - enumerable: false, - configurable: false - }) - - return - } - - const parsedURL = new URL(newOrigin) - - if (parsedURL.protocol !== 'http:' && parsedURL.protocol !== 'https:') { - throw new TypeError(`Only http & https urls are allowed, received ${parsedURL.protocol}`) - } - - Object.defineProperty(globalThis, globalOrigin, { - value: parsedURL, - writable: true, - enumerable: false, - configurable: false - }) -} - -module.exports = { - getGlobalOrigin, - setGlobalOrigin -} - - -/***/ }), - -/***/ 7967: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// https://github.com/Ethan-Arrowood/undici-fetch - - - -const { kHeadersList } = __nccwpck_require__(1439) -const { kGuard } = __nccwpck_require__(1048) -const { kEnumerableProperty } = __nccwpck_require__(6223) -const { - makeIterator, - isValidHeaderName, - isValidHeaderValue -} = __nccwpck_require__(6913) -const { webidl } = __nccwpck_require__(5337) -const assert = __nccwpck_require__(9491) - -const kHeadersMap = Symbol('headers map') -const kHeadersSortedMap = Symbol('headers map sorted') - -/** - * @see https://fetch.spec.whatwg.org/#concept-header-value-normalize - * @param {string} potentialValue - */ -function headerValueNormalize (potentialValue) { - // To normalize a byte sequence potentialValue, remove - // any leading and trailing HTTP whitespace bytes from - // potentialValue. - - // Trimming the end with `.replace()` and a RegExp is typically subject to - // ReDoS. This is safer and faster. - let i = potentialValue.length - while (/[\r\n\t ]/.test(potentialValue.charAt(--i))); - return potentialValue.slice(0, i + 1).replace(/^[\r\n\t ]+/, '') -} - -function fill (headers, object) { - // To fill a Headers object headers with a given object object, run these steps: - - // 1. If object is a sequence, then for each header in object: - // Note: webidl conversion to array has already been done. - if (Array.isArray(object)) { - for (const header of object) { - // 1. If header does not contain exactly two items, then throw a TypeError. - if (header.length !== 2) { - throw webidl.errors.exception({ - header: 'Headers constructor', - message: `expected name/value pair to be length 2, found ${header.length}.` - }) - } - - // 2. Append (header’s first item, header’s second item) to headers. - headers.append(header[0], header[1]) - } - } else if (typeof object === 'object' && object !== null) { - // Note: null should throw - - // 2. Otherwise, object is a record, then for each key → value in object, - // append (key, value) to headers - for (const [key, value] of Object.entries(object)) { - headers.append(key, value) - } - } else { - throw webidl.errors.conversionFailed({ - prefix: 'Headers constructor', - argument: 'Argument 1', - types: ['sequence<sequence<ByteString>>', 'record<ByteString, ByteString>'] - }) - } -} - -class HeadersList { - /** @type {[string, string][]|null} */ - cookies = null - - constructor (init) { - if (init instanceof HeadersList) { - this[kHeadersMap] = new Map(init[kHeadersMap]) - this[kHeadersSortedMap] = init[kHeadersSortedMap] - this.cookies = init.cookies - } else { - this[kHeadersMap] = new Map(init) - this[kHeadersSortedMap] = null - } - } - - // https://fetch.spec.whatwg.org/#header-list-contains - contains (name) { - // A header list list contains a header name name if list - // contains a header whose name is a byte-case-insensitive - // match for name. - name = name.toLowerCase() - - return this[kHeadersMap].has(name) - } - - clear () { - this[kHeadersMap].clear() - this[kHeadersSortedMap] = null - this.cookies = null - } - - // https://fetch.spec.whatwg.org/#concept-header-list-append - append (name, value) { - this[kHeadersSortedMap] = null - - // 1. If list contains name, then set name to the first such - // header’s name. - const lowercaseName = name.toLowerCase() - const exists = this[kHeadersMap].get(lowercaseName) - - // 2. Append (name, value) to list. - if (exists) { - const delimiter = lowercaseName === 'cookie' ? '; ' : ', ' - this[kHeadersMap].set(lowercaseName, { - name: exists.name, - value: `${exists.value}${delimiter}${value}` - }) - } else { - this[kHeadersMap].set(lowercaseName, { name, value }) - } - - if (lowercaseName === 'set-cookie') { - this.cookies ??= [] - this.cookies.push(value) - } - } - - // https://fetch.spec.whatwg.org/#concept-header-list-set - set (name, value) { - this[kHeadersSortedMap] = null - const lowercaseName = name.toLowerCase() - - if (lowercaseName === 'set-cookie') { - this.cookies = [value] - } - - // 1. If list contains name, then set the value of - // the first such header to value and remove the - // others. - // 2. Otherwise, append header (name, value) to list. - return this[kHeadersMap].set(lowercaseName, { name, value }) - } - - // https://fetch.spec.whatwg.org/#concept-header-list-delete - delete (name) { - this[kHeadersSortedMap] = null - - name = name.toLowerCase() - - if (name === 'set-cookie') { - this.cookies = null - } - - return this[kHeadersMap].delete(name) - } - - // https://fetch.spec.whatwg.org/#concept-header-list-get - get (name) { - // 1. If list does not contain name, then return null. - if (!this.contains(name)) { - return null - } - - // 2. Return the values of all headers in list whose name - // is a byte-case-insensitive match for name, - // separated from each other by 0x2C 0x20, in order. - return this[kHeadersMap].get(name.toLowerCase())?.value ?? null - } - - * [Symbol.iterator] () { - // use the lowercased name - for (const [name, { value }] of this[kHeadersMap]) { - yield [name, value] - } - } - - get entries () { - const headers = {} - - if (this[kHeadersMap].size) { - for (const { name, value } of this[kHeadersMap].values()) { - headers[name] = value - } - } - - return headers - } -} - -// https://fetch.spec.whatwg.org/#headers-class -class Headers { - constructor (init = undefined) { - this[kHeadersList] = new HeadersList() - - // The new Headers(init) constructor steps are: - - // 1. Set this’s guard to "none". - this[kGuard] = 'none' - - // 2. If init is given, then fill this with init. - if (init !== undefined) { - init = webidl.converters.HeadersInit(init) - fill(this, init) - } - } - - // https://fetch.spec.whatwg.org/#dom-headers-append - append (name, value) { - webidl.brandCheck(this, Headers) - - webidl.argumentLengthCheck(arguments, 2, { header: 'Headers.append' }) - - name = webidl.converters.ByteString(name) - value = webidl.converters.ByteString(value) - - // 1. Normalize value. - value = headerValueNormalize(value) - - // 2. If name is not a header name or value is not a - // header value, then throw a TypeError. - if (!isValidHeaderName(name)) { - throw webidl.errors.invalidArgument({ - prefix: 'Headers.append', - value: name, - type: 'header name' - }) - } else if (!isValidHeaderValue(value)) { - throw webidl.errors.invalidArgument({ - prefix: 'Headers.append', - value, - type: 'header value' - }) - } - - // 3. If headers’s guard is "immutable", then throw a TypeError. - // 4. Otherwise, if headers’s guard is "request" and name is a - // forbidden header name, return. - // Note: undici does not implement forbidden header names - if (this[kGuard] === 'immutable') { - throw new TypeError('immutable') - } else if (this[kGuard] === 'request-no-cors') { - // 5. Otherwise, if headers’s guard is "request-no-cors": - // TODO - } - - // 6. Otherwise, if headers’s guard is "response" and name is a - // forbidden response-header name, return. - - // 7. Append (name, value) to headers’s header list. - // 8. If headers’s guard is "request-no-cors", then remove - // privileged no-CORS request headers from headers - return this[kHeadersList].append(name, value) - } - - // https://fetch.spec.whatwg.org/#dom-headers-delete - delete (name) { - webidl.brandCheck(this, Headers) - - webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.delete' }) - - name = webidl.converters.ByteString(name) - - // 1. If name is not a header name, then throw a TypeError. - if (!isValidHeaderName(name)) { - throw webidl.errors.invalidArgument({ - prefix: 'Headers.delete', - value: name, - type: 'header name' - }) - } - - // 2. If this’s guard is "immutable", then throw a TypeError. - // 3. Otherwise, if this’s guard is "request" and name is a - // forbidden header name, return. - // 4. Otherwise, if this’s guard is "request-no-cors", name - // is not a no-CORS-safelisted request-header name, and - // name is not a privileged no-CORS request-header name, - // return. - // 5. Otherwise, if this’s guard is "response" and name is - // a forbidden response-header name, return. - // Note: undici does not implement forbidden header names - if (this[kGuard] === 'immutable') { - throw new TypeError('immutable') - } else if (this[kGuard] === 'request-no-cors') { - // TODO - } - - // 6. If this’s header list does not contain name, then - // return. - if (!this[kHeadersList].contains(name)) { - return - } - - // 7. Delete name from this’s header list. - // 8. If this’s guard is "request-no-cors", then remove - // privileged no-CORS request headers from this. - return this[kHeadersList].delete(name) - } - - // https://fetch.spec.whatwg.org/#dom-headers-get - get (name) { - webidl.brandCheck(this, Headers) - - webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.get' }) - - name = webidl.converters.ByteString(name) - - // 1. If name is not a header name, then throw a TypeError. - if (!isValidHeaderName(name)) { - throw webidl.errors.invalidArgument({ - prefix: 'Headers.get', - value: name, - type: 'header name' - }) - } - - // 2. Return the result of getting name from this’s header - // list. - return this[kHeadersList].get(name) - } - - // https://fetch.spec.whatwg.org/#dom-headers-has - has (name) { - webidl.brandCheck(this, Headers) - - webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.has' }) - - name = webidl.converters.ByteString(name) - - // 1. If name is not a header name, then throw a TypeError. - if (!isValidHeaderName(name)) { - throw webidl.errors.invalidArgument({ - prefix: 'Headers.has', - value: name, - type: 'header name' - }) - } - - // 2. Return true if this’s header list contains name; - // otherwise false. - return this[kHeadersList].contains(name) - } - - // https://fetch.spec.whatwg.org/#dom-headers-set - set (name, value) { - webidl.brandCheck(this, Headers) - - webidl.argumentLengthCheck(arguments, 2, { header: 'Headers.set' }) - - name = webidl.converters.ByteString(name) - value = webidl.converters.ByteString(value) - - // 1. Normalize value. - value = headerValueNormalize(value) - - // 2. If name is not a header name or value is not a - // header value, then throw a TypeError. - if (!isValidHeaderName(name)) { - throw webidl.errors.invalidArgument({ - prefix: 'Headers.set', - value: name, - type: 'header name' - }) - } else if (!isValidHeaderValue(value)) { - throw webidl.errors.invalidArgument({ - prefix: 'Headers.set', - value, - type: 'header value' - }) - } - - // 3. If this’s guard is "immutable", then throw a TypeError. - // 4. Otherwise, if this’s guard is "request" and name is a - // forbidden header name, return. - // 5. Otherwise, if this’s guard is "request-no-cors" and - // name/value is not a no-CORS-safelisted request-header, - // return. - // 6. Otherwise, if this’s guard is "response" and name is a - // forbidden response-header name, return. - // Note: undici does not implement forbidden header names - if (this[kGuard] === 'immutable') { - throw new TypeError('immutable') - } else if (this[kGuard] === 'request-no-cors') { - // TODO - } - - // 7. Set (name, value) in this’s header list. - // 8. If this’s guard is "request-no-cors", then remove - // privileged no-CORS request headers from this - return this[kHeadersList].set(name, value) - } - - // https://fetch.spec.whatwg.org/#dom-headers-getsetcookie - getSetCookie () { - webidl.brandCheck(this, Headers) - - // 1. If this’s header list does not contain `Set-Cookie`, then return « ». - // 2. Return the values of all headers in this’s header list whose name is - // a byte-case-insensitive match for `Set-Cookie`, in order. - - const list = this[kHeadersList].cookies - - if (list) { - return [...list] - } - - return [] - } - - // https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine - get [kHeadersSortedMap] () { - if (this[kHeadersList][kHeadersSortedMap]) { - return this[kHeadersList][kHeadersSortedMap] - } - - // 1. Let headers be an empty list of headers with the key being the name - // and value the value. - const headers = [] - - // 2. Let names be the result of convert header names to a sorted-lowercase - // set with all the names of the headers in list. - const names = [...this[kHeadersList]].sort((a, b) => a[0] < b[0] ? -1 : 1) - const cookies = this[kHeadersList].cookies - - // 3. For each name of names: - for (const [name, value] of names) { - // 1. If name is `set-cookie`, then: - if (name === 'set-cookie') { - // 1. Let values be a list of all values of headers in list whose name - // is a byte-case-insensitive match for name, in order. - - // 2. For each value of values: - // 1. Append (name, value) to headers. - for (const value of cookies) { - headers.push([name, value]) - } - } else { - // 2. Otherwise: - - // 1. Let value be the result of getting name from list. - - // 2. Assert: value is non-null. - assert(value !== null) - - // 3. Append (name, value) to headers. - headers.push([name, value]) - } - } - - this[kHeadersList][kHeadersSortedMap] = headers - - // 4. Return headers. - return headers - } - - keys () { - webidl.brandCheck(this, Headers) - - return makeIterator( - () => [...this[kHeadersSortedMap].values()], - 'Headers', - 'key' - ) - } - - values () { - webidl.brandCheck(this, Headers) - - return makeIterator( - () => [...this[kHeadersSortedMap].values()], - 'Headers', - 'value' - ) - } - - entries () { - webidl.brandCheck(this, Headers) - - return makeIterator( - () => [...this[kHeadersSortedMap].values()], - 'Headers', - 'key+value' - ) - } - - /** - * @param {(value: string, key: string, self: Headers) => void} callbackFn - * @param {unknown} thisArg - */ - forEach (callbackFn, thisArg = globalThis) { - webidl.brandCheck(this, Headers) - - webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.forEach' }) - - if (typeof callbackFn !== 'function') { - throw new TypeError( - "Failed to execute 'forEach' on 'Headers': parameter 1 is not of type 'Function'." - ) - } - - for (const [key, value] of this) { - callbackFn.apply(thisArg, [value, key, this]) - } - } - - [Symbol.for('nodejs.util.inspect.custom')] () { - webidl.brandCheck(this, Headers) - - return this[kHeadersList] - } -} - -Headers.prototype[Symbol.iterator] = Headers.prototype.entries - -Object.defineProperties(Headers.prototype, { - append: kEnumerableProperty, - delete: kEnumerableProperty, - get: kEnumerableProperty, - has: kEnumerableProperty, - set: kEnumerableProperty, - getSetCookie: kEnumerableProperty, - keys: kEnumerableProperty, - values: kEnumerableProperty, - entries: kEnumerableProperty, - forEach: kEnumerableProperty, - [Symbol.iterator]: { enumerable: false }, - [Symbol.toStringTag]: { - value: 'Headers', - configurable: true - } -}) - -webidl.converters.HeadersInit = function (V) { - if (webidl.util.Type(V) === 'Object') { - if (V[Symbol.iterator]) { - return webidl.converters['sequence<sequence<ByteString>>'](V) - } - - return webidl.converters['record<ByteString, ByteString>'](V) - } - - throw webidl.errors.conversionFailed({ - prefix: 'Headers constructor', - argument: 'Argument 1', - types: ['sequence<sequence<ByteString>>', 'record<ByteString, ByteString>'] - }) -} - -module.exports = { - fill, - Headers, - HeadersList -} - - -/***/ }), - -/***/ 3360: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// https://github.com/Ethan-Arrowood/undici-fetch - - - -const { - Response, - makeNetworkError, - makeAppropriateNetworkError, - filterResponse, - makeResponse -} = __nccwpck_require__(1570) -const { Headers } = __nccwpck_require__(7967) -const { Request, makeRequest } = __nccwpck_require__(8619) -const zlib = __nccwpck_require__(9796) -const { - bytesMatch, - makePolicyContainer, - clonePolicyContainer, - requestBadPort, - TAOCheck, - appendRequestOriginHeader, - responseLocationURL, - requestCurrentURL, - setRequestReferrerPolicyOnRedirect, - tryUpgradeRequestToAPotentiallyTrustworthyURL, - createOpaqueTimingInfo, - appendFetchMetadata, - corsCheck, - crossOriginResourcePolicyCheck, - determineRequestsReferrer, - coarsenedSharedCurrentTime, - createDeferredPromise, - isBlobLike, - sameOrigin, - isCancelled, - isAborted, - isErrorLike, - fullyReadBody, - readableStreamClose, - isomorphicEncode, - urlIsLocal, - urlIsHttpHttpsScheme, - urlHasHttpsScheme -} = __nccwpck_require__(6913) -const { kState, kHeaders, kGuard, kRealm } = __nccwpck_require__(1048) -const assert = __nccwpck_require__(9491) -const { safelyExtractBody } = __nccwpck_require__(6770) -const { - redirectStatusSet, - nullBodyStatus, - safeMethodsSet, - requestBodyHeader, - subresourceSet, - DOMException -} = __nccwpck_require__(7213) -const { kHeadersList } = __nccwpck_require__(1439) -const EE = __nccwpck_require__(2361) -const { Readable, pipeline } = __nccwpck_require__(2781) -const { addAbortListener, isErrored, isReadable, nodeMajor, nodeMinor } = __nccwpck_require__(6223) -const { dataURLProcessor, serializeAMimeType } = __nccwpck_require__(6822) -const { TransformStream } = __nccwpck_require__(5356) -const { getGlobalDispatcher } = __nccwpck_require__(398) -const { webidl } = __nccwpck_require__(5337) -const { STATUS_CODES } = __nccwpck_require__(3685) -const GET_OR_HEAD = ['GET', 'HEAD'] - -/** @type {import('buffer').resolveObjectURL} */ -let resolveObjectURL -let ReadableStream = globalThis.ReadableStream - -class Fetch extends EE { - constructor (dispatcher) { - super() - - this.dispatcher = dispatcher - this.connection = null - this.dump = false - this.state = 'ongoing' - // 2 terminated listeners get added per request, - // but only 1 gets removed. If there are 20 redirects, - // 21 listeners will be added. - // See https://github.com/nodejs/undici/issues/1711 - // TODO (fix): Find and fix root cause for leaked listener. - this.setMaxListeners(21) - } - - terminate (reason) { - if (this.state !== 'ongoing') { - return - } - - this.state = 'terminated' - this.connection?.destroy(reason) - this.emit('terminated', reason) - } - - // https://fetch.spec.whatwg.org/#fetch-controller-abort - abort (error) { - if (this.state !== 'ongoing') { - return - } - - // 1. Set controller’s state to "aborted". - this.state = 'aborted' - - // 2. Let fallbackError be an "AbortError" DOMException. - // 3. Set error to fallbackError if it is not given. - if (!error) { - error = new DOMException('The operation was aborted.', 'AbortError') - } - - // 4. Let serializedError be StructuredSerialize(error). - // If that threw an exception, catch it, and let - // serializedError be StructuredSerialize(fallbackError). - - // 5. Set controller’s serialized abort reason to serializedError. - this.serializedAbortReason = error - - this.connection?.destroy(error) - this.emit('terminated', error) - } -} - -// https://fetch.spec.whatwg.org/#fetch-method -function fetch (input, init = {}) { - webidl.argumentLengthCheck(arguments, 1, { header: 'globalThis.fetch' }) - - // 1. Let p be a new promise. - const p = createDeferredPromise() - - // 2. Let requestObject be the result of invoking the initial value of - // Request as constructor with input and init as arguments. If this throws - // an exception, reject p with it and return p. - let requestObject - - try { - requestObject = new Request(input, init) - } catch (e) { - p.reject(e) - return p.promise - } - - // 3. Let request be requestObject’s request. - const request = requestObject[kState] - - // 4. If requestObject’s signal’s aborted flag is set, then: - if (requestObject.signal.aborted) { - // 1. Abort the fetch() call with p, request, null, and - // requestObject’s signal’s abort reason. - abortFetch(p, request, null, requestObject.signal.reason) - - // 2. Return p. - return p.promise - } - - // 5. Let globalObject be request’s client’s global object. - const globalObject = request.client.globalObject - - // 6. If globalObject is a ServiceWorkerGlobalScope object, then set - // request’s service-workers mode to "none". - if (globalObject?.constructor?.name === 'ServiceWorkerGlobalScope') { - request.serviceWorkers = 'none' - } - - // 7. Let responseObject be null. - let responseObject = null - - // 8. Let relevantRealm be this’s relevant Realm. - const relevantRealm = null - - // 9. Let locallyAborted be false. - let locallyAborted = false - - // 10. Let controller be null. - let controller = null - - // 11. Add the following abort steps to requestObject’s signal: - addAbortListener( - requestObject.signal, - () => { - // 1. Set locallyAborted to true. - locallyAborted = true - - // 2. Assert: controller is non-null. - assert(controller != null) - - // 3. Abort controller with requestObject’s signal’s abort reason. - controller.abort(requestObject.signal.reason) - - // 4. Abort the fetch() call with p, request, responseObject, - // and requestObject’s signal’s abort reason. - abortFetch(p, request, responseObject, requestObject.signal.reason) - } - ) - - // 12. Let handleFetchDone given response response be to finalize and - // report timing with response, globalObject, and "fetch". - const handleFetchDone = (response) => - finalizeAndReportTiming(response, 'fetch') - - // 13. Set controller to the result of calling fetch given request, - // with processResponseEndOfBody set to handleFetchDone, and processResponse - // given response being these substeps: - - const processResponse = (response) => { - // 1. If locallyAborted is true, terminate these substeps. - if (locallyAborted) { - return Promise.resolve() - } - - // 2. If response’s aborted flag is set, then: - if (response.aborted) { - // 1. Let deserializedError be the result of deserialize a serialized - // abort reason given controller’s serialized abort reason and - // relevantRealm. - - // 2. Abort the fetch() call with p, request, responseObject, and - // deserializedError. - - abortFetch(p, request, responseObject, controller.serializedAbortReason) - return Promise.resolve() - } - - // 3. If response is a network error, then reject p with a TypeError - // and terminate these substeps. - if (response.type === 'error') { - p.reject( - Object.assign(new TypeError('fetch failed'), { cause: response.error }) - ) - return Promise.resolve() - } - - // 4. Set responseObject to the result of creating a Response object, - // given response, "immutable", and relevantRealm. - responseObject = new Response() - responseObject[kState] = response - responseObject[kRealm] = relevantRealm - responseObject[kHeaders][kHeadersList] = response.headersList - responseObject[kHeaders][kGuard] = 'immutable' - responseObject[kHeaders][kRealm] = relevantRealm - - // 5. Resolve p with responseObject. - p.resolve(responseObject) - } - - controller = fetching({ - request, - processResponseEndOfBody: handleFetchDone, - processResponse, - dispatcher: init.dispatcher ?? getGlobalDispatcher() // undici - }) - - // 14. Return p. - return p.promise -} - -// https://fetch.spec.whatwg.org/#finalize-and-report-timing -function finalizeAndReportTiming (response, initiatorType = 'other') { - // 1. If response is an aborted network error, then return. - if (response.type === 'error' && response.aborted) { - return - } - - // 2. If response’s URL list is null or empty, then return. - if (!response.urlList?.length) { - return - } - - // 3. Let originalURL be response’s URL list[0]. - const originalURL = response.urlList[0] - - // 4. Let timingInfo be response’s timing info. - let timingInfo = response.timingInfo - - // 5. Let cacheState be response’s cache state. - let cacheState = response.cacheState - - // 6. If originalURL’s scheme is not an HTTP(S) scheme, then return. - if (!urlIsHttpHttpsScheme(originalURL)) { - return - } - - // 7. If timingInfo is null, then return. - if (timingInfo === null) { - return - } - - // 8. If response’s timing allow passed flag is not set, then: - if (!timingInfo.timingAllowPassed) { - // 1. Set timingInfo to a the result of creating an opaque timing info for timingInfo. - timingInfo = createOpaqueTimingInfo({ - startTime: timingInfo.startTime - }) - - // 2. Set cacheState to the empty string. - cacheState = '' - } - - // 9. Set timingInfo’s end time to the coarsened shared current time - // given global’s relevant settings object’s cross-origin isolated - // capability. - // TODO: given global’s relevant settings object’s cross-origin isolated - // capability? - timingInfo.endTime = coarsenedSharedCurrentTime() - - // 10. Set response’s timing info to timingInfo. - response.timingInfo = timingInfo - - // 11. Mark resource timing for timingInfo, originalURL, initiatorType, - // global, and cacheState. - markResourceTiming( - timingInfo, - originalURL, - initiatorType, - globalThis, - cacheState - ) -} - -// https://w3c.github.io/resource-timing/#dfn-mark-resource-timing -function markResourceTiming (timingInfo, originalURL, initiatorType, globalThis, cacheState) { - if (nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 2)) { - performance.markResourceTiming(timingInfo, originalURL.href, initiatorType, globalThis, cacheState) - } -} - -// https://fetch.spec.whatwg.org/#abort-fetch -function abortFetch (p, request, responseObject, error) { - // Note: AbortSignal.reason was added in node v17.2.0 - // which would give us an undefined error to reject with. - // Remove this once node v16 is no longer supported. - if (!error) { - error = new DOMException('The operation was aborted.', 'AbortError') - } - - // 1. Reject promise with error. - p.reject(error) - - // 2. If request’s body is not null and is readable, then cancel request’s - // body with error. - if (request.body != null && isReadable(request.body?.stream)) { - request.body.stream.cancel(error).catch((err) => { - if (err.code === 'ERR_INVALID_STATE') { - // Node bug? - return - } - throw err - }) - } - - // 3. If responseObject is null, then return. - if (responseObject == null) { - return - } - - // 4. Let response be responseObject’s response. - const response = responseObject[kState] - - // 5. If response’s body is not null and is readable, then error response’s - // body with error. - if (response.body != null && isReadable(response.body?.stream)) { - response.body.stream.cancel(error).catch((err) => { - if (err.code === 'ERR_INVALID_STATE') { - // Node bug? - return - } - throw err - }) - } -} - -// https://fetch.spec.whatwg.org/#fetching -function fetching ({ - request, - processRequestBodyChunkLength, - processRequestEndOfBody, - processResponse, - processResponseEndOfBody, - processResponseConsumeBody, - useParallelQueue = false, - dispatcher // undici -}) { - // 1. Let taskDestination be null. - let taskDestination = null - - // 2. Let crossOriginIsolatedCapability be false. - let crossOriginIsolatedCapability = false - - // 3. If request’s client is non-null, then: - if (request.client != null) { - // 1. Set taskDestination to request’s client’s global object. - taskDestination = request.client.globalObject - - // 2. Set crossOriginIsolatedCapability to request’s client’s cross-origin - // isolated capability. - crossOriginIsolatedCapability = - request.client.crossOriginIsolatedCapability - } - - // 4. If useParallelQueue is true, then set taskDestination to the result of - // starting a new parallel queue. - // TODO - - // 5. Let timingInfo be a new fetch timing info whose start time and - // post-redirect start time are the coarsened shared current time given - // crossOriginIsolatedCapability. - const currenTime = coarsenedSharedCurrentTime(crossOriginIsolatedCapability) - const timingInfo = createOpaqueTimingInfo({ - startTime: currenTime - }) - - // 6. Let fetchParams be a new fetch params whose - // request is request, - // timing info is timingInfo, - // process request body chunk length is processRequestBodyChunkLength, - // process request end-of-body is processRequestEndOfBody, - // process response is processResponse, - // process response consume body is processResponseConsumeBody, - // process response end-of-body is processResponseEndOfBody, - // task destination is taskDestination, - // and cross-origin isolated capability is crossOriginIsolatedCapability. - const fetchParams = { - controller: new Fetch(dispatcher), - request, - timingInfo, - processRequestBodyChunkLength, - processRequestEndOfBody, - processResponse, - processResponseConsumeBody, - processResponseEndOfBody, - taskDestination, - crossOriginIsolatedCapability - } - - // 7. If request’s body is a byte sequence, then set request’s body to - // request’s body as a body. - // NOTE: Since fetching is only called from fetch, body should already be - // extracted. - assert(!request.body || request.body.stream) - - // 8. If request’s window is "client", then set request’s window to request’s - // client, if request’s client’s global object is a Window object; otherwise - // "no-window". - if (request.window === 'client') { - // TODO: What if request.client is null? - request.window = - request.client?.globalObject?.constructor?.name === 'Window' - ? request.client - : 'no-window' - } - - // 9. If request’s origin is "client", then set request’s origin to request’s - // client’s origin. - if (request.origin === 'client') { - // TODO: What if request.client is null? - request.origin = request.client?.origin - } - - // 10. If all of the following conditions are true: - // TODO - - // 11. If request’s policy container is "client", then: - if (request.policyContainer === 'client') { - // 1. If request’s client is non-null, then set request’s policy - // container to a clone of request’s client’s policy container. [HTML] - if (request.client != null) { - request.policyContainer = clonePolicyContainer( - request.client.policyContainer - ) - } else { - // 2. Otherwise, set request’s policy container to a new policy - // container. - request.policyContainer = makePolicyContainer() - } - } - - // 12. If request’s header list does not contain `Accept`, then: - if (!request.headersList.contains('accept')) { - // 1. Let value be `*/*`. - const value = '*/*' - - // 2. A user agent should set value to the first matching statement, if - // any, switching on request’s destination: - // "document" - // "frame" - // "iframe" - // `text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8` - // "image" - // `image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5` - // "style" - // `text/css,*/*;q=0.1` - // TODO - - // 3. Append `Accept`/value to request’s header list. - request.headersList.append('accept', value) - } - - // 13. If request’s header list does not contain `Accept-Language`, then - // user agents should append `Accept-Language`/an appropriate value to - // request’s header list. - if (!request.headersList.contains('accept-language')) { - request.headersList.append('accept-language', '*') - } - - // 14. If request’s priority is null, then use request’s initiator and - // destination appropriately in setting request’s priority to a - // user-agent-defined object. - if (request.priority === null) { - // TODO - } - - // 15. If request is a subresource request, then: - if (subresourceSet.has(request.destination)) { - // TODO - } - - // 16. Run main fetch given fetchParams. - mainFetch(fetchParams) - .catch(err => { - fetchParams.controller.terminate(err) - }) - - // 17. Return fetchParam's controller - return fetchParams.controller -} - -// https://fetch.spec.whatwg.org/#concept-main-fetch -async function mainFetch (fetchParams, recursive = false) { - // 1. Let request be fetchParams’s request. - const request = fetchParams.request - - // 2. Let response be null. - let response = null - - // 3. If request’s local-URLs-only flag is set and request’s current URL is - // not local, then set response to a network error. - if (request.localURLsOnly && !urlIsLocal(requestCurrentURL(request))) { - response = makeNetworkError('local URLs only') - } - - // 4. Run report Content Security Policy violations for request. - // TODO - - // 5. Upgrade request to a potentially trustworthy URL, if appropriate. - tryUpgradeRequestToAPotentiallyTrustworthyURL(request) - - // 6. If should request be blocked due to a bad port, should fetching request - // be blocked as mixed content, or should request be blocked by Content - // Security Policy returns blocked, then set response to a network error. - if (requestBadPort(request) === 'blocked') { - response = makeNetworkError('bad port') - } - // TODO: should fetching request be blocked as mixed content? - // TODO: should request be blocked by Content Security Policy? - - // 7. If request’s referrer policy is the empty string, then set request’s - // referrer policy to request’s policy container’s referrer policy. - if (request.referrerPolicy === '') { - request.referrerPolicy = request.policyContainer.referrerPolicy - } - - // 8. If request’s referrer is not "no-referrer", then set request’s - // referrer to the result of invoking determine request’s referrer. - if (request.referrer !== 'no-referrer') { - request.referrer = determineRequestsReferrer(request) - } - - // 9. Set request’s current URL’s scheme to "https" if all of the following - // conditions are true: - // - request’s current URL’s scheme is "http" - // - request’s current URL’s host is a domain - // - Matching request’s current URL’s host per Known HSTS Host Domain Name - // Matching results in either a superdomain match with an asserted - // includeSubDomains directive or a congruent match (with or without an - // asserted includeSubDomains directive). [HSTS] - // TODO - - // 10. If recursive is false, then run the remaining steps in parallel. - // TODO - - // 11. If response is null, then set response to the result of running - // the steps corresponding to the first matching statement: - if (response === null) { - response = await (async () => { - const currentURL = requestCurrentURL(request) - - if ( - // - request’s current URL’s origin is same origin with request’s origin, - // and request’s response tainting is "basic" - (sameOrigin(currentURL, request.url) && request.responseTainting === 'basic') || - // request’s current URL’s scheme is "data" - (currentURL.protocol === 'data:') || - // - request’s mode is "navigate" or "websocket" - (request.mode === 'navigate' || request.mode === 'websocket') - ) { - // 1. Set request’s response tainting to "basic". - request.responseTainting = 'basic' - - // 2. Return the result of running scheme fetch given fetchParams. - return await schemeFetch(fetchParams) - } - - // request’s mode is "same-origin" - if (request.mode === 'same-origin') { - // 1. Return a network error. - return makeNetworkError('request mode cannot be "same-origin"') - } - - // request’s mode is "no-cors" - if (request.mode === 'no-cors') { - // 1. If request’s redirect mode is not "follow", then return a network - // error. - if (request.redirect !== 'follow') { - return makeNetworkError( - 'redirect mode cannot be "follow" for "no-cors" request' - ) - } - - // 2. Set request’s response tainting to "opaque". - request.responseTainting = 'opaque' - - // 3. Return the result of running scheme fetch given fetchParams. - return await schemeFetch(fetchParams) - } - - // request’s current URL’s scheme is not an HTTP(S) scheme - if (!urlIsHttpHttpsScheme(requestCurrentURL(request))) { - // Return a network error. - return makeNetworkError('URL scheme must be a HTTP(S) scheme') - } - - // - request’s use-CORS-preflight flag is set - // - request’s unsafe-request flag is set and either request’s method is - // not a CORS-safelisted method or CORS-unsafe request-header names with - // request’s header list is not empty - // 1. Set request’s response tainting to "cors". - // 2. Let corsWithPreflightResponse be the result of running HTTP fetch - // given fetchParams and true. - // 3. If corsWithPreflightResponse is a network error, then clear cache - // entries using request. - // 4. Return corsWithPreflightResponse. - // TODO - - // Otherwise - // 1. Set request’s response tainting to "cors". - request.responseTainting = 'cors' - - // 2. Return the result of running HTTP fetch given fetchParams. - return await httpFetch(fetchParams) - })() - } - - // 12. If recursive is true, then return response. - if (recursive) { - return response - } - - // 13. If response is not a network error and response is not a filtered - // response, then: - if (response.status !== 0 && !response.internalResponse) { - // If request’s response tainting is "cors", then: - if (request.responseTainting === 'cors') { - // 1. Let headerNames be the result of extracting header list values - // given `Access-Control-Expose-Headers` and response’s header list. - // TODO - // 2. If request’s credentials mode is not "include" and headerNames - // contains `*`, then set response’s CORS-exposed header-name list to - // all unique header names in response’s header list. - // TODO - // 3. Otherwise, if headerNames is not null or failure, then set - // response’s CORS-exposed header-name list to headerNames. - // TODO - } - - // Set response to the following filtered response with response as its - // internal response, depending on request’s response tainting: - if (request.responseTainting === 'basic') { - response = filterResponse(response, 'basic') - } else if (request.responseTainting === 'cors') { - response = filterResponse(response, 'cors') - } else if (request.responseTainting === 'opaque') { - response = filterResponse(response, 'opaque') - } else { - assert(false) - } - } - - // 14. Let internalResponse be response, if response is a network error, - // and response’s internal response otherwise. - let internalResponse = - response.status === 0 ? response : response.internalResponse - - // 15. If internalResponse’s URL list is empty, then set it to a clone of - // request’s URL list. - if (internalResponse.urlList.length === 0) { - internalResponse.urlList.push(...request.urlList) - } - - // 16. If request’s timing allow failed flag is unset, then set - // internalResponse’s timing allow passed flag. - if (!request.timingAllowFailed) { - response.timingAllowPassed = true - } - - // 17. If response is not a network error and any of the following returns - // blocked - // - should internalResponse to request be blocked as mixed content - // - should internalResponse to request be blocked by Content Security Policy - // - should internalResponse to request be blocked due to its MIME type - // - should internalResponse to request be blocked due to nosniff - // TODO - - // 18. If response’s type is "opaque", internalResponse’s status is 206, - // internalResponse’s range-requested flag is set, and request’s header - // list does not contain `Range`, then set response and internalResponse - // to a network error. - if ( - response.type === 'opaque' && - internalResponse.status === 206 && - internalResponse.rangeRequested && - !request.headers.contains('range') - ) { - response = internalResponse = makeNetworkError() - } - - // 19. If response is not a network error and either request’s method is - // `HEAD` or `CONNECT`, or internalResponse’s status is a null body status, - // set internalResponse’s body to null and disregard any enqueuing toward - // it (if any). - if ( - response.status !== 0 && - (request.method === 'HEAD' || - request.method === 'CONNECT' || - nullBodyStatus.includes(internalResponse.status)) - ) { - internalResponse.body = null - fetchParams.controller.dump = true - } - - // 20. If request’s integrity metadata is not the empty string, then: - if (request.integrity) { - // 1. Let processBodyError be this step: run fetch finale given fetchParams - // and a network error. - const processBodyError = (reason) => - fetchFinale(fetchParams, makeNetworkError(reason)) - - // 2. If request’s response tainting is "opaque", or response’s body is null, - // then run processBodyError and abort these steps. - if (request.responseTainting === 'opaque' || response.body == null) { - processBodyError(response.error) - return - } - - // 3. Let processBody given bytes be these steps: - const processBody = (bytes) => { - // 1. If bytes do not match request’s integrity metadata, - // then run processBodyError and abort these steps. [SRI] - if (!bytesMatch(bytes, request.integrity)) { - processBodyError('integrity mismatch') - return - } - - // 2. Set response’s body to bytes as a body. - response.body = safelyExtractBody(bytes)[0] - - // 3. Run fetch finale given fetchParams and response. - fetchFinale(fetchParams, response) - } - - // 4. Fully read response’s body given processBody and processBodyError. - await fullyReadBody(response.body, processBody, processBodyError) - } else { - // 21. Otherwise, run fetch finale given fetchParams and response. - fetchFinale(fetchParams, response) - } -} - -// https://fetch.spec.whatwg.org/#concept-scheme-fetch -// given a fetch params fetchParams -function schemeFetch (fetchParams) { - // Note: since the connection is destroyed on redirect, which sets fetchParams to a - // cancelled state, we do not want this condition to trigger *unless* there have been - // no redirects. See https://github.com/nodejs/undici/issues/1776 - // 1. If fetchParams is canceled, then return the appropriate network error for fetchParams. - if (isCancelled(fetchParams) && fetchParams.request.redirectCount === 0) { - return Promise.resolve(makeAppropriateNetworkError(fetchParams)) - } - - // 2. Let request be fetchParams’s request. - const { request } = fetchParams - - const { protocol: scheme } = requestCurrentURL(request) - - // 3. Switch on request’s current URL’s scheme and run the associated steps: - switch (scheme) { - case 'about:': { - // If request’s current URL’s path is the string "blank", then return a new response - // whose status message is `OK`, header list is « (`Content-Type`, `text/html;charset=utf-8`) », - // and body is the empty byte sequence as a body. - - // Otherwise, return a network error. - return Promise.resolve(makeNetworkError('about scheme is not supported')) - } - case 'blob:': { - if (!resolveObjectURL) { - resolveObjectURL = (__nccwpck_require__(4300).resolveObjectURL) - } - - // 1. Let blobURLEntry be request’s current URL’s blob URL entry. - const blobURLEntry = requestCurrentURL(request) - - // https://github.com/web-platform-tests/wpt/blob/7b0ebaccc62b566a1965396e5be7bb2bc06f841f/FileAPI/url/resources/fetch-tests.js#L52-L56 - // Buffer.resolveObjectURL does not ignore URL queries. - if (blobURLEntry.search.length !== 0) { - return Promise.resolve(makeNetworkError('NetworkError when attempting to fetch resource.')) - } - - const blobURLEntryObject = resolveObjectURL(blobURLEntry.toString()) - - // 2. If request’s method is not `GET`, blobURLEntry is null, or blobURLEntry’s - // object is not a Blob object, then return a network error. - if (request.method !== 'GET' || !isBlobLike(blobURLEntryObject)) { - return Promise.resolve(makeNetworkError('invalid method')) - } - - // 3. Let bodyWithType be the result of safely extracting blobURLEntry’s object. - const bodyWithType = safelyExtractBody(blobURLEntryObject) - - // 4. Let body be bodyWithType’s body. - const body = bodyWithType[0] - - // 5. Let length be body’s length, serialized and isomorphic encoded. - const length = isomorphicEncode(`${body.length}`) - - // 6. Let type be bodyWithType’s type if it is non-null; otherwise the empty byte sequence. - const type = bodyWithType[1] ?? '' - - // 7. Return a new response whose status message is `OK`, header list is - // « (`Content-Length`, length), (`Content-Type`, type) », and body is body. - const response = makeResponse({ - statusText: 'OK', - headersList: [ - ['content-length', { name: 'Content-Length', value: length }], - ['content-type', { name: 'Content-Type', value: type }] - ] - }) - - response.body = body - - return Promise.resolve(response) - } - case 'data:': { - // 1. Let dataURLStruct be the result of running the - // data: URL processor on request’s current URL. - const currentURL = requestCurrentURL(request) - const dataURLStruct = dataURLProcessor(currentURL) - - // 2. If dataURLStruct is failure, then return a - // network error. - if (dataURLStruct === 'failure') { - return Promise.resolve(makeNetworkError('failed to fetch the data URL')) - } - - // 3. Let mimeType be dataURLStruct’s MIME type, serialized. - const mimeType = serializeAMimeType(dataURLStruct.mimeType) - - // 4. Return a response whose status message is `OK`, - // header list is « (`Content-Type`, mimeType) », - // and body is dataURLStruct’s body as a body. - return Promise.resolve(makeResponse({ - statusText: 'OK', - headersList: [ - ['content-type', { name: 'Content-Type', value: mimeType }] - ], - body: safelyExtractBody(dataURLStruct.body)[0] - })) - } - case 'file:': { - // For now, unfortunate as it is, file URLs are left as an exercise for the reader. - // When in doubt, return a network error. - return Promise.resolve(makeNetworkError('not implemented... yet...')) - } - case 'http:': - case 'https:': { - // Return the result of running HTTP fetch given fetchParams. - - return httpFetch(fetchParams) - .catch((err) => makeNetworkError(err)) - } - default: { - return Promise.resolve(makeNetworkError('unknown scheme')) - } - } -} - -// https://fetch.spec.whatwg.org/#finalize-response -function finalizeResponse (fetchParams, response) { - // 1. Set fetchParams’s request’s done flag. - fetchParams.request.done = true - - // 2, If fetchParams’s process response done is not null, then queue a fetch - // task to run fetchParams’s process response done given response, with - // fetchParams’s task destination. - if (fetchParams.processResponseDone != null) { - queueMicrotask(() => fetchParams.processResponseDone(response)) - } -} - -// https://fetch.spec.whatwg.org/#fetch-finale -function fetchFinale (fetchParams, response) { - // 1. If response is a network error, then: - if (response.type === 'error') { - // 1. Set response’s URL list to « fetchParams’s request’s URL list[0] ». - response.urlList = [fetchParams.request.urlList[0]] - - // 2. Set response’s timing info to the result of creating an opaque timing - // info for fetchParams’s timing info. - response.timingInfo = createOpaqueTimingInfo({ - startTime: fetchParams.timingInfo.startTime - }) - } - - // 2. Let processResponseEndOfBody be the following steps: - const processResponseEndOfBody = () => { - // 1. Set fetchParams’s request’s done flag. - fetchParams.request.done = true - - // If fetchParams’s process response end-of-body is not null, - // then queue a fetch task to run fetchParams’s process response - // end-of-body given response with fetchParams’s task destination. - if (fetchParams.processResponseEndOfBody != null) { - queueMicrotask(() => fetchParams.processResponseEndOfBody(response)) - } - } - - // 3. If fetchParams’s process response is non-null, then queue a fetch task - // to run fetchParams’s process response given response, with fetchParams’s - // task destination. - if (fetchParams.processResponse != null) { - queueMicrotask(() => fetchParams.processResponse(response)) - } - - // 4. If response’s body is null, then run processResponseEndOfBody. - if (response.body == null) { - processResponseEndOfBody() - } else { - // 5. Otherwise: - - // 1. Let transformStream be a new a TransformStream. - - // 2. Let identityTransformAlgorithm be an algorithm which, given chunk, - // enqueues chunk in transformStream. - const identityTransformAlgorithm = (chunk, controller) => { - controller.enqueue(chunk) - } - - // 3. Set up transformStream with transformAlgorithm set to identityTransformAlgorithm - // and flushAlgorithm set to processResponseEndOfBody. - const transformStream = new TransformStream({ - start () {}, - transform: identityTransformAlgorithm, - flush: processResponseEndOfBody - }, { - size () { - return 1 - } - }, { - size () { - return 1 - } - }) - - // 4. Set response’s body to the result of piping response’s body through transformStream. - response.body = { stream: response.body.stream.pipeThrough(transformStream) } - } - - // 6. If fetchParams’s process response consume body is non-null, then: - if (fetchParams.processResponseConsumeBody != null) { - // 1. Let processBody given nullOrBytes be this step: run fetchParams’s - // process response consume body given response and nullOrBytes. - const processBody = (nullOrBytes) => fetchParams.processResponseConsumeBody(response, nullOrBytes) - - // 2. Let processBodyError be this step: run fetchParams’s process - // response consume body given response and failure. - const processBodyError = (failure) => fetchParams.processResponseConsumeBody(response, failure) - - // 3. If response’s body is null, then queue a fetch task to run processBody - // given null, with fetchParams’s task destination. - if (response.body == null) { - queueMicrotask(() => processBody(null)) - } else { - // 4. Otherwise, fully read response’s body given processBody, processBodyError, - // and fetchParams’s task destination. - return fullyReadBody(response.body, processBody, processBodyError) - } - return Promise.resolve() - } -} - -// https://fetch.spec.whatwg.org/#http-fetch -async function httpFetch (fetchParams) { - // 1. Let request be fetchParams’s request. - const request = fetchParams.request - - // 2. Let response be null. - let response = null - - // 3. Let actualResponse be null. - let actualResponse = null - - // 4. Let timingInfo be fetchParams’s timing info. - const timingInfo = fetchParams.timingInfo - - // 5. If request’s service-workers mode is "all", then: - if (request.serviceWorkers === 'all') { - // TODO - } - - // 6. If response is null, then: - if (response === null) { - // 1. If makeCORSPreflight is true and one of these conditions is true: - // TODO - - // 2. If request’s redirect mode is "follow", then set request’s - // service-workers mode to "none". - if (request.redirect === 'follow') { - request.serviceWorkers = 'none' - } - - // 3. Set response and actualResponse to the result of running - // HTTP-network-or-cache fetch given fetchParams. - actualResponse = response = await httpNetworkOrCacheFetch(fetchParams) - - // 4. If request’s response tainting is "cors" and a CORS check - // for request and response returns failure, then return a network error. - if ( - request.responseTainting === 'cors' && - corsCheck(request, response) === 'failure' - ) { - return makeNetworkError('cors failure') - } - - // 5. If the TAO check for request and response returns failure, then set - // request’s timing allow failed flag. - if (TAOCheck(request, response) === 'failure') { - request.timingAllowFailed = true - } - } - - // 7. If either request’s response tainting or response’s type - // is "opaque", and the cross-origin resource policy check with - // request’s origin, request’s client, request’s destination, - // and actualResponse returns blocked, then return a network error. - if ( - (request.responseTainting === 'opaque' || response.type === 'opaque') && - crossOriginResourcePolicyCheck( - request.origin, - request.client, - request.destination, - actualResponse - ) === 'blocked' - ) { - return makeNetworkError('blocked') - } - - // 8. If actualResponse’s status is a redirect status, then: - if (redirectStatusSet.has(actualResponse.status)) { - // 1. If actualResponse’s status is not 303, request’s body is not null, - // and the connection uses HTTP/2, then user agents may, and are even - // encouraged to, transmit an RST_STREAM frame. - // See, https://github.com/whatwg/fetch/issues/1288 - if (request.redirect !== 'manual') { - fetchParams.controller.connection.destroy() - } - - // 2. Switch on request’s redirect mode: - if (request.redirect === 'error') { - // Set response to a network error. - response = makeNetworkError('unexpected redirect') - } else if (request.redirect === 'manual') { - // Set response to an opaque-redirect filtered response whose internal - // response is actualResponse. - // NOTE(spec): On the web this would return an `opaqueredirect` response, - // but that doesn't make sense server side. - // See https://github.com/nodejs/undici/issues/1193. - response = actualResponse - } else if (request.redirect === 'follow') { - // Set response to the result of running HTTP-redirect fetch given - // fetchParams and response. - response = await httpRedirectFetch(fetchParams, response) - } else { - assert(false) - } - } - - // 9. Set response’s timing info to timingInfo. - response.timingInfo = timingInfo - - // 10. Return response. - return response -} - -// https://fetch.spec.whatwg.org/#http-redirect-fetch -function httpRedirectFetch (fetchParams, response) { - // 1. Let request be fetchParams’s request. - const request = fetchParams.request - - // 2. Let actualResponse be response, if response is not a filtered response, - // and response’s internal response otherwise. - const actualResponse = response.internalResponse - ? response.internalResponse - : response - - // 3. Let locationURL be actualResponse’s location URL given request’s current - // URL’s fragment. - let locationURL - - try { - locationURL = responseLocationURL( - actualResponse, - requestCurrentURL(request).hash - ) - - // 4. If locationURL is null, then return response. - if (locationURL == null) { - return response - } - } catch (err) { - // 5. If locationURL is failure, then return a network error. - return Promise.resolve(makeNetworkError(err)) - } - - // 6. If locationURL’s scheme is not an HTTP(S) scheme, then return a network - // error. - if (!urlIsHttpHttpsScheme(locationURL)) { - return Promise.resolve(makeNetworkError('URL scheme must be a HTTP(S) scheme')) - } - - // 7. If request’s redirect count is 20, then return a network error. - if (request.redirectCount === 20) { - return Promise.resolve(makeNetworkError('redirect count exceeded')) - } - - // 8. Increase request’s redirect count by 1. - request.redirectCount += 1 - - // 9. If request’s mode is "cors", locationURL includes credentials, and - // request’s origin is not same origin with locationURL’s origin, then return - // a network error. - if ( - request.mode === 'cors' && - (locationURL.username || locationURL.password) && - !sameOrigin(request, locationURL) - ) { - return Promise.resolve(makeNetworkError('cross origin not allowed for request mode "cors"')) - } - - // 10. If request’s response tainting is "cors" and locationURL includes - // credentials, then return a network error. - if ( - request.responseTainting === 'cors' && - (locationURL.username || locationURL.password) - ) { - return Promise.resolve(makeNetworkError( - 'URL cannot contain credentials for request mode "cors"' - )) - } - - // 11. If actualResponse’s status is not 303, request’s body is non-null, - // and request’s body’s source is null, then return a network error. - if ( - actualResponse.status !== 303 && - request.body != null && - request.body.source == null - ) { - return Promise.resolve(makeNetworkError()) - } - - // 12. If one of the following is true - // - actualResponse’s status is 301 or 302 and request’s method is `POST` - // - actualResponse’s status is 303 and request’s method is not `GET` or `HEAD` - if ( - ([301, 302].includes(actualResponse.status) && request.method === 'POST') || - (actualResponse.status === 303 && - !GET_OR_HEAD.includes(request.method)) - ) { - // then: - // 1. Set request’s method to `GET` and request’s body to null. - request.method = 'GET' - request.body = null - - // 2. For each headerName of request-body-header name, delete headerName from - // request’s header list. - for (const headerName of requestBodyHeader) { - request.headersList.delete(headerName) - } - } - - // 13. If request’s current URL’s origin is not same origin with locationURL’s - // origin, then for each headerName of CORS non-wildcard request-header name, - // delete headerName from request’s header list. - if (!sameOrigin(requestCurrentURL(request), locationURL)) { - // https://fetch.spec.whatwg.org/#cors-non-wildcard-request-header-name - request.headersList.delete('authorization') - - // "Cookie" and "Host" are forbidden request-headers, which undici doesn't implement. - request.headersList.delete('cookie') - request.headersList.delete('host') - } - - // 14. If request’s body is non-null, then set request’s body to the first return - // value of safely extracting request’s body’s source. - if (request.body != null) { - assert(request.body.source != null) - request.body = safelyExtractBody(request.body.source)[0] - } - - // 15. Let timingInfo be fetchParams’s timing info. - const timingInfo = fetchParams.timingInfo - - // 16. Set timingInfo’s redirect end time and post-redirect start time to the - // coarsened shared current time given fetchParams’s cross-origin isolated - // capability. - timingInfo.redirectEndTime = timingInfo.postRedirectStartTime = - coarsenedSharedCurrentTime(fetchParams.crossOriginIsolatedCapability) - - // 17. If timingInfo’s redirect start time is 0, then set timingInfo’s - // redirect start time to timingInfo’s start time. - if (timingInfo.redirectStartTime === 0) { - timingInfo.redirectStartTime = timingInfo.startTime - } - - // 18. Append locationURL to request’s URL list. - request.urlList.push(locationURL) - - // 19. Invoke set request’s referrer policy on redirect on request and - // actualResponse. - setRequestReferrerPolicyOnRedirect(request, actualResponse) - - // 20. Return the result of running main fetch given fetchParams and true. - return mainFetch(fetchParams, true) -} - -// https://fetch.spec.whatwg.org/#http-network-or-cache-fetch -async function httpNetworkOrCacheFetch ( - fetchParams, - isAuthenticationFetch = false, - isNewConnectionFetch = false -) { - // 1. Let request be fetchParams’s request. - const request = fetchParams.request - - // 2. Let httpFetchParams be null. - let httpFetchParams = null - - // 3. Let httpRequest be null. - let httpRequest = null - - // 4. Let response be null. - let response = null - - // 5. Let storedResponse be null. - // TODO: cache - - // 6. Let httpCache be null. - const httpCache = null - - // 7. Let the revalidatingFlag be unset. - const revalidatingFlag = false - - // 8. Run these steps, but abort when the ongoing fetch is terminated: - - // 1. If request’s window is "no-window" and request’s redirect mode is - // "error", then set httpFetchParams to fetchParams and httpRequest to - // request. - if (request.window === 'no-window' && request.redirect === 'error') { - httpFetchParams = fetchParams - httpRequest = request - } else { - // Otherwise: - - // 1. Set httpRequest to a clone of request. - httpRequest = makeRequest(request) - - // 2. Set httpFetchParams to a copy of fetchParams. - httpFetchParams = { ...fetchParams } - - // 3. Set httpFetchParams’s request to httpRequest. - httpFetchParams.request = httpRequest - } - - // 3. Let includeCredentials be true if one of - const includeCredentials = - request.credentials === 'include' || - (request.credentials === 'same-origin' && - request.responseTainting === 'basic') - - // 4. Let contentLength be httpRequest’s body’s length, if httpRequest’s - // body is non-null; otherwise null. - const contentLength = httpRequest.body ? httpRequest.body.length : null - - // 5. Let contentLengthHeaderValue be null. - let contentLengthHeaderValue = null - - // 6. If httpRequest’s body is null and httpRequest’s method is `POST` or - // `PUT`, then set contentLengthHeaderValue to `0`. - if ( - httpRequest.body == null && - ['POST', 'PUT'].includes(httpRequest.method) - ) { - contentLengthHeaderValue = '0' - } - - // 7. If contentLength is non-null, then set contentLengthHeaderValue to - // contentLength, serialized and isomorphic encoded. - if (contentLength != null) { - contentLengthHeaderValue = isomorphicEncode(`${contentLength}`) - } - - // 8. If contentLengthHeaderValue is non-null, then append - // `Content-Length`/contentLengthHeaderValue to httpRequest’s header - // list. - if (contentLengthHeaderValue != null) { - httpRequest.headersList.append('content-length', contentLengthHeaderValue) - } - - // 9. If contentLengthHeaderValue is non-null, then append (`Content-Length`, - // contentLengthHeaderValue) to httpRequest’s header list. - - // 10. If contentLength is non-null and httpRequest’s keepalive is true, - // then: - if (contentLength != null && httpRequest.keepalive) { - // NOTE: keepalive is a noop outside of browser context. - } - - // 11. If httpRequest’s referrer is a URL, then append - // `Referer`/httpRequest’s referrer, serialized and isomorphic encoded, - // to httpRequest’s header list. - if (httpRequest.referrer instanceof URL) { - httpRequest.headersList.append('referer', isomorphicEncode(httpRequest.referrer.href)) - } - - // 12. Append a request `Origin` header for httpRequest. - appendRequestOriginHeader(httpRequest) - - // 13. Append the Fetch metadata headers for httpRequest. [FETCH-METADATA] - appendFetchMetadata(httpRequest) - - // 14. If httpRequest’s header list does not contain `User-Agent`, then - // user agents should append `User-Agent`/default `User-Agent` value to - // httpRequest’s header list. - if (!httpRequest.headersList.contains('user-agent')) { - httpRequest.headersList.append('user-agent', typeof esbuildDetection === 'undefined' ? 'undici' : 'node') - } - - // 15. If httpRequest’s cache mode is "default" and httpRequest’s header - // list contains `If-Modified-Since`, `If-None-Match`, - // `If-Unmodified-Since`, `If-Match`, or `If-Range`, then set - // httpRequest’s cache mode to "no-store". - if ( - httpRequest.cache === 'default' && - (httpRequest.headersList.contains('if-modified-since') || - httpRequest.headersList.contains('if-none-match') || - httpRequest.headersList.contains('if-unmodified-since') || - httpRequest.headersList.contains('if-match') || - httpRequest.headersList.contains('if-range')) - ) { - httpRequest.cache = 'no-store' - } - - // 16. If httpRequest’s cache mode is "no-cache", httpRequest’s prevent - // no-cache cache-control header modification flag is unset, and - // httpRequest’s header list does not contain `Cache-Control`, then append - // `Cache-Control`/`max-age=0` to httpRequest’s header list. - if ( - httpRequest.cache === 'no-cache' && - !httpRequest.preventNoCacheCacheControlHeaderModification && - !httpRequest.headersList.contains('cache-control') - ) { - httpRequest.headersList.append('cache-control', 'max-age=0') - } - - // 17. If httpRequest’s cache mode is "no-store" or "reload", then: - if (httpRequest.cache === 'no-store' || httpRequest.cache === 'reload') { - // 1. If httpRequest’s header list does not contain `Pragma`, then append - // `Pragma`/`no-cache` to httpRequest’s header list. - if (!httpRequest.headersList.contains('pragma')) { - httpRequest.headersList.append('pragma', 'no-cache') - } - - // 2. If httpRequest’s header list does not contain `Cache-Control`, - // then append `Cache-Control`/`no-cache` to httpRequest’s header list. - if (!httpRequest.headersList.contains('cache-control')) { - httpRequest.headersList.append('cache-control', 'no-cache') - } - } - - // 18. If httpRequest’s header list contains `Range`, then append - // `Accept-Encoding`/`identity` to httpRequest’s header list. - if (httpRequest.headersList.contains('range')) { - httpRequest.headersList.append('accept-encoding', 'identity') - } - - // 19. Modify httpRequest’s header list per HTTP. Do not append a given - // header if httpRequest’s header list contains that header’s name. - // TODO: https://github.com/whatwg/fetch/issues/1285#issuecomment-896560129 - if (!httpRequest.headersList.contains('accept-encoding')) { - if (urlHasHttpsScheme(requestCurrentURL(httpRequest))) { - httpRequest.headersList.append('accept-encoding', 'br, gzip, deflate') - } else { - httpRequest.headersList.append('accept-encoding', 'gzip, deflate') - } - } - - httpRequest.headersList.delete('host') - - // 20. If includeCredentials is true, then: - if (includeCredentials) { - // 1. If the user agent is not configured to block cookies for httpRequest - // (see section 7 of [COOKIES]), then: - // TODO: credentials - // 2. If httpRequest’s header list does not contain `Authorization`, then: - // TODO: credentials - } - - // 21. If there’s a proxy-authentication entry, use it as appropriate. - // TODO: proxy-authentication - - // 22. Set httpCache to the result of determining the HTTP cache - // partition, given httpRequest. - // TODO: cache - - // 23. If httpCache is null, then set httpRequest’s cache mode to - // "no-store". - if (httpCache == null) { - httpRequest.cache = 'no-store' - } - - // 24. If httpRequest’s cache mode is neither "no-store" nor "reload", - // then: - if (httpRequest.mode !== 'no-store' && httpRequest.mode !== 'reload') { - // TODO: cache - } - - // 9. If aborted, then return the appropriate network error for fetchParams. - // TODO - - // 10. If response is null, then: - if (response == null) { - // 1. If httpRequest’s cache mode is "only-if-cached", then return a - // network error. - if (httpRequest.mode === 'only-if-cached') { - return makeNetworkError('only if cached') - } - - // 2. Let forwardResponse be the result of running HTTP-network fetch - // given httpFetchParams, includeCredentials, and isNewConnectionFetch. - const forwardResponse = await httpNetworkFetch( - httpFetchParams, - includeCredentials, - isNewConnectionFetch - ) - - // 3. If httpRequest’s method is unsafe and forwardResponse’s status is - // in the range 200 to 399, inclusive, invalidate appropriate stored - // responses in httpCache, as per the "Invalidation" chapter of HTTP - // Caching, and set storedResponse to null. [HTTP-CACHING] - if ( - !safeMethodsSet.has(httpRequest.method) && - forwardResponse.status >= 200 && - forwardResponse.status <= 399 - ) { - // TODO: cache - } - - // 4. If the revalidatingFlag is set and forwardResponse’s status is 304, - // then: - if (revalidatingFlag && forwardResponse.status === 304) { - // TODO: cache - } - - // 5. If response is null, then: - if (response == null) { - // 1. Set response to forwardResponse. - response = forwardResponse - - // 2. Store httpRequest and forwardResponse in httpCache, as per the - // "Storing Responses in Caches" chapter of HTTP Caching. [HTTP-CACHING] - // TODO: cache - } - } - - // 11. Set response’s URL list to a clone of httpRequest’s URL list. - response.urlList = [...httpRequest.urlList] - - // 12. If httpRequest’s header list contains `Range`, then set response’s - // range-requested flag. - if (httpRequest.headersList.contains('range')) { - response.rangeRequested = true - } - - // 13. Set response’s request-includes-credentials to includeCredentials. - response.requestIncludesCredentials = includeCredentials - - // 14. If response’s status is 401, httpRequest’s response tainting is not - // "cors", includeCredentials is true, and request’s window is an environment - // settings object, then: - // TODO - - // 15. If response’s status is 407, then: - if (response.status === 407) { - // 1. If request’s window is "no-window", then return a network error. - if (request.window === 'no-window') { - return makeNetworkError() - } - - // 2. ??? - - // 3. If fetchParams is canceled, then return the appropriate network error for fetchParams. - if (isCancelled(fetchParams)) { - return makeAppropriateNetworkError(fetchParams) - } - - // 4. Prompt the end user as appropriate in request’s window and store - // the result as a proxy-authentication entry. [HTTP-AUTH] - // TODO: Invoke some kind of callback? - - // 5. Set response to the result of running HTTP-network-or-cache fetch given - // fetchParams. - // TODO - return makeNetworkError('proxy authentication required') - } - - // 16. If all of the following are true - if ( - // response’s status is 421 - response.status === 421 && - // isNewConnectionFetch is false - !isNewConnectionFetch && - // request’s body is null, or request’s body is non-null and request’s body’s source is non-null - (request.body == null || request.body.source != null) - ) { - // then: - - // 1. If fetchParams is canceled, then return the appropriate network error for fetchParams. - if (isCancelled(fetchParams)) { - return makeAppropriateNetworkError(fetchParams) - } - - // 2. Set response to the result of running HTTP-network-or-cache - // fetch given fetchParams, isAuthenticationFetch, and true. - - // TODO (spec): The spec doesn't specify this but we need to cancel - // the active response before we can start a new one. - // https://github.com/whatwg/fetch/issues/1293 - fetchParams.controller.connection.destroy() - - response = await httpNetworkOrCacheFetch( - fetchParams, - isAuthenticationFetch, - true - ) - } - - // 17. If isAuthenticationFetch is true, then create an authentication entry - if (isAuthenticationFetch) { - // TODO - } - - // 18. Return response. - return response -} - -// https://fetch.spec.whatwg.org/#http-network-fetch -async function httpNetworkFetch ( - fetchParams, - includeCredentials = false, - forceNewConnection = false -) { - assert(!fetchParams.controller.connection || fetchParams.controller.connection.destroyed) - - fetchParams.controller.connection = { - abort: null, - destroyed: false, - destroy (err) { - if (!this.destroyed) { - this.destroyed = true - this.abort?.(err ?? new DOMException('The operation was aborted.', 'AbortError')) - } - } - } - - // 1. Let request be fetchParams’s request. - const request = fetchParams.request - - // 2. Let response be null. - let response = null - - // 3. Let timingInfo be fetchParams’s timing info. - const timingInfo = fetchParams.timingInfo - - // 4. Let httpCache be the result of determining the HTTP cache partition, - // given request. - // TODO: cache - const httpCache = null - - // 5. If httpCache is null, then set request’s cache mode to "no-store". - if (httpCache == null) { - request.cache = 'no-store' - } - - // 6. Let networkPartitionKey be the result of determining the network - // partition key given request. - // TODO - - // 7. Let newConnection be "yes" if forceNewConnection is true; otherwise - // "no". - const newConnection = forceNewConnection ? 'yes' : 'no' // eslint-disable-line no-unused-vars - - // 8. Switch on request’s mode: - if (request.mode === 'websocket') { - // Let connection be the result of obtaining a WebSocket connection, - // given request’s current URL. - // TODO - } else { - // Let connection be the result of obtaining a connection, given - // networkPartitionKey, request’s current URL’s origin, - // includeCredentials, and forceNewConnection. - // TODO - } - - // 9. Run these steps, but abort when the ongoing fetch is terminated: - - // 1. If connection is failure, then return a network error. - - // 2. Set timingInfo’s final connection timing info to the result of - // calling clamp and coarsen connection timing info with connection’s - // timing info, timingInfo’s post-redirect start time, and fetchParams’s - // cross-origin isolated capability. - - // 3. If connection is not an HTTP/2 connection, request’s body is non-null, - // and request’s body’s source is null, then append (`Transfer-Encoding`, - // `chunked`) to request’s header list. - - // 4. Set timingInfo’s final network-request start time to the coarsened - // shared current time given fetchParams’s cross-origin isolated - // capability. - - // 5. Set response to the result of making an HTTP request over connection - // using request with the following caveats: - - // - Follow the relevant requirements from HTTP. [HTTP] [HTTP-SEMANTICS] - // [HTTP-COND] [HTTP-CACHING] [HTTP-AUTH] - - // - If request’s body is non-null, and request’s body’s source is null, - // then the user agent may have a buffer of up to 64 kibibytes and store - // a part of request’s body in that buffer. If the user agent reads from - // request’s body beyond that buffer’s size and the user agent needs to - // resend request, then instead return a network error. - - // - Set timingInfo’s final network-response start time to the coarsened - // shared current time given fetchParams’s cross-origin isolated capability, - // immediately after the user agent’s HTTP parser receives the first byte - // of the response (e.g., frame header bytes for HTTP/2 or response status - // line for HTTP/1.x). - - // - Wait until all the headers are transmitted. - - // - Any responses whose status is in the range 100 to 199, inclusive, - // and is not 101, are to be ignored, except for the purposes of setting - // timingInfo’s final network-response start time above. - - // - If request’s header list contains `Transfer-Encoding`/`chunked` and - // response is transferred via HTTP/1.0 or older, then return a network - // error. - - // - If the HTTP request results in a TLS client certificate dialog, then: - - // 1. If request’s window is an environment settings object, make the - // dialog available in request’s window. - - // 2. Otherwise, return a network error. - - // To transmit request’s body body, run these steps: - let requestBody = null - // 1. If body is null and fetchParams’s process request end-of-body is - // non-null, then queue a fetch task given fetchParams’s process request - // end-of-body and fetchParams’s task destination. - if (request.body == null && fetchParams.processRequestEndOfBody) { - queueMicrotask(() => fetchParams.processRequestEndOfBody()) - } else if (request.body != null) { - // 2. Otherwise, if body is non-null: - - // 1. Let processBodyChunk given bytes be these steps: - const processBodyChunk = async function * (bytes) { - // 1. If the ongoing fetch is terminated, then abort these steps. - if (isCancelled(fetchParams)) { - return - } - - // 2. Run this step in parallel: transmit bytes. - yield bytes - - // 3. If fetchParams’s process request body is non-null, then run - // fetchParams’s process request body given bytes’s length. - fetchParams.processRequestBodyChunkLength?.(bytes.byteLength) - } - - // 2. Let processEndOfBody be these steps: - const processEndOfBody = () => { - // 1. If fetchParams is canceled, then abort these steps. - if (isCancelled(fetchParams)) { - return - } - - // 2. If fetchParams’s process request end-of-body is non-null, - // then run fetchParams’s process request end-of-body. - if (fetchParams.processRequestEndOfBody) { - fetchParams.processRequestEndOfBody() - } - } - - // 3. Let processBodyError given e be these steps: - const processBodyError = (e) => { - // 1. If fetchParams is canceled, then abort these steps. - if (isCancelled(fetchParams)) { - return - } - - // 2. If e is an "AbortError" DOMException, then abort fetchParams’s controller. - if (e.name === 'AbortError') { - fetchParams.controller.abort() - } else { - fetchParams.controller.terminate(e) - } - } - - // 4. Incrementally read request’s body given processBodyChunk, processEndOfBody, - // processBodyError, and fetchParams’s task destination. - requestBody = (async function * () { - try { - for await (const bytes of request.body.stream) { - yield * processBodyChunk(bytes) - } - processEndOfBody() - } catch (err) { - processBodyError(err) - } - })() - } - - try { - // socket is only provided for websockets - const { body, status, statusText, headersList, socket } = await dispatch({ body: requestBody }) - - if (socket) { - response = makeResponse({ status, statusText, headersList, socket }) - } else { - const iterator = body[Symbol.asyncIterator]() - fetchParams.controller.next = () => iterator.next() - - response = makeResponse({ status, statusText, headersList }) - } - } catch (err) { - // 10. If aborted, then: - if (err.name === 'AbortError') { - // 1. If connection uses HTTP/2, then transmit an RST_STREAM frame. - fetchParams.controller.connection.destroy() - - // 2. Return the appropriate network error for fetchParams. - return makeAppropriateNetworkError(fetchParams, err) - } - - return makeNetworkError(err) - } - - // 11. Let pullAlgorithm be an action that resumes the ongoing fetch - // if it is suspended. - const pullAlgorithm = () => { - fetchParams.controller.resume() - } - - // 12. Let cancelAlgorithm be an algorithm that aborts fetchParams’s - // controller with reason, given reason. - const cancelAlgorithm = (reason) => { - fetchParams.controller.abort(reason) - } - - // 13. Let highWaterMark be a non-negative, non-NaN number, chosen by - // the user agent. - // TODO - - // 14. Let sizeAlgorithm be an algorithm that accepts a chunk object - // and returns a non-negative, non-NaN, non-infinite number, chosen by the user agent. - // TODO - - // 15. Let stream be a new ReadableStream. - // 16. Set up stream with pullAlgorithm set to pullAlgorithm, - // cancelAlgorithm set to cancelAlgorithm, highWaterMark set to - // highWaterMark, and sizeAlgorithm set to sizeAlgorithm. - if (!ReadableStream) { - ReadableStream = (__nccwpck_require__(5356).ReadableStream) - } - - const stream = new ReadableStream( - { - async start (controller) { - fetchParams.controller.controller = controller - }, - async pull (controller) { - await pullAlgorithm(controller) - }, - async cancel (reason) { - await cancelAlgorithm(reason) - } - }, - { - highWaterMark: 0, - size () { - return 1 - } - } - ) - - // 17. Run these steps, but abort when the ongoing fetch is terminated: - - // 1. Set response’s body to a new body whose stream is stream. - response.body = { stream } - - // 2. If response is not a network error and request’s cache mode is - // not "no-store", then update response in httpCache for request. - // TODO - - // 3. If includeCredentials is true and the user agent is not configured - // to block cookies for request (see section 7 of [COOKIES]), then run the - // "set-cookie-string" parsing algorithm (see section 5.2 of [COOKIES]) on - // the value of each header whose name is a byte-case-insensitive match for - // `Set-Cookie` in response’s header list, if any, and request’s current URL. - // TODO - - // 18. If aborted, then: - // TODO - - // 19. Run these steps in parallel: - - // 1. Run these steps, but abort when fetchParams is canceled: - fetchParams.controller.on('terminated', onAborted) - fetchParams.controller.resume = async () => { - // 1. While true - while (true) { - // 1-3. See onData... - - // 4. Set bytes to the result of handling content codings given - // codings and bytes. - let bytes - let isFailure - try { - const { done, value } = await fetchParams.controller.next() - - if (isAborted(fetchParams)) { - break - } - - bytes = done ? undefined : value - } catch (err) { - if (fetchParams.controller.ended && !timingInfo.encodedBodySize) { - // zlib doesn't like empty streams. - bytes = undefined - } else { - bytes = err - - // err may be propagated from the result of calling readablestream.cancel, - // which might not be an error. https://github.com/nodejs/undici/issues/2009 - isFailure = true - } - } - - if (bytes === undefined) { - // 2. Otherwise, if the bytes transmission for response’s message - // body is done normally and stream is readable, then close - // stream, finalize response for fetchParams and response, and - // abort these in-parallel steps. - readableStreamClose(fetchParams.controller.controller) - - finalizeResponse(fetchParams, response) - - return - } - - // 5. Increase timingInfo’s decoded body size by bytes’s length. - timingInfo.decodedBodySize += bytes?.byteLength ?? 0 - - // 6. If bytes is failure, then terminate fetchParams’s controller. - if (isFailure) { - fetchParams.controller.terminate(bytes) - return - } - - // 7. Enqueue a Uint8Array wrapping an ArrayBuffer containing bytes - // into stream. - fetchParams.controller.controller.enqueue(new Uint8Array(bytes)) - - // 8. If stream is errored, then terminate the ongoing fetch. - if (isErrored(stream)) { - fetchParams.controller.terminate() - return - } - - // 9. If stream doesn’t need more data ask the user agent to suspend - // the ongoing fetch. - if (!fetchParams.controller.controller.desiredSize) { - return - } - } - } - - // 2. If aborted, then: - function onAborted (reason) { - // 2. If fetchParams is aborted, then: - if (isAborted(fetchParams)) { - // 1. Set response’s aborted flag. - response.aborted = true - - // 2. If stream is readable, then error stream with the result of - // deserialize a serialized abort reason given fetchParams’s - // controller’s serialized abort reason and an - // implementation-defined realm. - if (isReadable(stream)) { - fetchParams.controller.controller.error( - fetchParams.controller.serializedAbortReason - ) - } - } else { - // 3. Otherwise, if stream is readable, error stream with a TypeError. - if (isReadable(stream)) { - fetchParams.controller.controller.error(new TypeError('terminated', { - cause: isErrorLike(reason) ? reason : undefined - })) - } - } - - // 4. If connection uses HTTP/2, then transmit an RST_STREAM frame. - // 5. Otherwise, the user agent should close connection unless it would be bad for performance to do so. - fetchParams.controller.connection.destroy() - } - - // 20. Return response. - return response - - async function dispatch ({ body }) { - const url = requestCurrentURL(request) - /** @type {import('../..').Agent} */ - const agent = fetchParams.controller.dispatcher - - return new Promise((resolve, reject) => agent.dispatch( - { - path: url.pathname + url.search, - origin: url.origin, - method: request.method, - body: fetchParams.controller.dispatcher.isMockActive ? request.body && request.body.source : body, - headers: request.headersList.entries, - maxRedirections: 0, - upgrade: request.mode === 'websocket' ? 'websocket' : undefined - }, - { - body: null, - abort: null, - - onConnect (abort) { - // TODO (fix): Do we need connection here? - const { connection } = fetchParams.controller - - if (connection.destroyed) { - abort(new DOMException('The operation was aborted.', 'AbortError')) - } else { - fetchParams.controller.on('terminated', abort) - this.abort = connection.abort = abort - } - }, - - onHeaders (status, headersList, resume, statusText) { - if (status < 200) { - return - } - - let codings = [] - let location = '' - - const headers = new Headers() - - // For H2, the headers are a plain JS object - // We distinguish between them and iterate accordingly - if (Array.isArray(headersList)) { - for (let n = 0; n < headersList.length; n += 2) { - const key = headersList[n + 0].toString('latin1') - const val = headersList[n + 1].toString('latin1') - if (key.toLowerCase() === 'content-encoding') { - // https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.1 - // "All content-coding values are case-insensitive..." - codings = val.toLowerCase().split(',').map((x) => x.trim()) - } else if (key.toLowerCase() === 'location') { - location = val - } - - headers.append(key, val) - } - } else { - const keys = Object.keys(headersList) - for (const key of keys) { - const val = headersList[key] - if (key.toLowerCase() === 'content-encoding') { - // https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.1 - // "All content-coding values are case-insensitive..." - codings = val.toLowerCase().split(',').map((x) => x.trim()).reverse() - } else if (key.toLowerCase() === 'location') { - location = val - } - - headers.append(key, val) - } - } - - this.body = new Readable({ read: resume }) - - const decoders = [] - - const willFollow = request.redirect === 'follow' && - location && - redirectStatusSet.has(status) - - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding - if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) { - for (const coding of codings) { - // https://www.rfc-editor.org/rfc/rfc9112.html#section-7.2 - if (coding === 'x-gzip' || coding === 'gzip') { - decoders.push(zlib.createGunzip({ - // Be less strict when decoding compressed responses, since sometimes - // servers send slightly invalid responses that are still accepted - // by common browsers. - // Always using Z_SYNC_FLUSH is what cURL does. - flush: zlib.constants.Z_SYNC_FLUSH, - finishFlush: zlib.constants.Z_SYNC_FLUSH - })) - } else if (coding === 'deflate') { - decoders.push(zlib.createInflate()) - } else if (coding === 'br') { - decoders.push(zlib.createBrotliDecompress()) - } else { - decoders.length = 0 - break - } - } - } - - resolve({ - status, - statusText, - headersList: headers[kHeadersList], - body: decoders.length - ? pipeline(this.body, ...decoders, () => { }) - : this.body.on('error', () => {}) - }) - - return true - }, - - onData (chunk) { - if (fetchParams.controller.dump) { - return - } - - // 1. If one or more bytes have been transmitted from response’s - // message body, then: - - // 1. Let bytes be the transmitted bytes. - const bytes = chunk - - // 2. Let codings be the result of extracting header list values - // given `Content-Encoding` and response’s header list. - // See pullAlgorithm. - - // 3. Increase timingInfo’s encoded body size by bytes’s length. - timingInfo.encodedBodySize += bytes.byteLength - - // 4. See pullAlgorithm... - - return this.body.push(bytes) - }, - - onComplete () { - if (this.abort) { - fetchParams.controller.off('terminated', this.abort) - } - - fetchParams.controller.ended = true - - this.body.push(null) - }, - - onError (error) { - if (this.abort) { - fetchParams.controller.off('terminated', this.abort) - } - - this.body?.destroy(error) - - fetchParams.controller.terminate(error) - - reject(error) - }, - - onUpgrade (status, headersList, socket) { - if (status !== 101) { - return - } - - const headers = new Headers() - - for (let n = 0; n < headersList.length; n += 2) { - const key = headersList[n + 0].toString('latin1') - const val = headersList[n + 1].toString('latin1') - - headers.append(key, val) - } - - resolve({ - status, - statusText: STATUS_CODES[status], - headersList: headers[kHeadersList], - socket - }) - - return true - } - } - )) - } -} - -module.exports = { - fetch, - Fetch, - fetching, - finalizeAndReportTiming -} - - -/***/ }), - -/***/ 8619: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -/* globals AbortController */ - - - -const { extractBody, mixinBody, cloneBody } = __nccwpck_require__(6770) -const { Headers, fill: fillHeaders, HeadersList } = __nccwpck_require__(7967) -const { FinalizationRegistry } = __nccwpck_require__(7905)() -const util = __nccwpck_require__(6223) -const { - isValidHTTPToken, - sameOrigin, - normalizeMethod, - makePolicyContainer -} = __nccwpck_require__(6913) -const { - forbiddenMethodsSet, - corsSafeListedMethodsSet, - referrerPolicy, - requestRedirect, - requestMode, - requestCredentials, - requestCache, - requestDuplex -} = __nccwpck_require__(7213) -const { kEnumerableProperty } = util -const { kHeaders, kSignal, kState, kGuard, kRealm } = __nccwpck_require__(1048) -const { webidl } = __nccwpck_require__(5337) -const { getGlobalOrigin } = __nccwpck_require__(4428) -const { URLSerializer } = __nccwpck_require__(6822) -const { kHeadersList } = __nccwpck_require__(1439) -const assert = __nccwpck_require__(9491) -const { getMaxListeners, setMaxListeners, getEventListeners, defaultMaxListeners } = __nccwpck_require__(2361) - -let TransformStream = globalThis.TransformStream - -const kInit = Symbol('init') -const kAbortController = Symbol('abortController') - -const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => { - signal.removeEventListener('abort', abort) -}) - -// https://fetch.spec.whatwg.org/#request-class -class Request { - // https://fetch.spec.whatwg.org/#dom-request - constructor (input, init = {}) { - if (input === kInit) { - return - } - - webidl.argumentLengthCheck(arguments, 1, { header: 'Request constructor' }) - - input = webidl.converters.RequestInfo(input) - init = webidl.converters.RequestInit(init) - - // https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object - this[kRealm] = { - settingsObject: { - baseUrl: getGlobalOrigin(), - get origin () { - return this.baseUrl?.origin - }, - policyContainer: makePolicyContainer() - } - } - - // 1. Let request be null. - let request = null - - // 2. Let fallbackMode be null. - let fallbackMode = null - - // 3. Let baseURL be this’s relevant settings object’s API base URL. - const baseUrl = this[kRealm].settingsObject.baseUrl - - // 4. Let signal be null. - let signal = null - - // 5. If input is a string, then: - if (typeof input === 'string') { - // 1. Let parsedURL be the result of parsing input with baseURL. - // 2. If parsedURL is failure, then throw a TypeError. - let parsedURL - try { - parsedURL = new URL(input, baseUrl) - } catch (err) { - throw new TypeError('Failed to parse URL from ' + input, { cause: err }) - } - - // 3. If parsedURL includes credentials, then throw a TypeError. - if (parsedURL.username || parsedURL.password) { - throw new TypeError( - 'Request cannot be constructed from a URL that includes credentials: ' + - input - ) - } - - // 4. Set request to a new request whose URL is parsedURL. - request = makeRequest({ urlList: [parsedURL] }) - - // 5. Set fallbackMode to "cors". - fallbackMode = 'cors' - } else { - // 6. Otherwise: - - // 7. Assert: input is a Request object. - assert(input instanceof Request) - - // 8. Set request to input’s request. - request = input[kState] - - // 9. Set signal to input’s signal. - signal = input[kSignal] - } - - // 7. Let origin be this’s relevant settings object’s origin. - const origin = this[kRealm].settingsObject.origin - - // 8. Let window be "client". - let window = 'client' - - // 9. If request’s window is an environment settings object and its origin - // is same origin with origin, then set window to request’s window. - if ( - request.window?.constructor?.name === 'EnvironmentSettingsObject' && - sameOrigin(request.window, origin) - ) { - window = request.window - } - - // 10. If init["window"] exists and is non-null, then throw a TypeError. - if (init.window != null) { - throw new TypeError(`'window' option '${window}' must be null`) - } - - // 11. If init["window"] exists, then set window to "no-window". - if ('window' in init) { - window = 'no-window' - } - - // 12. Set request to a new request with the following properties: - request = makeRequest({ - // URL request’s URL. - // undici implementation note: this is set as the first item in request's urlList in makeRequest - // method request’s method. - method: request.method, - // header list A copy of request’s header list. - // undici implementation note: headersList is cloned in makeRequest - headersList: request.headersList, - // unsafe-request flag Set. - unsafeRequest: request.unsafeRequest, - // client This’s relevant settings object. - client: this[kRealm].settingsObject, - // window window. - window, - // priority request’s priority. - priority: request.priority, - // origin request’s origin. The propagation of the origin is only significant for navigation requests - // being handled by a service worker. In this scenario a request can have an origin that is different - // from the current client. - origin: request.origin, - // referrer request’s referrer. - referrer: request.referrer, - // referrer policy request’s referrer policy. - referrerPolicy: request.referrerPolicy, - // mode request’s mode. - mode: request.mode, - // credentials mode request’s credentials mode. - credentials: request.credentials, - // cache mode request’s cache mode. - cache: request.cache, - // redirect mode request’s redirect mode. - redirect: request.redirect, - // integrity metadata request’s integrity metadata. - integrity: request.integrity, - // keepalive request’s keepalive. - keepalive: request.keepalive, - // reload-navigation flag request’s reload-navigation flag. - reloadNavigation: request.reloadNavigation, - // history-navigation flag request’s history-navigation flag. - historyNavigation: request.historyNavigation, - // URL list A clone of request’s URL list. - urlList: [...request.urlList] - }) - - // 13. If init is not empty, then: - if (Object.keys(init).length > 0) { - // 1. If request’s mode is "navigate", then set it to "same-origin". - if (request.mode === 'navigate') { - request.mode = 'same-origin' - } - - // 2. Unset request’s reload-navigation flag. - request.reloadNavigation = false - - // 3. Unset request’s history-navigation flag. - request.historyNavigation = false - - // 4. Set request’s origin to "client". - request.origin = 'client' - - // 5. Set request’s referrer to "client" - request.referrer = 'client' - - // 6. Set request’s referrer policy to the empty string. - request.referrerPolicy = '' - - // 7. Set request’s URL to request’s current URL. - request.url = request.urlList[request.urlList.length - 1] - - // 8. Set request’s URL list to « request’s URL ». - request.urlList = [request.url] - } - - // 14. If init["referrer"] exists, then: - if (init.referrer !== undefined) { - // 1. Let referrer be init["referrer"]. - const referrer = init.referrer - - // 2. If referrer is the empty string, then set request’s referrer to "no-referrer". - if (referrer === '') { - request.referrer = 'no-referrer' - } else { - // 1. Let parsedReferrer be the result of parsing referrer with - // baseURL. - // 2. If parsedReferrer is failure, then throw a TypeError. - let parsedReferrer - try { - parsedReferrer = new URL(referrer, baseUrl) - } catch (err) { - throw new TypeError(`Referrer "${referrer}" is not a valid URL.`, { cause: err }) - } - - // 3. If one of the following is true - // - parsedReferrer’s scheme is "about" and path is the string "client" - // - parsedReferrer’s origin is not same origin with origin - // then set request’s referrer to "client". - if ( - (parsedReferrer.protocol === 'about:' && parsedReferrer.hostname === 'client') || - (origin && !sameOrigin(parsedReferrer, this[kRealm].settingsObject.baseUrl)) - ) { - request.referrer = 'client' - } else { - // 4. Otherwise, set request’s referrer to parsedReferrer. - request.referrer = parsedReferrer - } - } - } - - // 15. If init["referrerPolicy"] exists, then set request’s referrer policy - // to it. - if (init.referrerPolicy !== undefined) { - request.referrerPolicy = init.referrerPolicy - } - - // 16. Let mode be init["mode"] if it exists, and fallbackMode otherwise. - let mode - if (init.mode !== undefined) { - mode = init.mode - } else { - mode = fallbackMode - } - - // 17. If mode is "navigate", then throw a TypeError. - if (mode === 'navigate') { - throw webidl.errors.exception({ - header: 'Request constructor', - message: 'invalid request mode navigate.' - }) - } - - // 18. If mode is non-null, set request’s mode to mode. - if (mode != null) { - request.mode = mode - } - - // 19. If init["credentials"] exists, then set request’s credentials mode - // to it. - if (init.credentials !== undefined) { - request.credentials = init.credentials - } - - // 18. If init["cache"] exists, then set request’s cache mode to it. - if (init.cache !== undefined) { - request.cache = init.cache - } - - // 21. If request’s cache mode is "only-if-cached" and request’s mode is - // not "same-origin", then throw a TypeError. - if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { - throw new TypeError( - "'only-if-cached' can be set only with 'same-origin' mode" - ) - } - - // 22. If init["redirect"] exists, then set request’s redirect mode to it. - if (init.redirect !== undefined) { - request.redirect = init.redirect - } - - // 23. If init["integrity"] exists, then set request’s integrity metadata to it. - if (init.integrity !== undefined && init.integrity != null) { - request.integrity = String(init.integrity) - } - - // 24. If init["keepalive"] exists, then set request’s keepalive to it. - if (init.keepalive !== undefined) { - request.keepalive = Boolean(init.keepalive) - } - - // 25. If init["method"] exists, then: - if (init.method !== undefined) { - // 1. Let method be init["method"]. - let method = init.method - - // 2. If method is not a method or method is a forbidden method, then - // throw a TypeError. - if (!isValidHTTPToken(init.method)) { - throw TypeError(`'${init.method}' is not a valid HTTP method.`) - } - - if (forbiddenMethodsSet.has(method.toUpperCase())) { - throw TypeError(`'${init.method}' HTTP method is unsupported.`) - } - - // 3. Normalize method. - method = normalizeMethod(init.method) - - // 4. Set request’s method to method. - request.method = method - } - - // 26. If init["signal"] exists, then set signal to it. - if (init.signal !== undefined) { - signal = init.signal - } - - // 27. Set this’s request to request. - this[kState] = request - - // 28. Set this’s signal to a new AbortSignal object with this’s relevant - // Realm. - // TODO: could this be simplified with AbortSignal.any - // (https://dom.spec.whatwg.org/#dom-abortsignal-any) - const ac = new AbortController() - this[kSignal] = ac.signal - this[kSignal][kRealm] = this[kRealm] - - // 29. If signal is not null, then make this’s signal follow signal. - if (signal != null) { - if ( - !signal || - typeof signal.aborted !== 'boolean' || - typeof signal.addEventListener !== 'function' - ) { - throw new TypeError( - "Failed to construct 'Request': member signal is not of type AbortSignal." - ) - } - - if (signal.aborted) { - ac.abort(signal.reason) - } else { - // Keep a strong ref to ac while request object - // is alive. This is needed to prevent AbortController - // from being prematurely garbage collected. - // See, https://github.com/nodejs/undici/issues/1926. - this[kAbortController] = ac - - const acRef = new WeakRef(ac) - const abort = function () { - const ac = acRef.deref() - if (ac !== undefined) { - ac.abort(this.reason) - } - } - - // Third-party AbortControllers may not work with these. - // See, https://github.com/nodejs/undici/pull/1910#issuecomment-1464495619. - try { - // If the max amount of listeners is equal to the default, increase it - // This is only available in node >= v19.9.0 - if (typeof getMaxListeners === 'function' && getMaxListeners(signal) === defaultMaxListeners) { - setMaxListeners(100, signal) - } else if (getEventListeners(signal, 'abort').length >= defaultMaxListeners) { - setMaxListeners(100, signal) - } - } catch {} - - util.addAbortListener(signal, abort) - requestFinalizer.register(ac, { signal, abort }) - } - } - - // 30. Set this’s headers to a new Headers object with this’s relevant - // Realm, whose header list is request’s header list and guard is - // "request". - this[kHeaders] = new Headers() - this[kHeaders][kHeadersList] = request.headersList - this[kHeaders][kGuard] = 'request' - this[kHeaders][kRealm] = this[kRealm] - - // 31. If this’s request’s mode is "no-cors", then: - if (mode === 'no-cors') { - // 1. If this’s request’s method is not a CORS-safelisted method, - // then throw a TypeError. - if (!corsSafeListedMethodsSet.has(request.method)) { - throw new TypeError( - `'${request.method} is unsupported in no-cors mode.` - ) - } - - // 2. Set this’s headers’s guard to "request-no-cors". - this[kHeaders][kGuard] = 'request-no-cors' - } - - // 32. If init is not empty, then: - if (Object.keys(init).length !== 0) { - // 1. Let headers be a copy of this’s headers and its associated header - // list. - let headers = new Headers(this[kHeaders]) - - // 2. If init["headers"] exists, then set headers to init["headers"]. - if (init.headers !== undefined) { - headers = init.headers - } - - // 3. Empty this’s headers’s header list. - this[kHeaders][kHeadersList].clear() - - // 4. If headers is a Headers object, then for each header in its header - // list, append header’s name/header’s value to this’s headers. - if (headers.constructor.name === 'Headers') { - for (const [key, val] of headers) { - this[kHeaders].append(key, val) - } - } else { - // 5. Otherwise, fill this’s headers with headers. - fillHeaders(this[kHeaders], headers) - } - } - - // 33. Let inputBody be input’s request’s body if input is a Request - // object; otherwise null. - const inputBody = input instanceof Request ? input[kState].body : null - - // 34. If either init["body"] exists and is non-null or inputBody is - // non-null, and request’s method is `GET` or `HEAD`, then throw a - // TypeError. - if ( - (init.body != null || inputBody != null) && - (request.method === 'GET' || request.method === 'HEAD') - ) { - throw new TypeError('Request with GET/HEAD method cannot have body.') - } - - // 35. Let initBody be null. - let initBody = null - - // 36. If init["body"] exists and is non-null, then: - if (init.body != null) { - // 1. Let Content-Type be null. - // 2. Set initBody and Content-Type to the result of extracting - // init["body"], with keepalive set to request’s keepalive. - const [extractedBody, contentType] = extractBody( - init.body, - request.keepalive - ) - initBody = extractedBody - - // 3, If Content-Type is non-null and this’s headers’s header list does - // not contain `Content-Type`, then append `Content-Type`/Content-Type to - // this’s headers. - if (contentType && !this[kHeaders][kHeadersList].contains('content-type')) { - this[kHeaders].append('content-type', contentType) - } - } - - // 37. Let inputOrInitBody be initBody if it is non-null; otherwise - // inputBody. - const inputOrInitBody = initBody ?? inputBody - - // 38. If inputOrInitBody is non-null and inputOrInitBody’s source is - // null, then: - if (inputOrInitBody != null && inputOrInitBody.source == null) { - // 1. If initBody is non-null and init["duplex"] does not exist, - // then throw a TypeError. - if (initBody != null && init.duplex == null) { - throw new TypeError('RequestInit: duplex option is required when sending a body.') - } - - // 2. If this’s request’s mode is neither "same-origin" nor "cors", - // then throw a TypeError. - if (request.mode !== 'same-origin' && request.mode !== 'cors') { - throw new TypeError( - 'If request is made from ReadableStream, mode should be "same-origin" or "cors"' - ) - } - - // 3. Set this’s request’s use-CORS-preflight flag. - request.useCORSPreflightFlag = true - } - - // 39. Let finalBody be inputOrInitBody. - let finalBody = inputOrInitBody - - // 40. If initBody is null and inputBody is non-null, then: - if (initBody == null && inputBody != null) { - // 1. If input is unusable, then throw a TypeError. - if (util.isDisturbed(inputBody.stream) || inputBody.stream.locked) { - throw new TypeError( - 'Cannot construct a Request with a Request object that has already been used.' - ) - } - - // 2. Set finalBody to the result of creating a proxy for inputBody. - if (!TransformStream) { - TransformStream = (__nccwpck_require__(5356).TransformStream) - } - - // https://streams.spec.whatwg.org/#readablestream-create-a-proxy - const identityTransform = new TransformStream() - inputBody.stream.pipeThrough(identityTransform) - finalBody = { - source: inputBody.source, - length: inputBody.length, - stream: identityTransform.readable - } - } - - // 41. Set this’s request’s body to finalBody. - this[kState].body = finalBody - } - - // Returns request’s HTTP method, which is "GET" by default. - get method () { - webidl.brandCheck(this, Request) - - // The method getter steps are to return this’s request’s method. - return this[kState].method - } - - // Returns the URL of request as a string. - get url () { - webidl.brandCheck(this, Request) - - // The url getter steps are to return this’s request’s URL, serialized. - return URLSerializer(this[kState].url) - } - - // Returns a Headers object consisting of the headers associated with request. - // Note that headers added in the network layer by the user agent will not - // be accounted for in this object, e.g., the "Host" header. - get headers () { - webidl.brandCheck(this, Request) - - // The headers getter steps are to return this’s headers. - return this[kHeaders] - } - - // Returns the kind of resource requested by request, e.g., "document" - // or "script". - get destination () { - webidl.brandCheck(this, Request) - - // The destination getter are to return this’s request’s destination. - return this[kState].destination - } - - // Returns the referrer of request. Its value can be a same-origin URL if - // explicitly set in init, the empty string to indicate no referrer, and - // "about:client" when defaulting to the global’s default. This is used - // during fetching to determine the value of the `Referer` header of the - // request being made. - get referrer () { - webidl.brandCheck(this, Request) - - // 1. If this’s request’s referrer is "no-referrer", then return the - // empty string. - if (this[kState].referrer === 'no-referrer') { - return '' - } - - // 2. If this’s request’s referrer is "client", then return - // "about:client". - if (this[kState].referrer === 'client') { - return 'about:client' - } - - // Return this’s request’s referrer, serialized. - return this[kState].referrer.toString() - } - - // Returns the referrer policy associated with request. - // This is used during fetching to compute the value of the request’s - // referrer. - get referrerPolicy () { - webidl.brandCheck(this, Request) - - // The referrerPolicy getter steps are to return this’s request’s referrer policy. - return this[kState].referrerPolicy - } - - // Returns the mode associated with request, which is a string indicating - // whether the request will use CORS, or will be restricted to same-origin - // URLs. - get mode () { - webidl.brandCheck(this, Request) - - // The mode getter steps are to return this’s request’s mode. - return this[kState].mode - } - - // Returns the credentials mode associated with request, - // which is a string indicating whether credentials will be sent with the - // request always, never, or only when sent to a same-origin URL. - get credentials () { - // The credentials getter steps are to return this’s request’s credentials mode. - return this[kState].credentials - } - - // Returns the cache mode associated with request, - // which is a string indicating how the request will - // interact with the browser’s cache when fetching. - get cache () { - webidl.brandCheck(this, Request) - - // The cache getter steps are to return this’s request’s cache mode. - return this[kState].cache - } - - // Returns the redirect mode associated with request, - // which is a string indicating how redirects for the - // request will be handled during fetching. A request - // will follow redirects by default. - get redirect () { - webidl.brandCheck(this, Request) - - // The redirect getter steps are to return this’s request’s redirect mode. - return this[kState].redirect - } - - // Returns request’s subresource integrity metadata, which is a - // cryptographic hash of the resource being fetched. Its value - // consists of multiple hashes separated by whitespace. [SRI] - get integrity () { - webidl.brandCheck(this, Request) - - // The integrity getter steps are to return this’s request’s integrity - // metadata. - return this[kState].integrity - } - - // Returns a boolean indicating whether or not request can outlive the - // global in which it was created. - get keepalive () { - webidl.brandCheck(this, Request) - - // The keepalive getter steps are to return this’s request’s keepalive. - return this[kState].keepalive - } - - // Returns a boolean indicating whether or not request is for a reload - // navigation. - get isReloadNavigation () { - webidl.brandCheck(this, Request) - - // The isReloadNavigation getter steps are to return true if this’s - // request’s reload-navigation flag is set; otherwise false. - return this[kState].reloadNavigation - } - - // Returns a boolean indicating whether or not request is for a history - // navigation (a.k.a. back-foward navigation). - get isHistoryNavigation () { - webidl.brandCheck(this, Request) - - // The isHistoryNavigation getter steps are to return true if this’s request’s - // history-navigation flag is set; otherwise false. - return this[kState].historyNavigation - } - - // Returns the signal associated with request, which is an AbortSignal - // object indicating whether or not request has been aborted, and its - // abort event handler. - get signal () { - webidl.brandCheck(this, Request) - - // The signal getter steps are to return this’s signal. - return this[kSignal] - } - - get body () { - webidl.brandCheck(this, Request) - - return this[kState].body ? this[kState].body.stream : null - } - - get bodyUsed () { - webidl.brandCheck(this, Request) - - return !!this[kState].body && util.isDisturbed(this[kState].body.stream) - } - - get duplex () { - webidl.brandCheck(this, Request) - - return 'half' - } - - // Returns a clone of request. - clone () { - webidl.brandCheck(this, Request) - - // 1. If this is unusable, then throw a TypeError. - if (this.bodyUsed || this.body?.locked) { - throw new TypeError('unusable') - } - - // 2. Let clonedRequest be the result of cloning this’s request. - const clonedRequest = cloneRequest(this[kState]) - - // 3. Let clonedRequestObject be the result of creating a Request object, - // given clonedRequest, this’s headers’s guard, and this’s relevant Realm. - const clonedRequestObject = new Request(kInit) - clonedRequestObject[kState] = clonedRequest - clonedRequestObject[kRealm] = this[kRealm] - clonedRequestObject[kHeaders] = new Headers() - clonedRequestObject[kHeaders][kHeadersList] = clonedRequest.headersList - clonedRequestObject[kHeaders][kGuard] = this[kHeaders][kGuard] - clonedRequestObject[kHeaders][kRealm] = this[kHeaders][kRealm] - - // 4. Make clonedRequestObject’s signal follow this’s signal. - const ac = new AbortController() - if (this.signal.aborted) { - ac.abort(this.signal.reason) - } else { - util.addAbortListener( - this.signal, - () => { - ac.abort(this.signal.reason) - } - ) - } - clonedRequestObject[kSignal] = ac.signal - - // 4. Return clonedRequestObject. - return clonedRequestObject - } -} - -mixinBody(Request) - -function makeRequest (init) { - // https://fetch.spec.whatwg.org/#requests - const request = { - method: 'GET', - localURLsOnly: false, - unsafeRequest: false, - body: null, - client: null, - reservedClient: null, - replacesClientId: '', - window: 'client', - keepalive: false, - serviceWorkers: 'all', - initiator: '', - destination: '', - priority: null, - origin: 'client', - policyContainer: 'client', - referrer: 'client', - referrerPolicy: '', - mode: 'no-cors', - useCORSPreflightFlag: false, - credentials: 'same-origin', - useCredentials: false, - cache: 'default', - redirect: 'follow', - integrity: '', - cryptoGraphicsNonceMetadata: '', - parserMetadata: '', - reloadNavigation: false, - historyNavigation: false, - userActivation: false, - taintedOrigin: false, - redirectCount: 0, - responseTainting: 'basic', - preventNoCacheCacheControlHeaderModification: false, - done: false, - timingAllowFailed: false, - ...init, - headersList: init.headersList - ? new HeadersList(init.headersList) - : new HeadersList() - } - request.url = request.urlList[0] - return request -} - -// https://fetch.spec.whatwg.org/#concept-request-clone -function cloneRequest (request) { - // To clone a request request, run these steps: - - // 1. Let newRequest be a copy of request, except for its body. - const newRequest = makeRequest({ ...request, body: null }) - - // 2. If request’s body is non-null, set newRequest’s body to the - // result of cloning request’s body. - if (request.body != null) { - newRequest.body = cloneBody(request.body) - } - - // 3. Return newRequest. - return newRequest -} - -Object.defineProperties(Request.prototype, { - method: kEnumerableProperty, - url: kEnumerableProperty, - headers: kEnumerableProperty, - redirect: kEnumerableProperty, - clone: kEnumerableProperty, - signal: kEnumerableProperty, - duplex: kEnumerableProperty, - destination: kEnumerableProperty, - body: kEnumerableProperty, - bodyUsed: kEnumerableProperty, - isHistoryNavigation: kEnumerableProperty, - isReloadNavigation: kEnumerableProperty, - keepalive: kEnumerableProperty, - integrity: kEnumerableProperty, - cache: kEnumerableProperty, - credentials: kEnumerableProperty, - attribute: kEnumerableProperty, - referrerPolicy: kEnumerableProperty, - referrer: kEnumerableProperty, - mode: kEnumerableProperty, - [Symbol.toStringTag]: { - value: 'Request', - configurable: true - } -}) - -webidl.converters.Request = webidl.interfaceConverter( - Request -) - -// https://fetch.spec.whatwg.org/#requestinfo -webidl.converters.RequestInfo = function (V) { - if (typeof V === 'string') { - return webidl.converters.USVString(V) - } - - if (V instanceof Request) { - return webidl.converters.Request(V) - } - - return webidl.converters.USVString(V) -} - -webidl.converters.AbortSignal = webidl.interfaceConverter( - AbortSignal -) - -// https://fetch.spec.whatwg.org/#requestinit -webidl.converters.RequestInit = webidl.dictionaryConverter([ - { - key: 'method', - converter: webidl.converters.ByteString - }, - { - key: 'headers', - converter: webidl.converters.HeadersInit - }, - { - key: 'body', - converter: webidl.nullableConverter( - webidl.converters.BodyInit - ) - }, - { - key: 'referrer', - converter: webidl.converters.USVString - }, - { - key: 'referrerPolicy', - converter: webidl.converters.DOMString, - // https://w3c.github.io/webappsec-referrer-policy/#referrer-policy - allowedValues: referrerPolicy - }, - { - key: 'mode', - converter: webidl.converters.DOMString, - // https://fetch.spec.whatwg.org/#concept-request-mode - allowedValues: requestMode - }, - { - key: 'credentials', - converter: webidl.converters.DOMString, - // https://fetch.spec.whatwg.org/#requestcredentials - allowedValues: requestCredentials - }, - { - key: 'cache', - converter: webidl.converters.DOMString, - // https://fetch.spec.whatwg.org/#requestcache - allowedValues: requestCache - }, - { - key: 'redirect', - converter: webidl.converters.DOMString, - // https://fetch.spec.whatwg.org/#requestredirect - allowedValues: requestRedirect - }, - { - key: 'integrity', - converter: webidl.converters.DOMString - }, - { - key: 'keepalive', - converter: webidl.converters.boolean - }, - { - key: 'signal', - converter: webidl.nullableConverter( - (signal) => webidl.converters.AbortSignal( - signal, - { strict: false } - ) - ) - }, - { - key: 'window', - converter: webidl.converters.any - }, - { - key: 'duplex', - converter: webidl.converters.DOMString, - allowedValues: requestDuplex - } -]) - -module.exports = { Request, makeRequest } - - -/***/ }), - -/***/ 1570: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { Headers, HeadersList, fill } = __nccwpck_require__(7967) -const { extractBody, cloneBody, mixinBody } = __nccwpck_require__(6770) -const util = __nccwpck_require__(6223) -const { kEnumerableProperty } = util -const { - isValidReasonPhrase, - isCancelled, - isAborted, - isBlobLike, - serializeJavascriptValueToJSONString, - isErrorLike, - isomorphicEncode -} = __nccwpck_require__(6913) -const { - redirectStatusSet, - nullBodyStatus, - DOMException -} = __nccwpck_require__(7213) -const { kState, kHeaders, kGuard, kRealm } = __nccwpck_require__(1048) -const { webidl } = __nccwpck_require__(5337) -const { FormData } = __nccwpck_require__(4595) -const { getGlobalOrigin } = __nccwpck_require__(4428) -const { URLSerializer } = __nccwpck_require__(6822) -const { kHeadersList } = __nccwpck_require__(1439) -const assert = __nccwpck_require__(9491) -const { types } = __nccwpck_require__(3837) - -const ReadableStream = globalThis.ReadableStream || (__nccwpck_require__(5356).ReadableStream) -const textEncoder = new TextEncoder('utf-8') - -// https://fetch.spec.whatwg.org/#response-class -class Response { - // Creates network error Response. - static error () { - // TODO - const relevantRealm = { settingsObject: {} } - - // The static error() method steps are to return the result of creating a - // Response object, given a new network error, "immutable", and this’s - // relevant Realm. - const responseObject = new Response() - responseObject[kState] = makeNetworkError() - responseObject[kRealm] = relevantRealm - responseObject[kHeaders][kHeadersList] = responseObject[kState].headersList - responseObject[kHeaders][kGuard] = 'immutable' - responseObject[kHeaders][kRealm] = relevantRealm - return responseObject - } - - // https://fetch.spec.whatwg.org/#dom-response-json - static json (data, init = {}) { - webidl.argumentLengthCheck(arguments, 1, { header: 'Response.json' }) - - if (init !== null) { - init = webidl.converters.ResponseInit(init) - } - - // 1. Let bytes the result of running serialize a JavaScript value to JSON bytes on data. - const bytes = textEncoder.encode( - serializeJavascriptValueToJSONString(data) - ) - - // 2. Let body be the result of extracting bytes. - const body = extractBody(bytes) - - // 3. Let responseObject be the result of creating a Response object, given a new response, - // "response", and this’s relevant Realm. - const relevantRealm = { settingsObject: {} } - const responseObject = new Response() - responseObject[kRealm] = relevantRealm - responseObject[kHeaders][kGuard] = 'response' - responseObject[kHeaders][kRealm] = relevantRealm - - // 4. Perform initialize a response given responseObject, init, and (body, "application/json"). - initializeResponse(responseObject, init, { body: body[0], type: 'application/json' }) - - // 5. Return responseObject. - return responseObject - } - - // Creates a redirect Response that redirects to url with status status. - static redirect (url, status = 302) { - const relevantRealm = { settingsObject: {} } - - webidl.argumentLengthCheck(arguments, 1, { header: 'Response.redirect' }) - - url = webidl.converters.USVString(url) - status = webidl.converters['unsigned short'](status) - - // 1. Let parsedURL be the result of parsing url with current settings - // object’s API base URL. - // 2. If parsedURL is failure, then throw a TypeError. - // TODO: base-URL? - let parsedURL - try { - parsedURL = new URL(url, getGlobalOrigin()) - } catch (err) { - throw Object.assign(new TypeError('Failed to parse URL from ' + url), { - cause: err - }) - } - - // 3. If status is not a redirect status, then throw a RangeError. - if (!redirectStatusSet.has(status)) { - throw new RangeError('Invalid status code ' + status) - } - - // 4. Let responseObject be the result of creating a Response object, - // given a new response, "immutable", and this’s relevant Realm. - const responseObject = new Response() - responseObject[kRealm] = relevantRealm - responseObject[kHeaders][kGuard] = 'immutable' - responseObject[kHeaders][kRealm] = relevantRealm - - // 5. Set responseObject’s response’s status to status. - responseObject[kState].status = status - - // 6. Let value be parsedURL, serialized and isomorphic encoded. - const value = isomorphicEncode(URLSerializer(parsedURL)) - - // 7. Append `Location`/value to responseObject’s response’s header list. - responseObject[kState].headersList.append('location', value) - - // 8. Return responseObject. - return responseObject - } - - // https://fetch.spec.whatwg.org/#dom-response - constructor (body = null, init = {}) { - if (body !== null) { - body = webidl.converters.BodyInit(body) - } - - init = webidl.converters.ResponseInit(init) - - // TODO - this[kRealm] = { settingsObject: {} } - - // 1. Set this’s response to a new response. - this[kState] = makeResponse({}) - - // 2. Set this’s headers to a new Headers object with this’s relevant - // Realm, whose header list is this’s response’s header list and guard - // is "response". - this[kHeaders] = new Headers() - this[kHeaders][kGuard] = 'response' - this[kHeaders][kHeadersList] = this[kState].headersList - this[kHeaders][kRealm] = this[kRealm] - - // 3. Let bodyWithType be null. - let bodyWithType = null - - // 4. If body is non-null, then set bodyWithType to the result of extracting body. - if (body != null) { - const [extractedBody, type] = extractBody(body) - bodyWithType = { body: extractedBody, type } - } - - // 5. Perform initialize a response given this, init, and bodyWithType. - initializeResponse(this, init, bodyWithType) - } - - // Returns response’s type, e.g., "cors". - get type () { - webidl.brandCheck(this, Response) - - // The type getter steps are to return this’s response’s type. - return this[kState].type - } - - // Returns response’s URL, if it has one; otherwise the empty string. - get url () { - webidl.brandCheck(this, Response) - - const urlList = this[kState].urlList - - // The url getter steps are to return the empty string if this’s - // response’s URL is null; otherwise this’s response’s URL, - // serialized with exclude fragment set to true. - const url = urlList[urlList.length - 1] ?? null - - if (url === null) { - return '' - } - - return URLSerializer(url, true) - } - - // Returns whether response was obtained through a redirect. - get redirected () { - webidl.brandCheck(this, Response) - - // The redirected getter steps are to return true if this’s response’s URL - // list has more than one item; otherwise false. - return this[kState].urlList.length > 1 - } - - // Returns response’s status. - get status () { - webidl.brandCheck(this, Response) - - // The status getter steps are to return this’s response’s status. - return this[kState].status - } - - // Returns whether response’s status is an ok status. - get ok () { - webidl.brandCheck(this, Response) - - // The ok getter steps are to return true if this’s response’s status is an - // ok status; otherwise false. - return this[kState].status >= 200 && this[kState].status <= 299 - } - - // Returns response’s status message. - get statusText () { - webidl.brandCheck(this, Response) - - // The statusText getter steps are to return this’s response’s status - // message. - return this[kState].statusText - } - - // Returns response’s headers as Headers. - get headers () { - webidl.brandCheck(this, Response) - - // The headers getter steps are to return this’s headers. - return this[kHeaders] - } - - get body () { - webidl.brandCheck(this, Response) - - return this[kState].body ? this[kState].body.stream : null - } - - get bodyUsed () { - webidl.brandCheck(this, Response) - - return !!this[kState].body && util.isDisturbed(this[kState].body.stream) - } - - // Returns a clone of response. - clone () { - webidl.brandCheck(this, Response) - - // 1. If this is unusable, then throw a TypeError. - if (this.bodyUsed || (this.body && this.body.locked)) { - throw webidl.errors.exception({ - header: 'Response.clone', - message: 'Body has already been consumed.' - }) - } - - // 2. Let clonedResponse be the result of cloning this’s response. - const clonedResponse = cloneResponse(this[kState]) - - // 3. Return the result of creating a Response object, given - // clonedResponse, this’s headers’s guard, and this’s relevant Realm. - const clonedResponseObject = new Response() - clonedResponseObject[kState] = clonedResponse - clonedResponseObject[kRealm] = this[kRealm] - clonedResponseObject[kHeaders][kHeadersList] = clonedResponse.headersList - clonedResponseObject[kHeaders][kGuard] = this[kHeaders][kGuard] - clonedResponseObject[kHeaders][kRealm] = this[kHeaders][kRealm] - - return clonedResponseObject - } -} - -mixinBody(Response) - -Object.defineProperties(Response.prototype, { - type: kEnumerableProperty, - url: kEnumerableProperty, - status: kEnumerableProperty, - ok: kEnumerableProperty, - redirected: kEnumerableProperty, - statusText: kEnumerableProperty, - headers: kEnumerableProperty, - clone: kEnumerableProperty, - body: kEnumerableProperty, - bodyUsed: kEnumerableProperty, - [Symbol.toStringTag]: { - value: 'Response', - configurable: true - } -}) - -Object.defineProperties(Response, { - json: kEnumerableProperty, - redirect: kEnumerableProperty, - error: kEnumerableProperty -}) - -// https://fetch.spec.whatwg.org/#concept-response-clone -function cloneResponse (response) { - // To clone a response response, run these steps: - - // 1. If response is a filtered response, then return a new identical - // filtered response whose internal response is a clone of response’s - // internal response. - if (response.internalResponse) { - return filterResponse( - cloneResponse(response.internalResponse), - response.type - ) - } - - // 2. Let newResponse be a copy of response, except for its body. - const newResponse = makeResponse({ ...response, body: null }) - - // 3. If response’s body is non-null, then set newResponse’s body to the - // result of cloning response’s body. - if (response.body != null) { - newResponse.body = cloneBody(response.body) - } - - // 4. Return newResponse. - return newResponse -} - -function makeResponse (init) { - return { - aborted: false, - rangeRequested: false, - timingAllowPassed: false, - requestIncludesCredentials: false, - type: 'default', - status: 200, - timingInfo: null, - cacheState: '', - statusText: '', - ...init, - headersList: init.headersList - ? new HeadersList(init.headersList) - : new HeadersList(), - urlList: init.urlList ? [...init.urlList] : [] - } -} - -function makeNetworkError (reason) { - const isError = isErrorLike(reason) - return makeResponse({ - type: 'error', - status: 0, - error: isError - ? reason - : new Error(reason ? String(reason) : reason), - aborted: reason && reason.name === 'AbortError' - }) -} - -function makeFilteredResponse (response, state) { - state = { - internalResponse: response, - ...state - } - - return new Proxy(response, { - get (target, p) { - return p in state ? state[p] : target[p] - }, - set (target, p, value) { - assert(!(p in state)) - target[p] = value - return true - } - }) -} - -// https://fetch.spec.whatwg.org/#concept-filtered-response -function filterResponse (response, type) { - // Set response to the following filtered response with response as its - // internal response, depending on request’s response tainting: - if (type === 'basic') { - // A basic filtered response is a filtered response whose type is "basic" - // and header list excludes any headers in internal response’s header list - // whose name is a forbidden response-header name. - - // Note: undici does not implement forbidden response-header names - return makeFilteredResponse(response, { - type: 'basic', - headersList: response.headersList - }) - } else if (type === 'cors') { - // A CORS filtered response is a filtered response whose type is "cors" - // and header list excludes any headers in internal response’s header - // list whose name is not a CORS-safelisted response-header name, given - // internal response’s CORS-exposed header-name list. - - // Note: undici does not implement CORS-safelisted response-header names - return makeFilteredResponse(response, { - type: 'cors', - headersList: response.headersList - }) - } else if (type === 'opaque') { - // An opaque filtered response is a filtered response whose type is - // "opaque", URL list is the empty list, status is 0, status message - // is the empty byte sequence, header list is empty, and body is null. - - return makeFilteredResponse(response, { - type: 'opaque', - urlList: Object.freeze([]), - status: 0, - statusText: '', - body: null - }) - } else if (type === 'opaqueredirect') { - // An opaque-redirect filtered response is a filtered response whose type - // is "opaqueredirect", status is 0, status message is the empty byte - // sequence, header list is empty, and body is null. - - return makeFilteredResponse(response, { - type: 'opaqueredirect', - status: 0, - statusText: '', - headersList: [], - body: null - }) - } else { - assert(false) - } -} - -// https://fetch.spec.whatwg.org/#appropriate-network-error -function makeAppropriateNetworkError (fetchParams, err = null) { - // 1. Assert: fetchParams is canceled. - assert(isCancelled(fetchParams)) - - // 2. Return an aborted network error if fetchParams is aborted; - // otherwise return a network error. - return isAborted(fetchParams) - ? makeNetworkError(Object.assign(new DOMException('The operation was aborted.', 'AbortError'), { cause: err })) - : makeNetworkError(Object.assign(new DOMException('Request was cancelled.'), { cause: err })) -} - -// https://whatpr.org/fetch/1392.html#initialize-a-response -function initializeResponse (response, init, body) { - // 1. If init["status"] is not in the range 200 to 599, inclusive, then - // throw a RangeError. - if (init.status !== null && (init.status < 200 || init.status > 599)) { - throw new RangeError('init["status"] must be in the range of 200 to 599, inclusive.') - } - - // 2. If init["statusText"] does not match the reason-phrase token production, - // then throw a TypeError. - if ('statusText' in init && init.statusText != null) { - // See, https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2: - // reason-phrase = *( HTAB / SP / VCHAR / obs-text ) - if (!isValidReasonPhrase(String(init.statusText))) { - throw new TypeError('Invalid statusText') - } - } - - // 3. Set response’s response’s status to init["status"]. - if ('status' in init && init.status != null) { - response[kState].status = init.status - } - - // 4. Set response’s response’s status message to init["statusText"]. - if ('statusText' in init && init.statusText != null) { - response[kState].statusText = init.statusText - } - - // 5. If init["headers"] exists, then fill response’s headers with init["headers"]. - if ('headers' in init && init.headers != null) { - fill(response[kHeaders], init.headers) - } - - // 6. If body was given, then: - if (body) { - // 1. If response's status is a null body status, then throw a TypeError. - if (nullBodyStatus.includes(response.status)) { - throw webidl.errors.exception({ - header: 'Response constructor', - message: 'Invalid response status code ' + response.status - }) - } - - // 2. Set response's body to body's body. - response[kState].body = body.body - - // 3. If body's type is non-null and response's header list does not contain - // `Content-Type`, then append (`Content-Type`, body's type) to response's header list. - if (body.type != null && !response[kState].headersList.contains('Content-Type')) { - response[kState].headersList.append('content-type', body.type) - } - } -} - -webidl.converters.ReadableStream = webidl.interfaceConverter( - ReadableStream -) - -webidl.converters.FormData = webidl.interfaceConverter( - FormData -) - -webidl.converters.URLSearchParams = webidl.interfaceConverter( - URLSearchParams -) - -// https://fetch.spec.whatwg.org/#typedefdef-xmlhttprequestbodyinit -webidl.converters.XMLHttpRequestBodyInit = function (V) { - if (typeof V === 'string') { - return webidl.converters.USVString(V) - } - - if (isBlobLike(V)) { - return webidl.converters.Blob(V, { strict: false }) - } - - if ( - types.isAnyArrayBuffer(V) || - types.isTypedArray(V) || - types.isDataView(V) - ) { - return webidl.converters.BufferSource(V) - } - - if (util.isFormDataLike(V)) { - return webidl.converters.FormData(V, { strict: false }) - } - - if (V instanceof URLSearchParams) { - return webidl.converters.URLSearchParams(V) - } - - return webidl.converters.DOMString(V) -} - -// https://fetch.spec.whatwg.org/#bodyinit -webidl.converters.BodyInit = function (V) { - if (V instanceof ReadableStream) { - return webidl.converters.ReadableStream(V) - } - - // Note: the spec doesn't include async iterables, - // this is an undici extension. - if (V?.[Symbol.asyncIterator]) { - return V - } - - return webidl.converters.XMLHttpRequestBodyInit(V) -} - -webidl.converters.ResponseInit = webidl.dictionaryConverter([ - { - key: 'status', - converter: webidl.converters['unsigned short'], - defaultValue: 200 - }, - { - key: 'statusText', - converter: webidl.converters.ByteString, - defaultValue: '' - }, - { - key: 'headers', - converter: webidl.converters.HeadersInit - } -]) - -module.exports = { - makeNetworkError, - makeResponse, - makeAppropriateNetworkError, - filterResponse, - Response, - cloneResponse -} - - -/***/ }), - -/***/ 1048: -/***/ ((module) => { - -"use strict"; - - -module.exports = { - kUrl: Symbol('url'), - kHeaders: Symbol('headers'), - kSignal: Symbol('signal'), - kState: Symbol('state'), - kGuard: Symbol('guard'), - kRealm: Symbol('realm') -} - - -/***/ }), - -/***/ 6913: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet } = __nccwpck_require__(7213) -const { getGlobalOrigin } = __nccwpck_require__(4428) -const { performance } = __nccwpck_require__(4074) -const { isBlobLike, toUSVString, ReadableStreamFrom } = __nccwpck_require__(6223) -const assert = __nccwpck_require__(9491) -const { isUint8Array } = __nccwpck_require__(9830) - -// https://nodejs.org/api/crypto.html#determining-if-crypto-support-is-unavailable -/** @type {import('crypto')|undefined} */ -let crypto - -try { - crypto = __nccwpck_require__(6113) -} catch { - -} - -function responseURL (response) { - // https://fetch.spec.whatwg.org/#responses - // A response has an associated URL. It is a pointer to the last URL - // in response’s URL list and null if response’s URL list is empty. - const urlList = response.urlList - const length = urlList.length - return length === 0 ? null : urlList[length - 1].toString() -} - -// https://fetch.spec.whatwg.org/#concept-response-location-url -function responseLocationURL (response, requestFragment) { - // 1. If response’s status is not a redirect status, then return null. - if (!redirectStatusSet.has(response.status)) { - return null - } - - // 2. Let location be the result of extracting header list values given - // `Location` and response’s header list. - let location = response.headersList.get('location') - - // 3. If location is a header value, then set location to the result of - // parsing location with response’s URL. - if (location !== null && isValidHeaderValue(location)) { - location = new URL(location, responseURL(response)) - } - - // 4. If location is a URL whose fragment is null, then set location’s - // fragment to requestFragment. - if (location && !location.hash) { - location.hash = requestFragment - } - - // 5. Return location. - return location -} - -/** @returns {URL} */ -function requestCurrentURL (request) { - return request.urlList[request.urlList.length - 1] -} - -function requestBadPort (request) { - // 1. Let url be request’s current URL. - const url = requestCurrentURL(request) - - // 2. If url’s scheme is an HTTP(S) scheme and url’s port is a bad port, - // then return blocked. - if (urlIsHttpHttpsScheme(url) && badPortsSet.has(url.port)) { - return 'blocked' - } - - // 3. Return allowed. - return 'allowed' -} - -function isErrorLike (object) { - return object instanceof Error || ( - object?.constructor?.name === 'Error' || - object?.constructor?.name === 'DOMException' - ) -} - -// Check whether |statusText| is a ByteString and -// matches the Reason-Phrase token production. -// RFC 2616: https://tools.ietf.org/html/rfc2616 -// RFC 7230: https://tools.ietf.org/html/rfc7230 -// "reason-phrase = *( HTAB / SP / VCHAR / obs-text )" -// https://github.com/chromium/chromium/blob/94.0.4604.1/third_party/blink/renderer/core/fetch/response.cc#L116 -function isValidReasonPhrase (statusText) { - for (let i = 0; i < statusText.length; ++i) { - const c = statusText.charCodeAt(i) - if ( - !( - ( - c === 0x09 || // HTAB - (c >= 0x20 && c <= 0x7e) || // SP / VCHAR - (c >= 0x80 && c <= 0xff) - ) // obs-text - ) - ) { - return false - } - } - return true -} - -function isTokenChar (c) { - return !( - c >= 0x7f || - c <= 0x20 || - c === '(' || - c === ')' || - c === '<' || - c === '>' || - c === '@' || - c === ',' || - c === ';' || - c === ':' || - c === '\\' || - c === '"' || - c === '/' || - c === '[' || - c === ']' || - c === '?' || - c === '=' || - c === '{' || - c === '}' - ) -} - -// See RFC 7230, Section 3.2.6. -// https://github.com/chromium/chromium/blob/d7da0240cae77824d1eda25745c4022757499131/third_party/blink/renderer/platform/network/http_parsers.cc#L321 -function isValidHTTPToken (characters) { - if (!characters || typeof characters !== 'string') { - return false - } - for (let i = 0; i < characters.length; ++i) { - const c = characters.charCodeAt(i) - if (c > 0x7f || !isTokenChar(c)) { - return false - } - } - return true -} - -// https://fetch.spec.whatwg.org/#header-name -// https://github.com/chromium/chromium/blob/b3d37e6f94f87d59e44662d6078f6a12de845d17/net/http/http_util.cc#L342 -function isValidHeaderName (potentialValue) { - if (potentialValue.length === 0) { - return false - } - - return isValidHTTPToken(potentialValue) -} - -/** - * @see https://fetch.spec.whatwg.org/#header-value - * @param {string} potentialValue - */ -function isValidHeaderValue (potentialValue) { - // - Has no leading or trailing HTTP tab or space bytes. - // - Contains no 0x00 (NUL) or HTTP newline bytes. - if ( - potentialValue.startsWith('\t') || - potentialValue.startsWith(' ') || - potentialValue.endsWith('\t') || - potentialValue.endsWith(' ') - ) { - return false - } - - if ( - potentialValue.includes('\0') || - potentialValue.includes('\r') || - potentialValue.includes('\n') - ) { - return false - } - - return true -} - -// https://w3c.github.io/webappsec-referrer-policy/#set-requests-referrer-policy-on-redirect -function setRequestReferrerPolicyOnRedirect (request, actualResponse) { - // Given a request request and a response actualResponse, this algorithm - // updates request’s referrer policy according to the Referrer-Policy - // header (if any) in actualResponse. - - // 1. Let policy be the result of executing § 8.1 Parse a referrer policy - // from a Referrer-Policy header on actualResponse. - - // 8.1 Parse a referrer policy from a Referrer-Policy header - // 1. Let policy-tokens be the result of extracting header list values given `Referrer-Policy` and response’s header list. - const { headersList } = actualResponse - // 2. Let policy be the empty string. - // 3. For each token in policy-tokens, if token is a referrer policy and token is not the empty string, then set policy to token. - // 4. Return policy. - const policyHeader = (headersList.get('referrer-policy') ?? '').split(',') - - // Note: As the referrer-policy can contain multiple policies - // separated by comma, we need to loop through all of them - // and pick the first valid one. - // Ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#specify_a_fallback_policy - let policy = '' - if (policyHeader.length > 0) { - // The right-most policy takes precedence. - // The left-most policy is the fallback. - for (let i = policyHeader.length; i !== 0; i--) { - const token = policyHeader[i - 1].trim() - if (referrerPolicyTokens.has(token)) { - policy = token - break - } - } - } - - // 2. If policy is not the empty string, then set request’s referrer policy to policy. - if (policy !== '') { - request.referrerPolicy = policy - } -} - -// https://fetch.spec.whatwg.org/#cross-origin-resource-policy-check -function crossOriginResourcePolicyCheck () { - // TODO - return 'allowed' -} - -// https://fetch.spec.whatwg.org/#concept-cors-check -function corsCheck () { - // TODO - return 'success' -} - -// https://fetch.spec.whatwg.org/#concept-tao-check -function TAOCheck () { - // TODO - return 'success' -} - -function appendFetchMetadata (httpRequest) { - // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-dest-header - // TODO - - // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-mode-header - - // 1. Assert: r’s url is a potentially trustworthy URL. - // TODO - - // 2. Let header be a Structured Header whose value is a token. - let header = null - - // 3. Set header’s value to r’s mode. - header = httpRequest.mode - - // 4. Set a structured field value `Sec-Fetch-Mode`/header in r’s header list. - httpRequest.headersList.set('sec-fetch-mode', header) - - // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-site-header - // TODO - - // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-user-header - // TODO -} - -// https://fetch.spec.whatwg.org/#append-a-request-origin-header -function appendRequestOriginHeader (request) { - // 1. Let serializedOrigin be the result of byte-serializing a request origin with request. - let serializedOrigin = request.origin - - // 2. If request’s response tainting is "cors" or request’s mode is "websocket", then append (`Origin`, serializedOrigin) to request’s header list. - if (request.responseTainting === 'cors' || request.mode === 'websocket') { - if (serializedOrigin) { - request.headersList.append('origin', serializedOrigin) - } - - // 3. Otherwise, if request’s method is neither `GET` nor `HEAD`, then: - } else if (request.method !== 'GET' && request.method !== 'HEAD') { - // 1. Switch on request’s referrer policy: - switch (request.referrerPolicy) { - case 'no-referrer': - // Set serializedOrigin to `null`. - serializedOrigin = null - break - case 'no-referrer-when-downgrade': - case 'strict-origin': - case 'strict-origin-when-cross-origin': - // If request’s origin is a tuple origin, its scheme is "https", and request’s current URL’s scheme is not "https", then set serializedOrigin to `null`. - if (request.origin && urlHasHttpsScheme(request.origin) && !urlHasHttpsScheme(requestCurrentURL(request))) { - serializedOrigin = null - } - break - case 'same-origin': - // If request’s origin is not same origin with request’s current URL’s origin, then set serializedOrigin to `null`. - if (!sameOrigin(request, requestCurrentURL(request))) { - serializedOrigin = null - } - break - default: - // Do nothing. - } - - if (serializedOrigin) { - // 2. Append (`Origin`, serializedOrigin) to request’s header list. - request.headersList.append('origin', serializedOrigin) - } - } -} - -function coarsenedSharedCurrentTime (crossOriginIsolatedCapability) { - // TODO - return performance.now() -} - -// https://fetch.spec.whatwg.org/#create-an-opaque-timing-info -function createOpaqueTimingInfo (timingInfo) { - return { - startTime: timingInfo.startTime ?? 0, - redirectStartTime: 0, - redirectEndTime: 0, - postRedirectStartTime: timingInfo.startTime ?? 0, - finalServiceWorkerStartTime: 0, - finalNetworkResponseStartTime: 0, - finalNetworkRequestStartTime: 0, - endTime: 0, - encodedBodySize: 0, - decodedBodySize: 0, - finalConnectionTimingInfo: null - } -} - -// https://html.spec.whatwg.org/multipage/origin.html#policy-container -function makePolicyContainer () { - // Note: the fetch spec doesn't make use of embedder policy or CSP list - return { - referrerPolicy: 'strict-origin-when-cross-origin' - } -} - -// https://html.spec.whatwg.org/multipage/origin.html#clone-a-policy-container -function clonePolicyContainer (policyContainer) { - return { - referrerPolicy: policyContainer.referrerPolicy - } -} - -// https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer -function determineRequestsReferrer (request) { - // 1. Let policy be request's referrer policy. - const policy = request.referrerPolicy - - // Note: policy cannot (shouldn't) be null or an empty string. - assert(policy) - - // 2. Let environment be request’s client. - - let referrerSource = null - - // 3. Switch on request’s referrer: - if (request.referrer === 'client') { - // Note: node isn't a browser and doesn't implement document/iframes, - // so we bypass this step and replace it with our own. - - const globalOrigin = getGlobalOrigin() - - if (!globalOrigin || globalOrigin.origin === 'null') { - return 'no-referrer' - } - - // note: we need to clone it as it's mutated - referrerSource = new URL(globalOrigin) - } else if (request.referrer instanceof URL) { - // Let referrerSource be request’s referrer. - referrerSource = request.referrer - } - - // 4. Let request’s referrerURL be the result of stripping referrerSource for - // use as a referrer. - let referrerURL = stripURLForReferrer(referrerSource) - - // 5. Let referrerOrigin be the result of stripping referrerSource for use as - // a referrer, with the origin-only flag set to true. - const referrerOrigin = stripURLForReferrer(referrerSource, true) - - // 6. If the result of serializing referrerURL is a string whose length is - // greater than 4096, set referrerURL to referrerOrigin. - if (referrerURL.toString().length > 4096) { - referrerURL = referrerOrigin - } - - const areSameOrigin = sameOrigin(request, referrerURL) - const isNonPotentiallyTrustWorthy = isURLPotentiallyTrustworthy(referrerURL) && - !isURLPotentiallyTrustworthy(request.url) - - // 8. Execute the switch statements corresponding to the value of policy: - switch (policy) { - case 'origin': return referrerOrigin != null ? referrerOrigin : stripURLForReferrer(referrerSource, true) - case 'unsafe-url': return referrerURL - case 'same-origin': - return areSameOrigin ? referrerOrigin : 'no-referrer' - case 'origin-when-cross-origin': - return areSameOrigin ? referrerURL : referrerOrigin - case 'strict-origin-when-cross-origin': { - const currentURL = requestCurrentURL(request) - - // 1. If the origin of referrerURL and the origin of request’s current - // URL are the same, then return referrerURL. - if (sameOrigin(referrerURL, currentURL)) { - return referrerURL - } - - // 2. If referrerURL is a potentially trustworthy URL and request’s - // current URL is not a potentially trustworthy URL, then return no - // referrer. - if (isURLPotentiallyTrustworthy(referrerURL) && !isURLPotentiallyTrustworthy(currentURL)) { - return 'no-referrer' - } - - // 3. Return referrerOrigin. - return referrerOrigin - } - case 'strict-origin': // eslint-disable-line - /** - * 1. If referrerURL is a potentially trustworthy URL and - * request’s current URL is not a potentially trustworthy URL, - * then return no referrer. - * 2. Return referrerOrigin - */ - case 'no-referrer-when-downgrade': // eslint-disable-line - /** - * 1. If referrerURL is a potentially trustworthy URL and - * request’s current URL is not a potentially trustworthy URL, - * then return no referrer. - * 2. Return referrerOrigin - */ - - default: // eslint-disable-line - return isNonPotentiallyTrustWorthy ? 'no-referrer' : referrerOrigin - } -} - -/** - * @see https://w3c.github.io/webappsec-referrer-policy/#strip-url - * @param {URL} url - * @param {boolean|undefined} originOnly - */ -function stripURLForReferrer (url, originOnly) { - // 1. Assert: url is a URL. - assert(url instanceof URL) - - // 2. If url’s scheme is a local scheme, then return no referrer. - if (url.protocol === 'file:' || url.protocol === 'about:' || url.protocol === 'blank:') { - return 'no-referrer' - } - - // 3. Set url’s username to the empty string. - url.username = '' - - // 4. Set url’s password to the empty string. - url.password = '' - - // 5. Set url’s fragment to null. - url.hash = '' - - // 6. If the origin-only flag is true, then: - if (originOnly) { - // 1. Set url’s path to « the empty string ». - url.pathname = '' - - // 2. Set url’s query to null. - url.search = '' - } - - // 7. Return url. - return url -} - -function isURLPotentiallyTrustworthy (url) { - if (!(url instanceof URL)) { - return false - } - - // If child of about, return true - if (url.href === 'about:blank' || url.href === 'about:srcdoc') { - return true - } - - // If scheme is data, return true - if (url.protocol === 'data:') return true - - // If file, return true - if (url.protocol === 'file:') return true - - return isOriginPotentiallyTrustworthy(url.origin) - - function isOriginPotentiallyTrustworthy (origin) { - // If origin is explicitly null, return false - if (origin == null || origin === 'null') return false - - const originAsURL = new URL(origin) - - // If secure, return true - if (originAsURL.protocol === 'https:' || originAsURL.protocol === 'wss:') { - return true - } - - // If localhost or variants, return true - if (/^127(?:\.[0-9]+){0,2}\.[0-9]+$|^\[(?:0*:)*?:?0*1\]$/.test(originAsURL.hostname) || - (originAsURL.hostname === 'localhost' || originAsURL.hostname.includes('localhost.')) || - (originAsURL.hostname.endsWith('.localhost'))) { - return true - } - - // If any other, return false - return false - } -} - -/** - * @see https://w3c.github.io/webappsec-subresource-integrity/#does-response-match-metadatalist - * @param {Uint8Array} bytes - * @param {string} metadataList - */ -function bytesMatch (bytes, metadataList) { - // If node is not built with OpenSSL support, we cannot check - // a request's integrity, so allow it by default (the spec will - // allow requests if an invalid hash is given, as precedence). - /* istanbul ignore if: only if node is built with --without-ssl */ - if (crypto === undefined) { - return true - } - - // 1. Let parsedMetadata be the result of parsing metadataList. - const parsedMetadata = parseMetadata(metadataList) - - // 2. If parsedMetadata is no metadata, return true. - if (parsedMetadata === 'no metadata') { - return true - } - - // 3. If parsedMetadata is the empty set, return true. - if (parsedMetadata.length === 0) { - return true - } - - // 4. Let metadata be the result of getting the strongest - // metadata from parsedMetadata. - const list = parsedMetadata.sort((c, d) => d.algo.localeCompare(c.algo)) - // get the strongest algorithm - const strongest = list[0].algo - // get all entries that use the strongest algorithm; ignore weaker - const metadata = list.filter((item) => item.algo === strongest) - - // 5. For each item in metadata: - for (const item of metadata) { - // 1. Let algorithm be the alg component of item. - const algorithm = item.algo - - // 2. Let expectedValue be the val component of item. - let expectedValue = item.hash - - // See https://github.com/web-platform-tests/wpt/commit/e4c5cc7a5e48093220528dfdd1c4012dc3837a0e - // "be liberal with padding". This is annoying, and it's not even in the spec. - - if (expectedValue.endsWith('==')) { - expectedValue = expectedValue.slice(0, -2) - } - - // 3. Let actualValue be the result of applying algorithm to bytes. - let actualValue = crypto.createHash(algorithm).update(bytes).digest('base64') - - if (actualValue.endsWith('==')) { - actualValue = actualValue.slice(0, -2) - } - - // 4. If actualValue is a case-sensitive match for expectedValue, - // return true. - if (actualValue === expectedValue) { - return true - } - - let actualBase64URL = crypto.createHash(algorithm).update(bytes).digest('base64url') - - if (actualBase64URL.endsWith('==')) { - actualBase64URL = actualBase64URL.slice(0, -2) - } - - if (actualBase64URL === expectedValue) { - return true - } - } - - // 6. Return false. - return false -} - -// https://w3c.github.io/webappsec-subresource-integrity/#grammardef-hash-with-options -// https://www.w3.org/TR/CSP2/#source-list-syntax -// https://www.rfc-editor.org/rfc/rfc5234#appendix-B.1 -const parseHashWithOptions = /((?<algo>sha256|sha384|sha512)-(?<hash>[A-z0-9+/]{1}.*={0,2}))( +[\x21-\x7e]?)?/i - -/** - * @see https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata - * @param {string} metadata - */ -function parseMetadata (metadata) { - // 1. Let result be the empty set. - /** @type {{ algo: string, hash: string }[]} */ - const result = [] - - // 2. Let empty be equal to true. - let empty = true - - const supportedHashes = crypto.getHashes() - - // 3. For each token returned by splitting metadata on spaces: - for (const token of metadata.split(' ')) { - // 1. Set empty to false. - empty = false - - // 2. Parse token as a hash-with-options. - const parsedToken = parseHashWithOptions.exec(token) - - // 3. If token does not parse, continue to the next token. - if (parsedToken === null || parsedToken.groups === undefined) { - // Note: Chromium blocks the request at this point, but Firefox - // gives a warning that an invalid integrity was given. The - // correct behavior is to ignore these, and subsequently not - // check the integrity of the resource. - continue - } - - // 4. Let algorithm be the hash-algo component of token. - const algorithm = parsedToken.groups.algo - - // 5. If algorithm is a hash function recognized by the user - // agent, add the parsed token to result. - if (supportedHashes.includes(algorithm.toLowerCase())) { - result.push(parsedToken.groups) - } - } - - // 4. Return no metadata if empty is true, otherwise return result. - if (empty === true) { - return 'no metadata' - } - - return result -} - -// https://w3c.github.io/webappsec-upgrade-insecure-requests/#upgrade-request -function tryUpgradeRequestToAPotentiallyTrustworthyURL (request) { - // TODO -} - -/** - * @link {https://html.spec.whatwg.org/multipage/origin.html#same-origin} - * @param {URL} A - * @param {URL} B - */ -function sameOrigin (A, B) { - // 1. If A and B are the same opaque origin, then return true. - if (A.origin === B.origin && A.origin === 'null') { - return true - } - - // 2. If A and B are both tuple origins and their schemes, - // hosts, and port are identical, then return true. - if (A.protocol === B.protocol && A.hostname === B.hostname && A.port === B.port) { - return true - } - - // 3. Return false. - return false -} - -function createDeferredPromise () { - let res - let rej - const promise = new Promise((resolve, reject) => { - res = resolve - rej = reject - }) - - return { promise, resolve: res, reject: rej } -} - -function isAborted (fetchParams) { - return fetchParams.controller.state === 'aborted' -} - -function isCancelled (fetchParams) { - return fetchParams.controller.state === 'aborted' || - fetchParams.controller.state === 'terminated' -} - -// https://fetch.spec.whatwg.org/#concept-method-normalize -function normalizeMethod (method) { - return /^(DELETE|GET|HEAD|OPTIONS|POST|PUT)$/i.test(method) - ? method.toUpperCase() - : method -} - -// https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string -function serializeJavascriptValueToJSONString (value) { - // 1. Let result be ? Call(%JSON.stringify%, undefined, « value »). - const result = JSON.stringify(value) - - // 2. If result is undefined, then throw a TypeError. - if (result === undefined) { - throw new TypeError('Value is not JSON serializable') - } - - // 3. Assert: result is a string. - assert(typeof result === 'string') - - // 4. Return result. - return result -} - -// https://tc39.es/ecma262/#sec-%25iteratorprototype%25-object -const esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())) - -/** - * @see https://webidl.spec.whatwg.org/#dfn-iterator-prototype-object - * @param {() => unknown[]} iterator - * @param {string} name name of the instance - * @param {'key'|'value'|'key+value'} kind - */ -function makeIterator (iterator, name, kind) { - const object = { - index: 0, - kind, - target: iterator - } - - const i = { - next () { - // 1. Let interface be the interface for which the iterator prototype object exists. - - // 2. Let thisValue be the this value. - - // 3. Let object be ? ToObject(thisValue). - - // 4. If object is a platform object, then perform a security - // check, passing: - - // 5. If object is not a default iterator object for interface, - // then throw a TypeError. - if (Object.getPrototypeOf(this) !== i) { - throw new TypeError( - `'next' called on an object that does not implement interface ${name} Iterator.` - ) - } - - // 6. Let index be object’s index. - // 7. Let kind be object’s kind. - // 8. Let values be object’s target's value pairs to iterate over. - const { index, kind, target } = object - const values = target() - - // 9. Let len be the length of values. - const len = values.length - - // 10. If index is greater than or equal to len, then return - // CreateIterResultObject(undefined, true). - if (index >= len) { - return { value: undefined, done: true } - } - - // 11. Let pair be the entry in values at index index. - const pair = values[index] - - // 12. Set object’s index to index + 1. - object.index = index + 1 - - // 13. Return the iterator result for pair and kind. - return iteratorResult(pair, kind) - }, - // The class string of an iterator prototype object for a given interface is the - // result of concatenating the identifier of the interface and the string " Iterator". - [Symbol.toStringTag]: `${name} Iterator` - } - - // The [[Prototype]] internal slot of an iterator prototype object must be %IteratorPrototype%. - Object.setPrototypeOf(i, esIteratorPrototype) - // esIteratorPrototype needs to be the prototype of i - // which is the prototype of an empty object. Yes, it's confusing. - return Object.setPrototypeOf({}, i) -} - -// https://webidl.spec.whatwg.org/#iterator-result -function iteratorResult (pair, kind) { - let result - - // 1. Let result be a value determined by the value of kind: - switch (kind) { - case 'key': { - // 1. Let idlKey be pair’s key. - // 2. Let key be the result of converting idlKey to an - // ECMAScript value. - // 3. result is key. - result = pair[0] - break - } - case 'value': { - // 1. Let idlValue be pair’s value. - // 2. Let value be the result of converting idlValue to - // an ECMAScript value. - // 3. result is value. - result = pair[1] - break - } - case 'key+value': { - // 1. Let idlKey be pair’s key. - // 2. Let idlValue be pair’s value. - // 3. Let key be the result of converting idlKey to an - // ECMAScript value. - // 4. Let value be the result of converting idlValue to - // an ECMAScript value. - // 5. Let array be ! ArrayCreate(2). - // 6. Call ! CreateDataProperty(array, "0", key). - // 7. Call ! CreateDataProperty(array, "1", value). - // 8. result is array. - result = pair - break - } - } - - // 2. Return CreateIterResultObject(result, false). - return { value: result, done: false } -} - -/** - * @see https://fetch.spec.whatwg.org/#body-fully-read - */ -async function fullyReadBody (body, processBody, processBodyError) { - // 1. If taskDestination is null, then set taskDestination to - // the result of starting a new parallel queue. - - // 2. Let successSteps given a byte sequence bytes be to queue a - // fetch task to run processBody given bytes, with taskDestination. - const successSteps = processBody - - // 3. Let errorSteps be to queue a fetch task to run processBodyError, - // with taskDestination. - const errorSteps = processBodyError - - // 4. Let reader be the result of getting a reader for body’s stream. - // If that threw an exception, then run errorSteps with that - // exception and return. - let reader - - try { - reader = body.stream.getReader() - } catch (e) { - errorSteps(e) - return - } - - // 5. Read all bytes from reader, given successSteps and errorSteps. - try { - const result = await readAllBytes(reader) - successSteps(result) - } catch (e) { - errorSteps(e) - } -} - -/** @type {ReadableStream} */ -let ReadableStream = globalThis.ReadableStream - -function isReadableStreamLike (stream) { - if (!ReadableStream) { - ReadableStream = (__nccwpck_require__(5356).ReadableStream) - } - - return stream instanceof ReadableStream || ( - stream[Symbol.toStringTag] === 'ReadableStream' && - typeof stream.tee === 'function' - ) -} - -const MAXIMUM_ARGUMENT_LENGTH = 65535 - -/** - * @see https://infra.spec.whatwg.org/#isomorphic-decode - * @param {number[]|Uint8Array} input - */ -function isomorphicDecode (input) { - // 1. To isomorphic decode a byte sequence input, return a string whose code point - // length is equal to input’s length and whose code points have the same values - // as the values of input’s bytes, in the same order. - - if (input.length < MAXIMUM_ARGUMENT_LENGTH) { - return String.fromCharCode(...input) - } - - return input.reduce((previous, current) => previous + String.fromCharCode(current), '') -} - -/** - * @param {ReadableStreamController<Uint8Array>} controller - */ -function readableStreamClose (controller) { - try { - controller.close() - } catch (err) { - // TODO: add comment explaining why this error occurs. - if (!err.message.includes('Controller is already closed')) { - throw err - } - } -} - -/** - * @see https://infra.spec.whatwg.org/#isomorphic-encode - * @param {string} input - */ -function isomorphicEncode (input) { - // 1. Assert: input contains no code points greater than U+00FF. - for (let i = 0; i < input.length; i++) { - assert(input.charCodeAt(i) <= 0xFF) - } - - // 2. Return a byte sequence whose length is equal to input’s code - // point length and whose bytes have the same values as the - // values of input’s code points, in the same order - return input -} - -/** - * @see https://streams.spec.whatwg.org/#readablestreamdefaultreader-read-all-bytes - * @see https://streams.spec.whatwg.org/#read-loop - * @param {ReadableStreamDefaultReader} reader - */ -async function readAllBytes (reader) { - const bytes = [] - let byteLength = 0 - - while (true) { - const { done, value: chunk } = await reader.read() - - if (done) { - // 1. Call successSteps with bytes. - return Buffer.concat(bytes, byteLength) - } - - // 1. If chunk is not a Uint8Array object, call failureSteps - // with a TypeError and abort these steps. - if (!isUint8Array(chunk)) { - throw new TypeError('Received non-Uint8Array chunk') - } - - // 2. Append the bytes represented by chunk to bytes. - bytes.push(chunk) - byteLength += chunk.length - - // 3. Read-loop given reader, bytes, successSteps, and failureSteps. - } -} - -/** - * @see https://fetch.spec.whatwg.org/#is-local - * @param {URL} url - */ -function urlIsLocal (url) { - assert('protocol' in url) // ensure it's a url object - - const protocol = url.protocol - - return protocol === 'about:' || protocol === 'blob:' || protocol === 'data:' -} - -/** - * @param {string|URL} url - */ -function urlHasHttpsScheme (url) { - if (typeof url === 'string') { - return url.startsWith('https:') - } - - return url.protocol === 'https:' -} - -/** - * @see https://fetch.spec.whatwg.org/#http-scheme - * @param {URL} url - */ -function urlIsHttpHttpsScheme (url) { - assert('protocol' in url) // ensure it's a url object - - const protocol = url.protocol - - return protocol === 'http:' || protocol === 'https:' -} - -/** - * Fetch supports node >= 16.8.0, but Object.hasOwn was added in v16.9.0. - */ -const hasOwn = Object.hasOwn || ((dict, key) => Object.prototype.hasOwnProperty.call(dict, key)) - -module.exports = { - isAborted, - isCancelled, - createDeferredPromise, - ReadableStreamFrom, - toUSVString, - tryUpgradeRequestToAPotentiallyTrustworthyURL, - coarsenedSharedCurrentTime, - determineRequestsReferrer, - makePolicyContainer, - clonePolicyContainer, - appendFetchMetadata, - appendRequestOriginHeader, - TAOCheck, - corsCheck, - crossOriginResourcePolicyCheck, - createOpaqueTimingInfo, - setRequestReferrerPolicyOnRedirect, - isValidHTTPToken, - requestBadPort, - requestCurrentURL, - responseURL, - responseLocationURL, - isBlobLike, - isURLPotentiallyTrustworthy, - isValidReasonPhrase, - sameOrigin, - normalizeMethod, - serializeJavascriptValueToJSONString, - makeIterator, - isValidHeaderName, - isValidHeaderValue, - hasOwn, - isErrorLike, - fullyReadBody, - bytesMatch, - isReadableStreamLike, - readableStreamClose, - isomorphicEncode, - isomorphicDecode, - urlIsLocal, - urlHasHttpsScheme, - urlIsHttpHttpsScheme, - readAllBytes -} - - -/***/ }), - -/***/ 5337: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { types } = __nccwpck_require__(3837) -const { hasOwn, toUSVString } = __nccwpck_require__(6913) - -/** @type {import('../../types/webidl').Webidl} */ -const webidl = {} -webidl.converters = {} -webidl.util = {} -webidl.errors = {} - -webidl.errors.exception = function (message) { - return new TypeError(`${message.header}: ${message.message}`) -} - -webidl.errors.conversionFailed = function (context) { - const plural = context.types.length === 1 ? '' : ' one of' - const message = - `${context.argument} could not be converted to` + - `${plural}: ${context.types.join(', ')}.` - - return webidl.errors.exception({ - header: context.prefix, - message - }) -} - -webidl.errors.invalidArgument = function (context) { - return webidl.errors.exception({ - header: context.prefix, - message: `"${context.value}" is an invalid ${context.type}.` - }) -} - -// https://webidl.spec.whatwg.org/#implements -webidl.brandCheck = function (V, I, opts = undefined) { - if (opts?.strict !== false && !(V instanceof I)) { - throw new TypeError('Illegal invocation') - } else { - return V?.[Symbol.toStringTag] === I.prototype[Symbol.toStringTag] - } -} - -webidl.argumentLengthCheck = function ({ length }, min, ctx) { - if (length < min) { - throw webidl.errors.exception({ - message: `${min} argument${min !== 1 ? 's' : ''} required, ` + - `but${length ? ' only' : ''} ${length} found.`, - ...ctx - }) - } -} - -webidl.illegalConstructor = function () { - throw webidl.errors.exception({ - header: 'TypeError', - message: 'Illegal constructor' - }) -} - -// https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values -webidl.util.Type = function (V) { - switch (typeof V) { - case 'undefined': return 'Undefined' - case 'boolean': return 'Boolean' - case 'string': return 'String' - case 'symbol': return 'Symbol' - case 'number': return 'Number' - case 'bigint': return 'BigInt' - case 'function': - case 'object': { - if (V === null) { - return 'Null' - } - - return 'Object' - } - } -} - -// https://webidl.spec.whatwg.org/#abstract-opdef-converttoint -webidl.util.ConvertToInt = function (V, bitLength, signedness, opts = {}) { - let upperBound - let lowerBound - - // 1. If bitLength is 64, then: - if (bitLength === 64) { - // 1. Let upperBound be 2^53 − 1. - upperBound = Math.pow(2, 53) - 1 - - // 2. If signedness is "unsigned", then let lowerBound be 0. - if (signedness === 'unsigned') { - lowerBound = 0 - } else { - // 3. Otherwise let lowerBound be −2^53 + 1. - lowerBound = Math.pow(-2, 53) + 1 - } - } else if (signedness === 'unsigned') { - // 2. Otherwise, if signedness is "unsigned", then: - - // 1. Let lowerBound be 0. - lowerBound = 0 - - // 2. Let upperBound be 2^bitLength − 1. - upperBound = Math.pow(2, bitLength) - 1 - } else { - // 3. Otherwise: - - // 1. Let lowerBound be -2^bitLength − 1. - lowerBound = Math.pow(-2, bitLength) - 1 - - // 2. Let upperBound be 2^bitLength − 1 − 1. - upperBound = Math.pow(2, bitLength - 1) - 1 - } - - // 4. Let x be ? ToNumber(V). - let x = Number(V) - - // 5. If x is −0, then set x to +0. - if (x === 0) { - x = 0 - } - - // 6. If the conversion is to an IDL type associated - // with the [EnforceRange] extended attribute, then: - if (opts.enforceRange === true) { - // 1. If x is NaN, +∞, or −∞, then throw a TypeError. - if ( - Number.isNaN(x) || - x === Number.POSITIVE_INFINITY || - x === Number.NEGATIVE_INFINITY - ) { - throw webidl.errors.exception({ - header: 'Integer conversion', - message: `Could not convert ${V} to an integer.` - }) - } - - // 2. Set x to IntegerPart(x). - x = webidl.util.IntegerPart(x) - - // 3. If x < lowerBound or x > upperBound, then - // throw a TypeError. - if (x < lowerBound || x > upperBound) { - throw webidl.errors.exception({ - header: 'Integer conversion', - message: `Value must be between ${lowerBound}-${upperBound}, got ${x}.` - }) - } - - // 4. Return x. - return x - } - - // 7. If x is not NaN and the conversion is to an IDL - // type associated with the [Clamp] extended - // attribute, then: - if (!Number.isNaN(x) && opts.clamp === true) { - // 1. Set x to min(max(x, lowerBound), upperBound). - x = Math.min(Math.max(x, lowerBound), upperBound) - - // 2. Round x to the nearest integer, choosing the - // even integer if it lies halfway between two, - // and choosing +0 rather than −0. - if (Math.floor(x) % 2 === 0) { - x = Math.floor(x) - } else { - x = Math.ceil(x) - } - - // 3. Return x. - return x - } - - // 8. If x is NaN, +0, +∞, or −∞, then return +0. - if ( - Number.isNaN(x) || - (x === 0 && Object.is(0, x)) || - x === Number.POSITIVE_INFINITY || - x === Number.NEGATIVE_INFINITY - ) { - return 0 - } - - // 9. Set x to IntegerPart(x). - x = webidl.util.IntegerPart(x) - - // 10. Set x to x modulo 2^bitLength. - x = x % Math.pow(2, bitLength) - - // 11. If signedness is "signed" and x ≥ 2^bitLength − 1, - // then return x − 2^bitLength. - if (signedness === 'signed' && x >= Math.pow(2, bitLength) - 1) { - return x - Math.pow(2, bitLength) - } - - // 12. Otherwise, return x. - return x -} - -// https://webidl.spec.whatwg.org/#abstract-opdef-integerpart -webidl.util.IntegerPart = function (n) { - // 1. Let r be floor(abs(n)). - const r = Math.floor(Math.abs(n)) - - // 2. If n < 0, then return -1 × r. - if (n < 0) { - return -1 * r - } - - // 3. Otherwise, return r. - return r -} - -// https://webidl.spec.whatwg.org/#es-sequence -webidl.sequenceConverter = function (converter) { - return (V) => { - // 1. If Type(V) is not Object, throw a TypeError. - if (webidl.util.Type(V) !== 'Object') { - throw webidl.errors.exception({ - header: 'Sequence', - message: `Value of type ${webidl.util.Type(V)} is not an Object.` - }) - } - - // 2. Let method be ? GetMethod(V, @@iterator). - /** @type {Generator} */ - const method = V?.[Symbol.iterator]?.() - const seq = [] - - // 3. If method is undefined, throw a TypeError. - if ( - method === undefined || - typeof method.next !== 'function' - ) { - throw webidl.errors.exception({ - header: 'Sequence', - message: 'Object is not an iterator.' - }) - } - - // https://webidl.spec.whatwg.org/#create-sequence-from-iterable - while (true) { - const { done, value } = method.next() - - if (done) { - break - } - - seq.push(converter(value)) - } - - return seq - } -} - -// https://webidl.spec.whatwg.org/#es-to-record -webidl.recordConverter = function (keyConverter, valueConverter) { - return (O) => { - // 1. If Type(O) is not Object, throw a TypeError. - if (webidl.util.Type(O) !== 'Object') { - throw webidl.errors.exception({ - header: 'Record', - message: `Value of type ${webidl.util.Type(O)} is not an Object.` - }) - } - - // 2. Let result be a new empty instance of record<K, V>. - const result = {} - - if (!types.isProxy(O)) { - // Object.keys only returns enumerable properties - const keys = Object.keys(O) - - for (const key of keys) { - // 1. Let typedKey be key converted to an IDL value of type K. - const typedKey = keyConverter(key) - - // 2. Let value be ? Get(O, key). - // 3. Let typedValue be value converted to an IDL value of type V. - const typedValue = valueConverter(O[key]) - - // 4. Set result[typedKey] to typedValue. - result[typedKey] = typedValue - } - - // 5. Return result. - return result - } - - // 3. Let keys be ? O.[[OwnPropertyKeys]](). - const keys = Reflect.ownKeys(O) - - // 4. For each key of keys. - for (const key of keys) { - // 1. Let desc be ? O.[[GetOwnProperty]](key). - const desc = Reflect.getOwnPropertyDescriptor(O, key) - - // 2. If desc is not undefined and desc.[[Enumerable]] is true: - if (desc?.enumerable) { - // 1. Let typedKey be key converted to an IDL value of type K. - const typedKey = keyConverter(key) - - // 2. Let value be ? Get(O, key). - // 3. Let typedValue be value converted to an IDL value of type V. - const typedValue = valueConverter(O[key]) - - // 4. Set result[typedKey] to typedValue. - result[typedKey] = typedValue - } - } - - // 5. Return result. - return result - } -} - -webidl.interfaceConverter = function (i) { - return (V, opts = {}) => { - if (opts.strict !== false && !(V instanceof i)) { - throw webidl.errors.exception({ - header: i.name, - message: `Expected ${V} to be an instance of ${i.name}.` - }) - } - - return V - } -} - -webidl.dictionaryConverter = function (converters) { - return (dictionary) => { - const type = webidl.util.Type(dictionary) - const dict = {} - - if (type === 'Null' || type === 'Undefined') { - return dict - } else if (type !== 'Object') { - throw webidl.errors.exception({ - header: 'Dictionary', - message: `Expected ${dictionary} to be one of: Null, Undefined, Object.` - }) - } - - for (const options of converters) { - const { key, defaultValue, required, converter } = options - - if (required === true) { - if (!hasOwn(dictionary, key)) { - throw webidl.errors.exception({ - header: 'Dictionary', - message: `Missing required key "${key}".` - }) - } - } - - let value = dictionary[key] - const hasDefault = hasOwn(options, 'defaultValue') - - // Only use defaultValue if value is undefined and - // a defaultValue options was provided. - if (hasDefault && value !== null) { - value = value ?? defaultValue - } - - // A key can be optional and have no default value. - // When this happens, do not perform a conversion, - // and do not assign the key a value. - if (required || hasDefault || value !== undefined) { - value = converter(value) - - if ( - options.allowedValues && - !options.allowedValues.includes(value) - ) { - throw webidl.errors.exception({ - header: 'Dictionary', - message: `${value} is not an accepted type. Expected one of ${options.allowedValues.join(', ')}.` - }) - } - - dict[key] = value - } - } - - return dict - } -} - -webidl.nullableConverter = function (converter) { - return (V) => { - if (V === null) { - return V - } - - return converter(V) - } -} - -// https://webidl.spec.whatwg.org/#es-DOMString -webidl.converters.DOMString = function (V, opts = {}) { - // 1. If V is null and the conversion is to an IDL type - // associated with the [LegacyNullToEmptyString] - // extended attribute, then return the DOMString value - // that represents the empty string. - if (V === null && opts.legacyNullToEmptyString) { - return '' - } - - // 2. Let x be ? ToString(V). - if (typeof V === 'symbol') { - throw new TypeError('Could not convert argument of type symbol to string.') - } - - // 3. Return the IDL DOMString value that represents the - // same sequence of code units as the one the - // ECMAScript String value x represents. - return String(V) -} - -// https://webidl.spec.whatwg.org/#es-ByteString -webidl.converters.ByteString = function (V) { - // 1. Let x be ? ToString(V). - // Note: DOMString converter perform ? ToString(V) - const x = webidl.converters.DOMString(V) - - // 2. If the value of any element of x is greater than - // 255, then throw a TypeError. - for (let index = 0; index < x.length; index++) { - const charCode = x.charCodeAt(index) - - if (charCode > 255) { - throw new TypeError( - 'Cannot convert argument to a ByteString because the character at ' + - `index ${index} has a value of ${charCode} which is greater than 255.` - ) - } - } - - // 3. Return an IDL ByteString value whose length is the - // length of x, and where the value of each element is - // the value of the corresponding element of x. - return x -} - -// https://webidl.spec.whatwg.org/#es-USVString -webidl.converters.USVString = toUSVString - -// https://webidl.spec.whatwg.org/#es-boolean -webidl.converters.boolean = function (V) { - // 1. Let x be the result of computing ToBoolean(V). - const x = Boolean(V) - - // 2. Return the IDL boolean value that is the one that represents - // the same truth value as the ECMAScript Boolean value x. - return x -} - -// https://webidl.spec.whatwg.org/#es-any -webidl.converters.any = function (V) { - return V -} - -// https://webidl.spec.whatwg.org/#es-long-long -webidl.converters['long long'] = function (V) { - // 1. Let x be ? ConvertToInt(V, 64, "signed"). - const x = webidl.util.ConvertToInt(V, 64, 'signed') - - // 2. Return the IDL long long value that represents - // the same numeric value as x. - return x -} - -// https://webidl.spec.whatwg.org/#es-unsigned-long-long -webidl.converters['unsigned long long'] = function (V) { - // 1. Let x be ? ConvertToInt(V, 64, "unsigned"). - const x = webidl.util.ConvertToInt(V, 64, 'unsigned') - - // 2. Return the IDL unsigned long long value that - // represents the same numeric value as x. - return x -} - -// https://webidl.spec.whatwg.org/#es-unsigned-long -webidl.converters['unsigned long'] = function (V) { - // 1. Let x be ? ConvertToInt(V, 32, "unsigned"). - const x = webidl.util.ConvertToInt(V, 32, 'unsigned') - - // 2. Return the IDL unsigned long value that - // represents the same numeric value as x. - return x -} - -// https://webidl.spec.whatwg.org/#es-unsigned-short -webidl.converters['unsigned short'] = function (V, opts) { - // 1. Let x be ? ConvertToInt(V, 16, "unsigned"). - const x = webidl.util.ConvertToInt(V, 16, 'unsigned', opts) - - // 2. Return the IDL unsigned short value that represents - // the same numeric value as x. - return x -} - -// https://webidl.spec.whatwg.org/#idl-ArrayBuffer -webidl.converters.ArrayBuffer = function (V, opts = {}) { - // 1. If Type(V) is not Object, or V does not have an - // [[ArrayBufferData]] internal slot, then throw a - // TypeError. - // see: https://tc39.es/ecma262/#sec-properties-of-the-arraybuffer-instances - // see: https://tc39.es/ecma262/#sec-properties-of-the-sharedarraybuffer-instances - if ( - webidl.util.Type(V) !== 'Object' || - !types.isAnyArrayBuffer(V) - ) { - throw webidl.errors.conversionFailed({ - prefix: `${V}`, - argument: `${V}`, - types: ['ArrayBuffer'] - }) - } - - // 2. If the conversion is not to an IDL type associated - // with the [AllowShared] extended attribute, and - // IsSharedArrayBuffer(V) is true, then throw a - // TypeError. - if (opts.allowShared === false && types.isSharedArrayBuffer(V)) { - throw webidl.errors.exception({ - header: 'ArrayBuffer', - message: 'SharedArrayBuffer is not allowed.' - }) - } - - // 3. If the conversion is not to an IDL type associated - // with the [AllowResizable] extended attribute, and - // IsResizableArrayBuffer(V) is true, then throw a - // TypeError. - // Note: resizable ArrayBuffers are currently a proposal. - - // 4. Return the IDL ArrayBuffer value that is a - // reference to the same object as V. - return V -} - -webidl.converters.TypedArray = function (V, T, opts = {}) { - // 1. Let T be the IDL type V is being converted to. - - // 2. If Type(V) is not Object, or V does not have a - // [[TypedArrayName]] internal slot with a value - // equal to T’s name, then throw a TypeError. - if ( - webidl.util.Type(V) !== 'Object' || - !types.isTypedArray(V) || - V.constructor.name !== T.name - ) { - throw webidl.errors.conversionFailed({ - prefix: `${T.name}`, - argument: `${V}`, - types: [T.name] - }) - } - - // 3. If the conversion is not to an IDL type associated - // with the [AllowShared] extended attribute, and - // IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is - // true, then throw a TypeError. - if (opts.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { - throw webidl.errors.exception({ - header: 'ArrayBuffer', - message: 'SharedArrayBuffer is not allowed.' - }) - } - - // 4. If the conversion is not to an IDL type associated - // with the [AllowResizable] extended attribute, and - // IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) is - // true, then throw a TypeError. - // Note: resizable array buffers are currently a proposal - - // 5. Return the IDL value of type T that is a reference - // to the same object as V. - return V -} - -webidl.converters.DataView = function (V, opts = {}) { - // 1. If Type(V) is not Object, or V does not have a - // [[DataView]] internal slot, then throw a TypeError. - if (webidl.util.Type(V) !== 'Object' || !types.isDataView(V)) { - throw webidl.errors.exception({ - header: 'DataView', - message: 'Object is not a DataView.' - }) - } - - // 2. If the conversion is not to an IDL type associated - // with the [AllowShared] extended attribute, and - // IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is true, - // then throw a TypeError. - if (opts.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { - throw webidl.errors.exception({ - header: 'ArrayBuffer', - message: 'SharedArrayBuffer is not allowed.' - }) - } - - // 3. If the conversion is not to an IDL type associated - // with the [AllowResizable] extended attribute, and - // IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) is - // true, then throw a TypeError. - // Note: resizable ArrayBuffers are currently a proposal - - // 4. Return the IDL DataView value that is a reference - // to the same object as V. - return V -} - -// https://webidl.spec.whatwg.org/#BufferSource -webidl.converters.BufferSource = function (V, opts = {}) { - if (types.isAnyArrayBuffer(V)) { - return webidl.converters.ArrayBuffer(V, opts) - } - - if (types.isTypedArray(V)) { - return webidl.converters.TypedArray(V, V.constructor) - } - - if (types.isDataView(V)) { - return webidl.converters.DataView(V, opts) - } - - throw new TypeError(`Could not convert ${V} to a BufferSource.`) -} - -webidl.converters['sequence<ByteString>'] = webidl.sequenceConverter( - webidl.converters.ByteString -) - -webidl.converters['sequence<sequence<ByteString>>'] = webidl.sequenceConverter( - webidl.converters['sequence<ByteString>'] -) - -webidl.converters['record<ByteString, ByteString>'] = webidl.recordConverter( - webidl.converters.ByteString, - webidl.converters.ByteString -) - -module.exports = { - webidl -} - - -/***/ }), - -/***/ 7645: -/***/ ((module) => { - -"use strict"; - - -/** - * @see https://encoding.spec.whatwg.org/#concept-encoding-get - * @param {string|undefined} label - */ -function getEncoding (label) { - if (!label) { - return 'failure' - } - - // 1. Remove any leading and trailing ASCII whitespace from label. - // 2. If label is an ASCII case-insensitive match for any of the - // labels listed in the table below, then return the - // corresponding encoding; otherwise return failure. - switch (label.trim().toLowerCase()) { - case 'unicode-1-1-utf-8': - case 'unicode11utf8': - case 'unicode20utf8': - case 'utf-8': - case 'utf8': - case 'x-unicode20utf8': - return 'UTF-8' - case '866': - case 'cp866': - case 'csibm866': - case 'ibm866': - return 'IBM866' - case 'csisolatin2': - case 'iso-8859-2': - case 'iso-ir-101': - case 'iso8859-2': - case 'iso88592': - case 'iso_8859-2': - case 'iso_8859-2:1987': - case 'l2': - case 'latin2': - return 'ISO-8859-2' - case 'csisolatin3': - case 'iso-8859-3': - case 'iso-ir-109': - case 'iso8859-3': - case 'iso88593': - case 'iso_8859-3': - case 'iso_8859-3:1988': - case 'l3': - case 'latin3': - return 'ISO-8859-3' - case 'csisolatin4': - case 'iso-8859-4': - case 'iso-ir-110': - case 'iso8859-4': - case 'iso88594': - case 'iso_8859-4': - case 'iso_8859-4:1988': - case 'l4': - case 'latin4': - return 'ISO-8859-4' - case 'csisolatincyrillic': - case 'cyrillic': - case 'iso-8859-5': - case 'iso-ir-144': - case 'iso8859-5': - case 'iso88595': - case 'iso_8859-5': - case 'iso_8859-5:1988': - return 'ISO-8859-5' - case 'arabic': - case 'asmo-708': - case 'csiso88596e': - case 'csiso88596i': - case 'csisolatinarabic': - case 'ecma-114': - case 'iso-8859-6': - case 'iso-8859-6-e': - case 'iso-8859-6-i': - case 'iso-ir-127': - case 'iso8859-6': - case 'iso88596': - case 'iso_8859-6': - case 'iso_8859-6:1987': - return 'ISO-8859-6' - case 'csisolatingreek': - case 'ecma-118': - case 'elot_928': - case 'greek': - case 'greek8': - case 'iso-8859-7': - case 'iso-ir-126': - case 'iso8859-7': - case 'iso88597': - case 'iso_8859-7': - case 'iso_8859-7:1987': - case 'sun_eu_greek': - return 'ISO-8859-7' - case 'csiso88598e': - case 'csisolatinhebrew': - case 'hebrew': - case 'iso-8859-8': - case 'iso-8859-8-e': - case 'iso-ir-138': - case 'iso8859-8': - case 'iso88598': - case 'iso_8859-8': - case 'iso_8859-8:1988': - case 'visual': - return 'ISO-8859-8' - case 'csiso88598i': - case 'iso-8859-8-i': - case 'logical': - return 'ISO-8859-8-I' - case 'csisolatin6': - case 'iso-8859-10': - case 'iso-ir-157': - case 'iso8859-10': - case 'iso885910': - case 'l6': - case 'latin6': - return 'ISO-8859-10' - case 'iso-8859-13': - case 'iso8859-13': - case 'iso885913': - return 'ISO-8859-13' - case 'iso-8859-14': - case 'iso8859-14': - case 'iso885914': - return 'ISO-8859-14' - case 'csisolatin9': - case 'iso-8859-15': - case 'iso8859-15': - case 'iso885915': - case 'iso_8859-15': - case 'l9': - return 'ISO-8859-15' - case 'iso-8859-16': - return 'ISO-8859-16' - case 'cskoi8r': - case 'koi': - case 'koi8': - case 'koi8-r': - case 'koi8_r': - return 'KOI8-R' - case 'koi8-ru': - case 'koi8-u': - return 'KOI8-U' - case 'csmacintosh': - case 'mac': - case 'macintosh': - case 'x-mac-roman': - return 'macintosh' - case 'iso-8859-11': - case 'iso8859-11': - case 'iso885911': - case 'tis-620': - case 'windows-874': - return 'windows-874' - case 'cp1250': - case 'windows-1250': - case 'x-cp1250': - return 'windows-1250' - case 'cp1251': - case 'windows-1251': - case 'x-cp1251': - return 'windows-1251' - case 'ansi_x3.4-1968': - case 'ascii': - case 'cp1252': - case 'cp819': - case 'csisolatin1': - case 'ibm819': - case 'iso-8859-1': - case 'iso-ir-100': - case 'iso8859-1': - case 'iso88591': - case 'iso_8859-1': - case 'iso_8859-1:1987': - case 'l1': - case 'latin1': - case 'us-ascii': - case 'windows-1252': - case 'x-cp1252': - return 'windows-1252' - case 'cp1253': - case 'windows-1253': - case 'x-cp1253': - return 'windows-1253' - case 'cp1254': - case 'csisolatin5': - case 'iso-8859-9': - case 'iso-ir-148': - case 'iso8859-9': - case 'iso88599': - case 'iso_8859-9': - case 'iso_8859-9:1989': - case 'l5': - case 'latin5': - case 'windows-1254': - case 'x-cp1254': - return 'windows-1254' - case 'cp1255': - case 'windows-1255': - case 'x-cp1255': - return 'windows-1255' - case 'cp1256': - case 'windows-1256': - case 'x-cp1256': - return 'windows-1256' - case 'cp1257': - case 'windows-1257': - case 'x-cp1257': - return 'windows-1257' - case 'cp1258': - case 'windows-1258': - case 'x-cp1258': - return 'windows-1258' - case 'x-mac-cyrillic': - case 'x-mac-ukrainian': - return 'x-mac-cyrillic' - case 'chinese': - case 'csgb2312': - case 'csiso58gb231280': - case 'gb2312': - case 'gb_2312': - case 'gb_2312-80': - case 'gbk': - case 'iso-ir-58': - case 'x-gbk': - return 'GBK' - case 'gb18030': - return 'gb18030' - case 'big5': - case 'big5-hkscs': - case 'cn-big5': - case 'csbig5': - case 'x-x-big5': - return 'Big5' - case 'cseucpkdfmtjapanese': - case 'euc-jp': - case 'x-euc-jp': - return 'EUC-JP' - case 'csiso2022jp': - case 'iso-2022-jp': - return 'ISO-2022-JP' - case 'csshiftjis': - case 'ms932': - case 'ms_kanji': - case 'shift-jis': - case 'shift_jis': - case 'sjis': - case 'windows-31j': - case 'x-sjis': - return 'Shift_JIS' - case 'cseuckr': - case 'csksc56011987': - case 'euc-kr': - case 'iso-ir-149': - case 'korean': - case 'ks_c_5601-1987': - case 'ks_c_5601-1989': - case 'ksc5601': - case 'ksc_5601': - case 'windows-949': - return 'EUC-KR' - case 'csiso2022kr': - case 'hz-gb-2312': - case 'iso-2022-cn': - case 'iso-2022-cn-ext': - case 'iso-2022-kr': - case 'replacement': - return 'replacement' - case 'unicodefffe': - case 'utf-16be': - return 'UTF-16BE' - case 'csunicode': - case 'iso-10646-ucs-2': - case 'ucs-2': - case 'unicode': - case 'unicodefeff': - case 'utf-16': - case 'utf-16le': - return 'UTF-16LE' - case 'x-user-defined': - return 'x-user-defined' - default: return 'failure' - } -} - -module.exports = { - getEncoding -} - - -/***/ }), - -/***/ 7784: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { - staticPropertyDescriptors, - readOperation, - fireAProgressEvent -} = __nccwpck_require__(3934) -const { - kState, - kError, - kResult, - kEvents, - kAborted -} = __nccwpck_require__(8587) -const { webidl } = __nccwpck_require__(5337) -const { kEnumerableProperty } = __nccwpck_require__(6223) - -class FileReader extends EventTarget { - constructor () { - super() - - this[kState] = 'empty' - this[kResult] = null - this[kError] = null - this[kEvents] = { - loadend: null, - error: null, - abort: null, - load: null, - progress: null, - loadstart: null - } - } - - /** - * @see https://w3c.github.io/FileAPI/#dfn-readAsArrayBuffer - * @param {import('buffer').Blob} blob - */ - readAsArrayBuffer (blob) { - webidl.brandCheck(this, FileReader) - - webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsArrayBuffer' }) - - blob = webidl.converters.Blob(blob, { strict: false }) - - // The readAsArrayBuffer(blob) method, when invoked, - // must initiate a read operation for blob with ArrayBuffer. - readOperation(this, blob, 'ArrayBuffer') - } - - /** - * @see https://w3c.github.io/FileAPI/#readAsBinaryString - * @param {import('buffer').Blob} blob - */ - readAsBinaryString (blob) { - webidl.brandCheck(this, FileReader) - - webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsBinaryString' }) - - blob = webidl.converters.Blob(blob, { strict: false }) - - // The readAsBinaryString(blob) method, when invoked, - // must initiate a read operation for blob with BinaryString. - readOperation(this, blob, 'BinaryString') - } - - /** - * @see https://w3c.github.io/FileAPI/#readAsDataText - * @param {import('buffer').Blob} blob - * @param {string?} encoding - */ - readAsText (blob, encoding = undefined) { - webidl.brandCheck(this, FileReader) - - webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsText' }) - - blob = webidl.converters.Blob(blob, { strict: false }) - - if (encoding !== undefined) { - encoding = webidl.converters.DOMString(encoding) - } - - // The readAsText(blob, encoding) method, when invoked, - // must initiate a read operation for blob with Text and encoding. - readOperation(this, blob, 'Text', encoding) - } - - /** - * @see https://w3c.github.io/FileAPI/#dfn-readAsDataURL - * @param {import('buffer').Blob} blob - */ - readAsDataURL (blob) { - webidl.brandCheck(this, FileReader) - - webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsDataURL' }) - - blob = webidl.converters.Blob(blob, { strict: false }) - - // The readAsDataURL(blob) method, when invoked, must - // initiate a read operation for blob with DataURL. - readOperation(this, blob, 'DataURL') - } - - /** - * @see https://w3c.github.io/FileAPI/#dfn-abort - */ - abort () { - // 1. If this's state is "empty" or if this's state is - // "done" set this's result to null and terminate - // this algorithm. - if (this[kState] === 'empty' || this[kState] === 'done') { - this[kResult] = null - return - } - - // 2. If this's state is "loading" set this's state to - // "done" and set this's result to null. - if (this[kState] === 'loading') { - this[kState] = 'done' - this[kResult] = null - } - - // 3. If there are any tasks from this on the file reading - // task source in an affiliated task queue, then remove - // those tasks from that task queue. - this[kAborted] = true - - // 4. Terminate the algorithm for the read method being processed. - // TODO - - // 5. Fire a progress event called abort at this. - fireAProgressEvent('abort', this) - - // 6. If this's state is not "loading", fire a progress - // event called loadend at this. - if (this[kState] !== 'loading') { - fireAProgressEvent('loadend', this) - } - } - - /** - * @see https://w3c.github.io/FileAPI/#dom-filereader-readystate - */ - get readyState () { - webidl.brandCheck(this, FileReader) - - switch (this[kState]) { - case 'empty': return this.EMPTY - case 'loading': return this.LOADING - case 'done': return this.DONE - } - } - - /** - * @see https://w3c.github.io/FileAPI/#dom-filereader-result - */ - get result () { - webidl.brandCheck(this, FileReader) - - // The result attribute’s getter, when invoked, must return - // this's result. - return this[kResult] - } - - /** - * @see https://w3c.github.io/FileAPI/#dom-filereader-error - */ - get error () { - webidl.brandCheck(this, FileReader) - - // The error attribute’s getter, when invoked, must return - // this's error. - return this[kError] - } - - get onloadend () { - webidl.brandCheck(this, FileReader) - - return this[kEvents].loadend - } - - set onloadend (fn) { - webidl.brandCheck(this, FileReader) - - if (this[kEvents].loadend) { - this.removeEventListener('loadend', this[kEvents].loadend) - } - - if (typeof fn === 'function') { - this[kEvents].loadend = fn - this.addEventListener('loadend', fn) - } else { - this[kEvents].loadend = null - } - } - - get onerror () { - webidl.brandCheck(this, FileReader) - - return this[kEvents].error - } - - set onerror (fn) { - webidl.brandCheck(this, FileReader) - - if (this[kEvents].error) { - this.removeEventListener('error', this[kEvents].error) - } - - if (typeof fn === 'function') { - this[kEvents].error = fn - this.addEventListener('error', fn) - } else { - this[kEvents].error = null - } - } - - get onloadstart () { - webidl.brandCheck(this, FileReader) - - return this[kEvents].loadstart - } - - set onloadstart (fn) { - webidl.brandCheck(this, FileReader) - - if (this[kEvents].loadstart) { - this.removeEventListener('loadstart', this[kEvents].loadstart) - } - - if (typeof fn === 'function') { - this[kEvents].loadstart = fn - this.addEventListener('loadstart', fn) - } else { - this[kEvents].loadstart = null - } - } - - get onprogress () { - webidl.brandCheck(this, FileReader) - - return this[kEvents].progress - } - - set onprogress (fn) { - webidl.brandCheck(this, FileReader) - - if (this[kEvents].progress) { - this.removeEventListener('progress', this[kEvents].progress) - } - - if (typeof fn === 'function') { - this[kEvents].progress = fn - this.addEventListener('progress', fn) - } else { - this[kEvents].progress = null - } - } - - get onload () { - webidl.brandCheck(this, FileReader) - - return this[kEvents].load - } - - set onload (fn) { - webidl.brandCheck(this, FileReader) - - if (this[kEvents].load) { - this.removeEventListener('load', this[kEvents].load) - } - - if (typeof fn === 'function') { - this[kEvents].load = fn - this.addEventListener('load', fn) - } else { - this[kEvents].load = null - } - } - - get onabort () { - webidl.brandCheck(this, FileReader) - - return this[kEvents].abort - } - - set onabort (fn) { - webidl.brandCheck(this, FileReader) - - if (this[kEvents].abort) { - this.removeEventListener('abort', this[kEvents].abort) - } - - if (typeof fn === 'function') { - this[kEvents].abort = fn - this.addEventListener('abort', fn) - } else { - this[kEvents].abort = null - } - } -} - -// https://w3c.github.io/FileAPI/#dom-filereader-empty -FileReader.EMPTY = FileReader.prototype.EMPTY = 0 -// https://w3c.github.io/FileAPI/#dom-filereader-loading -FileReader.LOADING = FileReader.prototype.LOADING = 1 -// https://w3c.github.io/FileAPI/#dom-filereader-done -FileReader.DONE = FileReader.prototype.DONE = 2 - -Object.defineProperties(FileReader.prototype, { - EMPTY: staticPropertyDescriptors, - LOADING: staticPropertyDescriptors, - DONE: staticPropertyDescriptors, - readAsArrayBuffer: kEnumerableProperty, - readAsBinaryString: kEnumerableProperty, - readAsText: kEnumerableProperty, - readAsDataURL: kEnumerableProperty, - abort: kEnumerableProperty, - readyState: kEnumerableProperty, - result: kEnumerableProperty, - error: kEnumerableProperty, - onloadstart: kEnumerableProperty, - onprogress: kEnumerableProperty, - onload: kEnumerableProperty, - onabort: kEnumerableProperty, - onerror: kEnumerableProperty, - onloadend: kEnumerableProperty, - [Symbol.toStringTag]: { - value: 'FileReader', - writable: false, - enumerable: false, - configurable: true - } -}) - -Object.defineProperties(FileReader, { - EMPTY: staticPropertyDescriptors, - LOADING: staticPropertyDescriptors, - DONE: staticPropertyDescriptors -}) - -module.exports = { - FileReader -} - - -/***/ }), - -/***/ 1764: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { webidl } = __nccwpck_require__(5337) - -const kState = Symbol('ProgressEvent state') - -/** - * @see https://xhr.spec.whatwg.org/#progressevent - */ -class ProgressEvent extends Event { - constructor (type, eventInitDict = {}) { - type = webidl.converters.DOMString(type) - eventInitDict = webidl.converters.ProgressEventInit(eventInitDict ?? {}) - - super(type, eventInitDict) - - this[kState] = { - lengthComputable: eventInitDict.lengthComputable, - loaded: eventInitDict.loaded, - total: eventInitDict.total - } - } - - get lengthComputable () { - webidl.brandCheck(this, ProgressEvent) - - return this[kState].lengthComputable - } - - get loaded () { - webidl.brandCheck(this, ProgressEvent) - - return this[kState].loaded - } - - get total () { - webidl.brandCheck(this, ProgressEvent) - - return this[kState].total - } -} - -webidl.converters.ProgressEventInit = webidl.dictionaryConverter([ - { - key: 'lengthComputable', - converter: webidl.converters.boolean, - defaultValue: false - }, - { - key: 'loaded', - converter: webidl.converters['unsigned long long'], - defaultValue: 0 - }, - { - key: 'total', - converter: webidl.converters['unsigned long long'], - defaultValue: 0 - }, - { - key: 'bubbles', - converter: webidl.converters.boolean, - defaultValue: false - }, - { - key: 'cancelable', - converter: webidl.converters.boolean, - defaultValue: false - }, - { - key: 'composed', - converter: webidl.converters.boolean, - defaultValue: false - } -]) - -module.exports = { - ProgressEvent -} - - -/***/ }), - -/***/ 8587: -/***/ ((module) => { - -"use strict"; - - -module.exports = { - kState: Symbol('FileReader state'), - kResult: Symbol('FileReader result'), - kError: Symbol('FileReader error'), - kLastProgressEventFired: Symbol('FileReader last progress event fired timestamp'), - kEvents: Symbol('FileReader events'), - kAborted: Symbol('FileReader aborted') -} - - -/***/ }), - -/***/ 3934: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { - kState, - kError, - kResult, - kAborted, - kLastProgressEventFired -} = __nccwpck_require__(8587) -const { ProgressEvent } = __nccwpck_require__(1764) -const { getEncoding } = __nccwpck_require__(7645) -const { DOMException } = __nccwpck_require__(7213) -const { serializeAMimeType, parseMIMEType } = __nccwpck_require__(6822) -const { types } = __nccwpck_require__(3837) -const { StringDecoder } = __nccwpck_require__(1576) -const { btoa } = __nccwpck_require__(4300) - -/** @type {PropertyDescriptor} */ -const staticPropertyDescriptors = { - enumerable: true, - writable: false, - configurable: false -} - -/** - * @see https://w3c.github.io/FileAPI/#readOperation - * @param {import('./filereader').FileReader} fr - * @param {import('buffer').Blob} blob - * @param {string} type - * @param {string?} encodingName - */ -function readOperation (fr, blob, type, encodingName) { - // 1. If fr’s state is "loading", throw an InvalidStateError - // DOMException. - if (fr[kState] === 'loading') { - throw new DOMException('Invalid state', 'InvalidStateError') - } - - // 2. Set fr’s state to "loading". - fr[kState] = 'loading' - - // 3. Set fr’s result to null. - fr[kResult] = null - - // 4. Set fr’s error to null. - fr[kError] = null - - // 5. Let stream be the result of calling get stream on blob. - /** @type {import('stream/web').ReadableStream} */ - const stream = blob.stream() - - // 6. Let reader be the result of getting a reader from stream. - const reader = stream.getReader() - - // 7. Let bytes be an empty byte sequence. - /** @type {Uint8Array[]} */ - const bytes = [] - - // 8. Let chunkPromise be the result of reading a chunk from - // stream with reader. - let chunkPromise = reader.read() - - // 9. Let isFirstChunk be true. - let isFirstChunk = true - - // 10. In parallel, while true: - // Note: "In parallel" just means non-blocking - // Note 2: readOperation itself cannot be async as double - // reading the body would then reject the promise, instead - // of throwing an error. - ;(async () => { - while (!fr[kAborted]) { - // 1. Wait for chunkPromise to be fulfilled or rejected. - try { - const { done, value } = await chunkPromise - - // 2. If chunkPromise is fulfilled, and isFirstChunk is - // true, queue a task to fire a progress event called - // loadstart at fr. - if (isFirstChunk && !fr[kAborted]) { - queueMicrotask(() => { - fireAProgressEvent('loadstart', fr) - }) - } - - // 3. Set isFirstChunk to false. - isFirstChunk = false - - // 4. If chunkPromise is fulfilled with an object whose - // done property is false and whose value property is - // a Uint8Array object, run these steps: - if (!done && types.isUint8Array(value)) { - // 1. Let bs be the byte sequence represented by the - // Uint8Array object. - - // 2. Append bs to bytes. - bytes.push(value) - - // 3. If roughly 50ms have passed since these steps - // were last invoked, queue a task to fire a - // progress event called progress at fr. - if ( - ( - fr[kLastProgressEventFired] === undefined || - Date.now() - fr[kLastProgressEventFired] >= 50 - ) && - !fr[kAborted] - ) { - fr[kLastProgressEventFired] = Date.now() - queueMicrotask(() => { - fireAProgressEvent('progress', fr) - }) - } - - // 4. Set chunkPromise to the result of reading a - // chunk from stream with reader. - chunkPromise = reader.read() - } else if (done) { - // 5. Otherwise, if chunkPromise is fulfilled with an - // object whose done property is true, queue a task - // to run the following steps and abort this algorithm: - queueMicrotask(() => { - // 1. Set fr’s state to "done". - fr[kState] = 'done' - - // 2. Let result be the result of package data given - // bytes, type, blob’s type, and encodingName. - try { - const result = packageData(bytes, type, blob.type, encodingName) - - // 4. Else: - - if (fr[kAborted]) { - return - } - - // 1. Set fr’s result to result. - fr[kResult] = result - - // 2. Fire a progress event called load at the fr. - fireAProgressEvent('load', fr) - } catch (error) { - // 3. If package data threw an exception error: - - // 1. Set fr’s error to error. - fr[kError] = error - - // 2. Fire a progress event called error at fr. - fireAProgressEvent('error', fr) - } - - // 5. If fr’s state is not "loading", fire a progress - // event called loadend at the fr. - if (fr[kState] !== 'loading') { - fireAProgressEvent('loadend', fr) - } - }) - - break - } - } catch (error) { - if (fr[kAborted]) { - return - } - - // 6. Otherwise, if chunkPromise is rejected with an - // error error, queue a task to run the following - // steps and abort this algorithm: - queueMicrotask(() => { - // 1. Set fr’s state to "done". - fr[kState] = 'done' - - // 2. Set fr’s error to error. - fr[kError] = error - - // 3. Fire a progress event called error at fr. - fireAProgressEvent('error', fr) - - // 4. If fr’s state is not "loading", fire a progress - // event called loadend at fr. - if (fr[kState] !== 'loading') { - fireAProgressEvent('loadend', fr) - } - }) - - break - } - } - })() -} - -/** - * @see https://w3c.github.io/FileAPI/#fire-a-progress-event - * @see https://dom.spec.whatwg.org/#concept-event-fire - * @param {string} e The name of the event - * @param {import('./filereader').FileReader} reader - */ -function fireAProgressEvent (e, reader) { - // The progress event e does not bubble. e.bubbles must be false - // The progress event e is NOT cancelable. e.cancelable must be false - const event = new ProgressEvent(e, { - bubbles: false, - cancelable: false - }) - - reader.dispatchEvent(event) -} - -/** - * @see https://w3c.github.io/FileAPI/#blob-package-data - * @param {Uint8Array[]} bytes - * @param {string} type - * @param {string?} mimeType - * @param {string?} encodingName - */ -function packageData (bytes, type, mimeType, encodingName) { - // 1. A Blob has an associated package data algorithm, given - // bytes, a type, a optional mimeType, and a optional - // encodingName, which switches on type and runs the - // associated steps: - - switch (type) { - case 'DataURL': { - // 1. Return bytes as a DataURL [RFC2397] subject to - // the considerations below: - // * Use mimeType as part of the Data URL if it is - // available in keeping with the Data URL - // specification [RFC2397]. - // * If mimeType is not available return a Data URL - // without a media-type. [RFC2397]. - - // https://datatracker.ietf.org/doc/html/rfc2397#section-3 - // dataurl := "data:" [ mediatype ] [ ";base64" ] "," data - // mediatype := [ type "/" subtype ] *( ";" parameter ) - // data := *urlchar - // parameter := attribute "=" value - let dataURL = 'data:' - - const parsed = parseMIMEType(mimeType || 'application/octet-stream') - - if (parsed !== 'failure') { - dataURL += serializeAMimeType(parsed) - } - - dataURL += ';base64,' - - const decoder = new StringDecoder('latin1') - - for (const chunk of bytes) { - dataURL += btoa(decoder.write(chunk)) - } - - dataURL += btoa(decoder.end()) - - return dataURL - } - case 'Text': { - // 1. Let encoding be failure - let encoding = 'failure' - - // 2. If the encodingName is present, set encoding to the - // result of getting an encoding from encodingName. - if (encodingName) { - encoding = getEncoding(encodingName) - } - - // 3. If encoding is failure, and mimeType is present: - if (encoding === 'failure' && mimeType) { - // 1. Let type be the result of parse a MIME type - // given mimeType. - const type = parseMIMEType(mimeType) - - // 2. If type is not failure, set encoding to the result - // of getting an encoding from type’s parameters["charset"]. - if (type !== 'failure') { - encoding = getEncoding(type.parameters.get('charset')) - } - } - - // 4. If encoding is failure, then set encoding to UTF-8. - if (encoding === 'failure') { - encoding = 'UTF-8' - } - - // 5. Decode bytes using fallback encoding encoding, and - // return the result. - return decode(bytes, encoding) - } - case 'ArrayBuffer': { - // Return a new ArrayBuffer whose contents are bytes. - const sequence = combineByteSequences(bytes) - - return sequence.buffer - } - case 'BinaryString': { - // Return bytes as a binary string, in which every byte - // is represented by a code unit of equal value [0..255]. - let binaryString = '' - - const decoder = new StringDecoder('latin1') - - for (const chunk of bytes) { - binaryString += decoder.write(chunk) - } - - binaryString += decoder.end() - - return binaryString - } - } -} - -/** - * @see https://encoding.spec.whatwg.org/#decode - * @param {Uint8Array[]} ioQueue - * @param {string} encoding - */ -function decode (ioQueue, encoding) { - const bytes = combineByteSequences(ioQueue) - - // 1. Let BOMEncoding be the result of BOM sniffing ioQueue. - const BOMEncoding = BOMSniffing(bytes) - - let slice = 0 - - // 2. If BOMEncoding is non-null: - if (BOMEncoding !== null) { - // 1. Set encoding to BOMEncoding. - encoding = BOMEncoding - - // 2. Read three bytes from ioQueue, if BOMEncoding is - // UTF-8; otherwise read two bytes. - // (Do nothing with those bytes.) - slice = BOMEncoding === 'UTF-8' ? 3 : 2 - } - - // 3. Process a queue with an instance of encoding’s - // decoder, ioQueue, output, and "replacement". - - // 4. Return output. - - const sliced = bytes.slice(slice) - return new TextDecoder(encoding).decode(sliced) -} - -/** - * @see https://encoding.spec.whatwg.org/#bom-sniff - * @param {Uint8Array} ioQueue - */ -function BOMSniffing (ioQueue) { - // 1. Let BOM be the result of peeking 3 bytes from ioQueue, - // converted to a byte sequence. - const [a, b, c] = ioQueue - - // 2. For each of the rows in the table below, starting with - // the first one and going down, if BOM starts with the - // bytes given in the first column, then return the - // encoding given in the cell in the second column of that - // row. Otherwise, return null. - if (a === 0xEF && b === 0xBB && c === 0xBF) { - return 'UTF-8' - } else if (a === 0xFE && b === 0xFF) { - return 'UTF-16BE' - } else if (a === 0xFF && b === 0xFE) { - return 'UTF-16LE' - } - - return null -} - -/** - * @param {Uint8Array[]} sequences - */ -function combineByteSequences (sequences) { - const size = sequences.reduce((a, b) => { - return a + b.byteLength - }, 0) - - let offset = 0 - - return sequences.reduce((a, b) => { - a.set(b, offset) - offset += b.byteLength - return a - }, new Uint8Array(size)) -} - -module.exports = { - staticPropertyDescriptors, - readOperation, - fireAProgressEvent -} - - -/***/ }), - -/***/ 398: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -// We include a version number for the Dispatcher API. In case of breaking changes, -// this version number must be increased to avoid conflicts. -const globalDispatcher = Symbol.for('undici.globalDispatcher.1') -const { InvalidArgumentError } = __nccwpck_require__(5767) -const Agent = __nccwpck_require__(8162) - -if (getGlobalDispatcher() === undefined) { - setGlobalDispatcher(new Agent()) -} - -function setGlobalDispatcher (agent) { - if (!agent || typeof agent.dispatch !== 'function') { - throw new InvalidArgumentError('Argument agent must implement Agent') - } - Object.defineProperty(globalThis, globalDispatcher, { - value: agent, - writable: true, - enumerable: false, - configurable: false - }) -} - -function getGlobalDispatcher () { - return globalThis[globalDispatcher] -} - -module.exports = { - setGlobalDispatcher, - getGlobalDispatcher -} - - -/***/ }), - -/***/ 3978: -/***/ ((module) => { - -"use strict"; - - -module.exports = class DecoratorHandler { - constructor (handler) { - this.handler = handler - } - - onConnect (...args) { - return this.handler.onConnect(...args) - } - - onError (...args) { - return this.handler.onError(...args) - } - - onUpgrade (...args) { - return this.handler.onUpgrade(...args) - } - - onHeaders (...args) { - return this.handler.onHeaders(...args) - } - - onData (...args) { - return this.handler.onData(...args) - } - - onComplete (...args) { - return this.handler.onComplete(...args) - } - - onBodySent (...args) { - return this.handler.onBodySent(...args) - } -} - - -/***/ }), - -/***/ 1962: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const util = __nccwpck_require__(6223) -const { kBodyUsed } = __nccwpck_require__(1439) -const assert = __nccwpck_require__(9491) -const { InvalidArgumentError } = __nccwpck_require__(5767) -const EE = __nccwpck_require__(2361) - -const redirectableStatusCodes = [300, 301, 302, 303, 307, 308] - -const kBody = Symbol('body') - -class BodyAsyncIterable { - constructor (body) { - this[kBody] = body - this[kBodyUsed] = false - } - - async * [Symbol.asyncIterator] () { - assert(!this[kBodyUsed], 'disturbed') - this[kBodyUsed] = true - yield * this[kBody] - } -} - -class RedirectHandler { - constructor (dispatch, maxRedirections, opts, handler) { - if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) { - throw new InvalidArgumentError('maxRedirections must be a positive number') - } - - util.validateHandler(handler, opts.method, opts.upgrade) - - this.dispatch = dispatch - this.location = null - this.abort = null - this.opts = { ...opts, maxRedirections: 0 } // opts must be a copy - this.maxRedirections = maxRedirections - this.handler = handler - this.history = [] - - if (util.isStream(this.opts.body)) { - // TODO (fix): Provide some way for the user to cache the file to e.g. /tmp - // so that it can be dispatched again? - // TODO (fix): Do we need 100-expect support to provide a way to do this properly? - if (util.bodyLength(this.opts.body) === 0) { - this.opts.body - .on('data', function () { - assert(false) - }) - } - - if (typeof this.opts.body.readableDidRead !== 'boolean') { - this.opts.body[kBodyUsed] = false - EE.prototype.on.call(this.opts.body, 'data', function () { - this[kBodyUsed] = true - }) - } - } else if (this.opts.body && typeof this.opts.body.pipeTo === 'function') { - // TODO (fix): We can't access ReadableStream internal state - // to determine whether or not it has been disturbed. This is just - // a workaround. - this.opts.body = new BodyAsyncIterable(this.opts.body) - } else if ( - this.opts.body && - typeof this.opts.body !== 'string' && - !ArrayBuffer.isView(this.opts.body) && - util.isIterable(this.opts.body) - ) { - // TODO: Should we allow re-using iterable if !this.opts.idempotent - // or through some other flag? - this.opts.body = new BodyAsyncIterable(this.opts.body) - } - } - - onConnect (abort) { - this.abort = abort - this.handler.onConnect(abort, { history: this.history }) - } - - onUpgrade (statusCode, headers, socket) { - this.handler.onUpgrade(statusCode, headers, socket) - } - - onError (error) { - this.handler.onError(error) - } - - onHeaders (statusCode, headers, resume, statusText) { - this.location = this.history.length >= this.maxRedirections || util.isDisturbed(this.opts.body) - ? null - : parseLocation(statusCode, headers) - - if (this.opts.origin) { - this.history.push(new URL(this.opts.path, this.opts.origin)) - } - - if (!this.location) { - return this.handler.onHeaders(statusCode, headers, resume, statusText) - } - - const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin))) - const path = search ? `${pathname}${search}` : pathname - - // Remove headers referring to the original URL. - // By default it is Host only, unless it's a 303 (see below), which removes also all Content-* headers. - // https://tools.ietf.org/html/rfc7231#section-6.4 - this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin) - this.opts.path = path - this.opts.origin = origin - this.opts.maxRedirections = 0 - this.opts.query = null - - // https://tools.ietf.org/html/rfc7231#section-6.4.4 - // In case of HTTP 303, always replace method to be either HEAD or GET - if (statusCode === 303 && this.opts.method !== 'HEAD') { - this.opts.method = 'GET' - this.opts.body = null - } - } - - onData (chunk) { - if (this.location) { - /* - https://tools.ietf.org/html/rfc7231#section-6.4 - - TLDR: undici always ignores 3xx response bodies. - - Redirection is used to serve the requested resource from another URL, so it is assumes that - no body is generated (and thus can be ignored). Even though generating a body is not prohibited. - - For status 301, 302, 303, 307 and 308 (the latter from RFC 7238), the specs mention that the body usually - (which means it's optional and not mandated) contain just an hyperlink to the value of - the Location response header, so the body can be ignored safely. - - For status 300, which is "Multiple Choices", the spec mentions both generating a Location - response header AND a response body with the other possible location to follow. - Since the spec explicitily chooses not to specify a format for such body and leave it to - servers and browsers implementors, we ignore the body as there is no specified way to eventually parse it. - */ - } else { - return this.handler.onData(chunk) - } - } - - onComplete (trailers) { - if (this.location) { - /* - https://tools.ietf.org/html/rfc7231#section-6.4 - - TLDR: undici always ignores 3xx response trailers as they are not expected in case of redirections - and neither are useful if present. - - See comment on onData method above for more detailed informations. - */ - - this.location = null - this.abort = null - - this.dispatch(this.opts, this) - } else { - this.handler.onComplete(trailers) - } - } - - onBodySent (chunk) { - if (this.handler.onBodySent) { - this.handler.onBodySent(chunk) - } - } -} - -function parseLocation (statusCode, headers) { - if (redirectableStatusCodes.indexOf(statusCode) === -1) { - return null - } - - for (let i = 0; i < headers.length; i += 2) { - if (headers[i].toString().toLowerCase() === 'location') { - return headers[i + 1] - } - } -} - -// https://tools.ietf.org/html/rfc7231#section-6.4.4 -function shouldRemoveHeader (header, removeContent, unknownOrigin) { - return ( - (header.length === 4 && header.toString().toLowerCase() === 'host') || - (removeContent && header.toString().toLowerCase().indexOf('content-') === 0) || - (unknownOrigin && header.length === 13 && header.toString().toLowerCase() === 'authorization') || - (unknownOrigin && header.length === 6 && header.toString().toLowerCase() === 'cookie') - ) -} - -// https://tools.ietf.org/html/rfc7231#section-6.4 -function cleanRequestHeaders (headers, removeContent, unknownOrigin) { - const ret = [] - if (Array.isArray(headers)) { - for (let i = 0; i < headers.length; i += 2) { - if (!shouldRemoveHeader(headers[i], removeContent, unknownOrigin)) { - ret.push(headers[i], headers[i + 1]) - } - } - } else if (headers && typeof headers === 'object') { - for (const key of Object.keys(headers)) { - if (!shouldRemoveHeader(key, removeContent, unknownOrigin)) { - ret.push(key, headers[key]) - } - } - } else { - assert(headers == null, 'headers must be an object or an array') - } - return ret -} - -module.exports = RedirectHandler - - -/***/ }), - -/***/ 9095: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const RedirectHandler = __nccwpck_require__(1962) - -function createRedirectInterceptor ({ maxRedirections: defaultMaxRedirections }) { - return (dispatch) => { - return function Intercept (opts, handler) { - const { maxRedirections = defaultMaxRedirections } = opts - - if (!maxRedirections) { - return dispatch(opts, handler) - } - - const redirectHandler = new RedirectHandler(dispatch, maxRedirections, opts, handler) - opts = { ...opts, maxRedirections: 0 } // Stop sub dispatcher from also redirecting. - return dispatch(opts, redirectHandler) - } - } -} - -module.exports = createRedirectInterceptor - - -/***/ }), - -/***/ 6744: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.SPECIAL_HEADERS = exports.HEADER_STATE = exports.MINOR = exports.MAJOR = exports.CONNECTION_TOKEN_CHARS = exports.HEADER_CHARS = exports.TOKEN = exports.STRICT_TOKEN = exports.HEX = exports.URL_CHAR = exports.STRICT_URL_CHAR = exports.USERINFO_CHARS = exports.MARK = exports.ALPHANUM = exports.NUM = exports.HEX_MAP = exports.NUM_MAP = exports.ALPHA = exports.FINISH = exports.H_METHOD_MAP = exports.METHOD_MAP = exports.METHODS_RTSP = exports.METHODS_ICE = exports.METHODS_HTTP = exports.METHODS = exports.LENIENT_FLAGS = exports.FLAGS = exports.TYPE = exports.ERROR = void 0; -const utils_1 = __nccwpck_require__(7728); -// C headers -var ERROR; -(function (ERROR) { - ERROR[ERROR["OK"] = 0] = "OK"; - ERROR[ERROR["INTERNAL"] = 1] = "INTERNAL"; - ERROR[ERROR["STRICT"] = 2] = "STRICT"; - ERROR[ERROR["LF_EXPECTED"] = 3] = "LF_EXPECTED"; - ERROR[ERROR["UNEXPECTED_CONTENT_LENGTH"] = 4] = "UNEXPECTED_CONTENT_LENGTH"; - ERROR[ERROR["CLOSED_CONNECTION"] = 5] = "CLOSED_CONNECTION"; - ERROR[ERROR["INVALID_METHOD"] = 6] = "INVALID_METHOD"; - ERROR[ERROR["INVALID_URL"] = 7] = "INVALID_URL"; - ERROR[ERROR["INVALID_CONSTANT"] = 8] = "INVALID_CONSTANT"; - ERROR[ERROR["INVALID_VERSION"] = 9] = "INVALID_VERSION"; - ERROR[ERROR["INVALID_HEADER_TOKEN"] = 10] = "INVALID_HEADER_TOKEN"; - ERROR[ERROR["INVALID_CONTENT_LENGTH"] = 11] = "INVALID_CONTENT_LENGTH"; - ERROR[ERROR["INVALID_CHUNK_SIZE"] = 12] = "INVALID_CHUNK_SIZE"; - ERROR[ERROR["INVALID_STATUS"] = 13] = "INVALID_STATUS"; - ERROR[ERROR["INVALID_EOF_STATE"] = 14] = "INVALID_EOF_STATE"; - ERROR[ERROR["INVALID_TRANSFER_ENCODING"] = 15] = "INVALID_TRANSFER_ENCODING"; - ERROR[ERROR["CB_MESSAGE_BEGIN"] = 16] = "CB_MESSAGE_BEGIN"; - ERROR[ERROR["CB_HEADERS_COMPLETE"] = 17] = "CB_HEADERS_COMPLETE"; - ERROR[ERROR["CB_MESSAGE_COMPLETE"] = 18] = "CB_MESSAGE_COMPLETE"; - ERROR[ERROR["CB_CHUNK_HEADER"] = 19] = "CB_CHUNK_HEADER"; - ERROR[ERROR["CB_CHUNK_COMPLETE"] = 20] = "CB_CHUNK_COMPLETE"; - ERROR[ERROR["PAUSED"] = 21] = "PAUSED"; - ERROR[ERROR["PAUSED_UPGRADE"] = 22] = "PAUSED_UPGRADE"; - ERROR[ERROR["PAUSED_H2_UPGRADE"] = 23] = "PAUSED_H2_UPGRADE"; - ERROR[ERROR["USER"] = 24] = "USER"; -})(ERROR = exports.ERROR || (exports.ERROR = {})); -var TYPE; -(function (TYPE) { - TYPE[TYPE["BOTH"] = 0] = "BOTH"; - TYPE[TYPE["REQUEST"] = 1] = "REQUEST"; - TYPE[TYPE["RESPONSE"] = 2] = "RESPONSE"; -})(TYPE = exports.TYPE || (exports.TYPE = {})); -var FLAGS; -(function (FLAGS) { - FLAGS[FLAGS["CONNECTION_KEEP_ALIVE"] = 1] = "CONNECTION_KEEP_ALIVE"; - FLAGS[FLAGS["CONNECTION_CLOSE"] = 2] = "CONNECTION_CLOSE"; - FLAGS[FLAGS["CONNECTION_UPGRADE"] = 4] = "CONNECTION_UPGRADE"; - FLAGS[FLAGS["CHUNKED"] = 8] = "CHUNKED"; - FLAGS[FLAGS["UPGRADE"] = 16] = "UPGRADE"; - FLAGS[FLAGS["CONTENT_LENGTH"] = 32] = "CONTENT_LENGTH"; - FLAGS[FLAGS["SKIPBODY"] = 64] = "SKIPBODY"; - FLAGS[FLAGS["TRAILING"] = 128] = "TRAILING"; - // 1 << 8 is unused - FLAGS[FLAGS["TRANSFER_ENCODING"] = 512] = "TRANSFER_ENCODING"; -})(FLAGS = exports.FLAGS || (exports.FLAGS = {})); -var LENIENT_FLAGS; -(function (LENIENT_FLAGS) { - LENIENT_FLAGS[LENIENT_FLAGS["HEADERS"] = 1] = "HEADERS"; - LENIENT_FLAGS[LENIENT_FLAGS["CHUNKED_LENGTH"] = 2] = "CHUNKED_LENGTH"; - LENIENT_FLAGS[LENIENT_FLAGS["KEEP_ALIVE"] = 4] = "KEEP_ALIVE"; -})(LENIENT_FLAGS = exports.LENIENT_FLAGS || (exports.LENIENT_FLAGS = {})); -var METHODS; -(function (METHODS) { - METHODS[METHODS["DELETE"] = 0] = "DELETE"; - METHODS[METHODS["GET"] = 1] = "GET"; - METHODS[METHODS["HEAD"] = 2] = "HEAD"; - METHODS[METHODS["POST"] = 3] = "POST"; - METHODS[METHODS["PUT"] = 4] = "PUT"; - /* pathological */ - METHODS[METHODS["CONNECT"] = 5] = "CONNECT"; - METHODS[METHODS["OPTIONS"] = 6] = "OPTIONS"; - METHODS[METHODS["TRACE"] = 7] = "TRACE"; - /* WebDAV */ - METHODS[METHODS["COPY"] = 8] = "COPY"; - METHODS[METHODS["LOCK"] = 9] = "LOCK"; - METHODS[METHODS["MKCOL"] = 10] = "MKCOL"; - METHODS[METHODS["MOVE"] = 11] = "MOVE"; - METHODS[METHODS["PROPFIND"] = 12] = "PROPFIND"; - METHODS[METHODS["PROPPATCH"] = 13] = "PROPPATCH"; - METHODS[METHODS["SEARCH"] = 14] = "SEARCH"; - METHODS[METHODS["UNLOCK"] = 15] = "UNLOCK"; - METHODS[METHODS["BIND"] = 16] = "BIND"; - METHODS[METHODS["REBIND"] = 17] = "REBIND"; - METHODS[METHODS["UNBIND"] = 18] = "UNBIND"; - METHODS[METHODS["ACL"] = 19] = "ACL"; - /* subversion */ - METHODS[METHODS["REPORT"] = 20] = "REPORT"; - METHODS[METHODS["MKACTIVITY"] = 21] = "MKACTIVITY"; - METHODS[METHODS["CHECKOUT"] = 22] = "CHECKOUT"; - METHODS[METHODS["MERGE"] = 23] = "MERGE"; - /* upnp */ - METHODS[METHODS["M-SEARCH"] = 24] = "M-SEARCH"; - METHODS[METHODS["NOTIFY"] = 25] = "NOTIFY"; - METHODS[METHODS["SUBSCRIBE"] = 26] = "SUBSCRIBE"; - METHODS[METHODS["UNSUBSCRIBE"] = 27] = "UNSUBSCRIBE"; - /* RFC-5789 */ - METHODS[METHODS["PATCH"] = 28] = "PATCH"; - METHODS[METHODS["PURGE"] = 29] = "PURGE"; - /* CalDAV */ - METHODS[METHODS["MKCALENDAR"] = 30] = "MKCALENDAR"; - /* RFC-2068, section 19.6.1.2 */ - METHODS[METHODS["LINK"] = 31] = "LINK"; - METHODS[METHODS["UNLINK"] = 32] = "UNLINK"; - /* icecast */ - METHODS[METHODS["SOURCE"] = 33] = "SOURCE"; - /* RFC-7540, section 11.6 */ - METHODS[METHODS["PRI"] = 34] = "PRI"; - /* RFC-2326 RTSP */ - METHODS[METHODS["DESCRIBE"] = 35] = "DESCRIBE"; - METHODS[METHODS["ANNOUNCE"] = 36] = "ANNOUNCE"; - METHODS[METHODS["SETUP"] = 37] = "SETUP"; - METHODS[METHODS["PLAY"] = 38] = "PLAY"; - METHODS[METHODS["PAUSE"] = 39] = "PAUSE"; - METHODS[METHODS["TEARDOWN"] = 40] = "TEARDOWN"; - METHODS[METHODS["GET_PARAMETER"] = 41] = "GET_PARAMETER"; - METHODS[METHODS["SET_PARAMETER"] = 42] = "SET_PARAMETER"; - METHODS[METHODS["REDIRECT"] = 43] = "REDIRECT"; - METHODS[METHODS["RECORD"] = 44] = "RECORD"; - /* RAOP */ - METHODS[METHODS["FLUSH"] = 45] = "FLUSH"; -})(METHODS = exports.METHODS || (exports.METHODS = {})); -exports.METHODS_HTTP = [ - METHODS.DELETE, - METHODS.GET, - METHODS.HEAD, - METHODS.POST, - METHODS.PUT, - METHODS.CONNECT, - METHODS.OPTIONS, - METHODS.TRACE, - METHODS.COPY, - METHODS.LOCK, - METHODS.MKCOL, - METHODS.MOVE, - METHODS.PROPFIND, - METHODS.PROPPATCH, - METHODS.SEARCH, - METHODS.UNLOCK, - METHODS.BIND, - METHODS.REBIND, - METHODS.UNBIND, - METHODS.ACL, - METHODS.REPORT, - METHODS.MKACTIVITY, - METHODS.CHECKOUT, - METHODS.MERGE, - METHODS['M-SEARCH'], - METHODS.NOTIFY, - METHODS.SUBSCRIBE, - METHODS.UNSUBSCRIBE, - METHODS.PATCH, - METHODS.PURGE, - METHODS.MKCALENDAR, - METHODS.LINK, - METHODS.UNLINK, - METHODS.PRI, - // TODO(indutny): should we allow it with HTTP? - METHODS.SOURCE, -]; -exports.METHODS_ICE = [ - METHODS.SOURCE, -]; -exports.METHODS_RTSP = [ - METHODS.OPTIONS, - METHODS.DESCRIBE, - METHODS.ANNOUNCE, - METHODS.SETUP, - METHODS.PLAY, - METHODS.PAUSE, - METHODS.TEARDOWN, - METHODS.GET_PARAMETER, - METHODS.SET_PARAMETER, - METHODS.REDIRECT, - METHODS.RECORD, - METHODS.FLUSH, - // For AirPlay - METHODS.GET, - METHODS.POST, -]; -exports.METHOD_MAP = utils_1.enumToMap(METHODS); -exports.H_METHOD_MAP = {}; -Object.keys(exports.METHOD_MAP).forEach((key) => { - if (/^H/.test(key)) { - exports.H_METHOD_MAP[key] = exports.METHOD_MAP[key]; - } -}); -var FINISH; -(function (FINISH) { - FINISH[FINISH["SAFE"] = 0] = "SAFE"; - FINISH[FINISH["SAFE_WITH_CB"] = 1] = "SAFE_WITH_CB"; - FINISH[FINISH["UNSAFE"] = 2] = "UNSAFE"; -})(FINISH = exports.FINISH || (exports.FINISH = {})); -exports.ALPHA = []; -for (let i = 'A'.charCodeAt(0); i <= 'Z'.charCodeAt(0); i++) { - // Upper case - exports.ALPHA.push(String.fromCharCode(i)); - // Lower case - exports.ALPHA.push(String.fromCharCode(i + 0x20)); -} -exports.NUM_MAP = { - 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, - 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, -}; -exports.HEX_MAP = { - 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, - 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, - A: 0XA, B: 0XB, C: 0XC, D: 0XD, E: 0XE, F: 0XF, - a: 0xa, b: 0xb, c: 0xc, d: 0xd, e: 0xe, f: 0xf, -}; -exports.NUM = [ - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', -]; -exports.ALPHANUM = exports.ALPHA.concat(exports.NUM); -exports.MARK = ['-', '_', '.', '!', '~', '*', '\'', '(', ')']; -exports.USERINFO_CHARS = exports.ALPHANUM - .concat(exports.MARK) - .concat(['%', ';', ':', '&', '=', '+', '$', ',']); -// TODO(indutny): use RFC -exports.STRICT_URL_CHAR = [ - '!', '"', '$', '%', '&', '\'', - '(', ')', '*', '+', ',', '-', '.', '/', - ':', ';', '<', '=', '>', - '@', '[', '\\', ']', '^', '_', - '`', - '{', '|', '}', '~', -].concat(exports.ALPHANUM); -exports.URL_CHAR = exports.STRICT_URL_CHAR - .concat(['\t', '\f']); -// All characters with 0x80 bit set to 1 -for (let i = 0x80; i <= 0xff; i++) { - exports.URL_CHAR.push(i); -} -exports.HEX = exports.NUM.concat(['a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F']); -/* Tokens as defined by rfc 2616. Also lowercases them. - * token = 1*<any CHAR except CTLs or separators> - * separators = "(" | ")" | "<" | ">" | "@" - * | "," | ";" | ":" | "\" | <"> - * | "/" | "[" | "]" | "?" | "=" - * | "{" | "}" | SP | HT - */ -exports.STRICT_TOKEN = [ - '!', '#', '$', '%', '&', '\'', - '*', '+', '-', '.', - '^', '_', '`', - '|', '~', -].concat(exports.ALPHANUM); -exports.TOKEN = exports.STRICT_TOKEN.concat([' ']); -/* - * Verify that a char is a valid visible (printable) US-ASCII - * character or %x80-FF - */ -exports.HEADER_CHARS = ['\t']; -for (let i = 32; i <= 255; i++) { - if (i !== 127) { - exports.HEADER_CHARS.push(i); - } -} -// ',' = \x44 -exports.CONNECTION_TOKEN_CHARS = exports.HEADER_CHARS.filter((c) => c !== 44); -exports.MAJOR = exports.NUM_MAP; -exports.MINOR = exports.MAJOR; -var HEADER_STATE; -(function (HEADER_STATE) { - HEADER_STATE[HEADER_STATE["GENERAL"] = 0] = "GENERAL"; - HEADER_STATE[HEADER_STATE["CONNECTION"] = 1] = "CONNECTION"; - HEADER_STATE[HEADER_STATE["CONTENT_LENGTH"] = 2] = "CONTENT_LENGTH"; - HEADER_STATE[HEADER_STATE["TRANSFER_ENCODING"] = 3] = "TRANSFER_ENCODING"; - HEADER_STATE[HEADER_STATE["UPGRADE"] = 4] = "UPGRADE"; - HEADER_STATE[HEADER_STATE["CONNECTION_KEEP_ALIVE"] = 5] = "CONNECTION_KEEP_ALIVE"; - HEADER_STATE[HEADER_STATE["CONNECTION_CLOSE"] = 6] = "CONNECTION_CLOSE"; - HEADER_STATE[HEADER_STATE["CONNECTION_UPGRADE"] = 7] = "CONNECTION_UPGRADE"; - HEADER_STATE[HEADER_STATE["TRANSFER_ENCODING_CHUNKED"] = 8] = "TRANSFER_ENCODING_CHUNKED"; -})(HEADER_STATE = exports.HEADER_STATE || (exports.HEADER_STATE = {})); -exports.SPECIAL_HEADERS = { - 'connection': HEADER_STATE.CONNECTION, - 'content-length': HEADER_STATE.CONTENT_LENGTH, - 'proxy-connection': HEADER_STATE.CONNECTION, - 'transfer-encoding': HEADER_STATE.TRANSFER_ENCODING, - 'upgrade': HEADER_STATE.UPGRADE, -}; -//# sourceMappingURL=constants.js.map - -/***/ }), - -/***/ 7445: -/***/ ((module) => { - -module.exports = 'AGFzbQEAAAABMAhgAX8Bf2ADf39/AX9gBH9/f38Bf2AAAGADf39/AGABfwBgAn9/AGAGf39/f39/AALLAQgDZW52GHdhc21fb25faGVhZGVyc19jb21wbGV0ZQACA2VudhV3YXNtX29uX21lc3NhZ2VfYmVnaW4AAANlbnYLd2FzbV9vbl91cmwAAQNlbnYOd2FzbV9vbl9zdGF0dXMAAQNlbnYUd2FzbV9vbl9oZWFkZXJfZmllbGQAAQNlbnYUd2FzbV9vbl9oZWFkZXJfdmFsdWUAAQNlbnYMd2FzbV9vbl9ib2R5AAEDZW52GHdhc21fb25fbWVzc2FnZV9jb21wbGV0ZQAAA0ZFAwMEAAAFAAAAAAAABQEFAAUFBQAABgAAAAAGBgYGAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAAABAQcAAAUFAwABBAUBcAESEgUDAQACBggBfwFBgNQECwfRBSIGbWVtb3J5AgALX2luaXRpYWxpemUACRlfX2luZGlyZWN0X2Z1bmN0aW9uX3RhYmxlAQALbGxodHRwX2luaXQAChhsbGh0dHBfc2hvdWxkX2tlZXBfYWxpdmUAQQxsbGh0dHBfYWxsb2MADAZtYWxsb2MARgtsbGh0dHBfZnJlZQANBGZyZWUASA9sbGh0dHBfZ2V0X3R5cGUADhVsbGh0dHBfZ2V0X2h0dHBfbWFqb3IADxVsbGh0dHBfZ2V0X2h0dHBfbWlub3IAEBFsbGh0dHBfZ2V0X21ldGhvZAARFmxsaHR0cF9nZXRfc3RhdHVzX2NvZGUAEhJsbGh0dHBfZ2V0X3VwZ3JhZGUAEwxsbGh0dHBfcmVzZXQAFA5sbGh0dHBfZXhlY3V0ZQAVFGxsaHR0cF9zZXR0aW5nc19pbml0ABYNbGxodHRwX2ZpbmlzaAAXDGxsaHR0cF9wYXVzZQAYDWxsaHR0cF9yZXN1bWUAGRtsbGh0dHBfcmVzdW1lX2FmdGVyX3VwZ3JhZGUAGhBsbGh0dHBfZ2V0X2Vycm5vABsXbGxodHRwX2dldF9lcnJvcl9yZWFzb24AHBdsbGh0dHBfc2V0X2Vycm9yX3JlYXNvbgAdFGxsaHR0cF9nZXRfZXJyb3JfcG9zAB4RbGxodHRwX2Vycm5vX25hbWUAHxJsbGh0dHBfbWV0aG9kX25hbWUAIBJs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ADcDACAAQShqQgA3AwAgAEEgakIANwMAIABBEGpCADcDACAAQQhqQgA3AwAgAEHdATYCHEEAC3sBAX8CQCAAKAIMIgMNAAJAIAAoAgRFDQAgACABNgIECwJAIAAgASACEMSAgIAAIgMNACAAKAIMDwsgACADNgIcQQAhAyAAKAIEIgFFDQAgACABIAIgACgCCBGBgICAAAAiAUUNACAAIAI2AhQgACABNgIMIAEhAwsgAwvk8wEDDn8DfgR/I4CAgIAAQRBrIgMkgICAgAAgASEEIAEhBSABIQYgASEHIAEhCCABIQkgASEKIAEhCyABIQwgASENIAEhDiABIQ8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgACgCHCIQQX9qDt0B2gEB2QECAwQFBgcICQoLDA0O2AEPENcBERLWARMUFRYXGBkaG+AB3wEcHR7VAR8gISIjJCXUASYnKCkqKyzTAdIBLS7RAdABLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVG2wFHSElKzwHOAUvNAUzMAU1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4ABgQGCAYMBhAGFAYYBhwGIAYkB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QAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAC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FCAAIBA2AgxBACEQDLIBCyAAKAIEIRAgAEEANgIEAkAgACAQIAEQp4CAgAAiEA0AIAEhAQxNCyAAQdMANgIcIAAgATYCFCAAIBA2AgxBACEQDLEBCyAAKAIEIRAgAEEANgIEAkAgACAQIAEQp4CAgAAiEA0AIAEhAQxRCyAAQeUANgIcIAAgATYCFCAAIBA2AgxBACEQDLABCyAAQQA2AhwgACABNgIUIABBxoqAgAA2AhAgAEEHNgIMQQAhEAyvAQsgACgCBCEQIABBADYCBAJAIAAgECABEKeAgIAAIhANACABIQEMSQsgAEHSADYCHCAAIAE2AhQgACAQNgIMQQAhEAyuAQsgACgCBCEQIABBADYCBAJAIAAgECABEKeAgIAAIhANACABIQEMSQsgAEHTADYCHCAAIAE2AhQgACAQNgIMQQAhEAytAQsgACgCBCEQIABBADYCBAJAIAAgECABEKeAgIAAIhANACABIQEMTQsgAEHlADYCHCAAIAE2AhQgACAQNgIMQQAhEAysAQsgAEEANgIcIAAgATYCFCAAQdyIgIAANgIQIABBBzYCDEEAIRAMqwELIBBBP0cNASABQQFqIQELQQUhEAyQAQtBACEQIABBADYCHCAAIAE2AhQgAEH9koCAADYCECAAQQc2AgwMqAELIAAoAgQhECAAQQA2AgQCQCAAIBAgARCngICAACIQDQAgASEBDEILIABB0gA2AhwgACABNgIUIAAgEDYCDEEAIRAMpwELIAAoAgQhECAAQQA2AgQCQCAAIBAgARCngICAACIQDQAgASEBDEILIABB0wA2AhwgACABNgIUIAAgEDYCDEEAIRAMpgELIAAoAgQhECAAQQA2AgQCQCAAIBAgARCngICAACIQDQAgASEBDEYLIABB5QA2AhwgACABNgIUIAAgEDYCDEEAIRAMpQELIAAoAgQhASAAQQA2AgQCQCAAIAEgFBCngICAACIBDQAgFCEBDD8LIABB0gA2AhwgACAUNgIUIAAgATYCDEEAIRAMpAELIAAoAgQhASAAQQA2AgQCQCAAIAEgFBCngICAACIBDQAgFCEBDD8LIABB0wA2AhwgACAUNgIUIAAgATYCDEEAIRAMowELIAAoAgQhASAAQQA2AgQCQCAAIAEgFBCngICAACIBDQAgFCEBDEMLIABB5QA2AhwgACAU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YWdlX2JlZ2luYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX3ZhbHVlYCBjYWxsYmFjayBlcnJvcgBgb25fc3RhdHVzX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fdmVyc2lvbl9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX3VybF9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX2NodW5rX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25faGVhZGVyX3ZhbHVlX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fbWVzc2FnZV9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX21ldGhvZF9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX2hlYWRlcl9maWVsZF9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX2NodW5rX2V4dGVuc2lvbl9uYW1lYCBjYWxsYmFjayBlcnJvcgBVbmV4cGVjdGVkIGNoYXIgaW4gdXJsIHNlcnZlcgBJbnZhbGlkIGhlYWRlciB2YWx1ZSBjaGFyAEludmFsaWQgaGVhZGVyIGZpZWxkIGNoYXIAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl92ZXJzaW9uAEludmFsaWQgbWlub3IgdmVyc2lvbgBJbnZhbGlkIG1ham9yIHZlcnNpb24ARXhwZWN0ZWQgc3BhY2UgYWZ0ZXIgdmVyc2lvbgBFeHBlY3RlZCBDUkxGIGFmdGVyIHZlcnNpb24ASW52YWxpZCBIVFRQIHZlcnNpb24ASW52YWxpZCBoZWFkZXIgdG9rZW4AU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl91cmwASW52YWxpZCBjaGFyYWN0ZXJzIGluIHVybABVbmV4cGVjdGVkIHN0YXJ0IGNoYXIgaW4gdXJsAERvdWJsZSBAIGluIHVybABFbXB0eSBDb250ZW50LUxlbmd0aABJbnZhbGlkIGNoYXJhY3RlciBpbiBDb250ZW50LUxlbmd0aABEdXBsaWNhdGUgQ29udGVudC1MZW5ndGgASW52YWxpZCBjaGFyIGluIHVybCBwYXRoAENvbnRlbnQtTGVuZ3RoIGNhbid0IGJlIHByZXNlbnQgd2l0aCBUcmFuc2Zlci1FbmNvZGluZwBJbnZhbGlkIGNoYXJhY3RlciBpbiBjaHVuayBzaXplAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25faGVhZGVyX3ZhbHVlAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fY2h1bmtfZXh0ZW5zaW9uX3ZhbHVlAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgdmFsdWUATWlzc2luZyBleHBlY3RlZCBMRiBhZnRlciBoZWFkZXIgdmFsdWUASW52YWxpZCBgVHJhbnNmZXItRW5jb2RpbmdgIGhlYWRlciB2YWx1ZQBJbnZhbGlkIGNoYXJhY3RlciBpbiBjaHVuayBleHRlbnNpb25zIHF1b3RlIHZhbHVlAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGVkIHZhbHVlAFBhdXNlZCBieSBvbl9oZWFkZXJzX2NvbXBsZXRlAEludmFsaWQgRU9GIHN0YXRlAG9uX3Jlc2V0IHBhdXNlAG9uX2NodW5rX2hlYWRlciBwYXVzZQBvbl9tZXNzYWdlX2JlZ2luIHBhdXNlAG9uX2NodW5rX2V4dGVuc2lvbl92YWx1ZSBwYXVzZQBvbl9zdGF0dXNfY29tcGxldGUgcGF1c2UAb25fdmVyc2lvbl9jb21wbGV0ZSBwYXVzZQBvbl91cmxfY29tcGxldGUgcGF1c2UAb25fY2h1bmtfY29tcGxldGUgcGF1c2UAb25faGVhZGVyX3ZhbHVlX2NvbXBsZXRlIHBhdXNlAG9uX21lc3NhZ2VfY29tcGxldGUgcGF1c2UAb25fbWV0aG9kX2NvbXBsZXRlIHBhdXNlAG9uX2hlYWRlcl9maWVsZF9jb21wbGV0ZSBwYXVzZQBvbl9jaHVua19leHRlbnNpb25fbmFtZSBwYXVzZQBVbmV4cGVjdGVkIHNwYWNlIGFmdGVyIHN0YXJ0IGxpbmUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9jaHVua19leHRlbnNpb25fbmFtZQBJbnZhbGlkIGNoYXJhY3RlciBpbiBjaHVuayBleHRlbnNpb25zIG5hbWUAUGF1c2Ugb24gQ09OTkVDVC9VcGdyYWRlAFBhdXNlIG9uIFBSSS9VcGdyYWRlAEV4cGVjdGVkIEhUVFAvMiBDb25uZWN0aW9uIFByZWZhY2UAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9tZXRob2QARXhwZWN0ZWQgc3BhY2UgYWZ0ZXIgbWV0aG9kAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25faGVhZGVyX2ZpZWxkAFBhdXNlZABJbnZhbGlkIHdvcmQgZW5jb3VudGVyZWQASW52YWxpZCBtZXRob2QgZW5jb3VudGVyZWQAVW5leHBlY3RlZCBjaGFyIGluIHVybCBzY2hlbWEAUmVxdWVzdCBoYXMgaW52YWxpZCBgVHJhbnNmZXItRW5jb2RpbmdgAFNXSVRDSF9QUk9YWQBVU0VfUFJPWFkATUtBQ1RJVklUWQBVTlBST0NFU1NBQkxFX0VOVElUWQBDT1BZAE1PVkVEX1BFUk1BTkVOVExZAFRPT19FQVJMWQBOT1RJRlkARkFJTEVEX0RFUEVOREVOQ1kAQkFEX0dBVEVXQVkAUExBWQBQVVQAQ0hFQ0tPVVQAR0FURVdBWV9USU1FT1VUAFJFUVVFU1RfVElNRU9VVABORVRXT1JLX0NPTk5FQ1RfVElNRU9VVABDT05ORUNUSU9OX1RJTUVPVVQATE9HSU5fVElNRU9VVABORVRXT1JLX1JFQURfVElNRU9VVABQT1NUAE1JU0RJUkVDVEVEX1JFUVVFU1QAQ0xJRU5UX0NMT1NFRF9SRVFVRVNUAENMSUVOVF9DTE9TRURfTE9BRF9CQUxBTkNFRF9SRVFVRVNUAEJBRF9SRVFVRVNUAEhUVFBfUkVRVUVTVF9TRU5UX1RPX0hUVFBTX1BPUlQAUkVQT1JUAElNX0FfVEVBUE9UAFJFU0VUX0NPTlRFTlQATk9fQ09OVEVOVABQQVJUSUFMX0NPTlRFTlQASFBFX0lOVkFMSURfQ09OU1RBTlQASFBFX0NCX1JFU0VUAEdFVABIUEVfU1RSSUNUAENPTkZMSUNUAFRFTVBPUkFSWV9SRURJUkVDVABQRVJNQU5FTlRfUkVESVJFQ1QAQ09OTkVDVABNVUxUSV9TVEFUVVMASFBFX0lOVkFMSURfU1RBVFVTAFRPT19NQU5ZX1JFUVVFU1RTAEVBUkxZX0hJTlRTAFVOQVZBSUxBQkxFX0ZPUl9MRUdBTF9SRUFTT05TAE9QVElPTlMAU1dJVENISU5HX1BST1RPQ09MUwBWQVJJQU5UX0FMU09fTkVHT1RJQVRFUwBNVUxUSVBMRV9DSE9JQ0VTAElOVEVSTkFMX1NFUlZFUl9FUlJPUgBXRUJfU0VSVkVSX1VOS05PV05fRVJST1IAUkFJTEdVTl9FUlJPUgBJREVOVElUWV9QUk9WSURFUl9BVVRIRU5USUNBVElPTl9FUlJPUgBTU0xfQ0VSVElGSUNBVEVfRVJST1IASU5WQUxJRF9YX0ZPUldBUkRFRF9GT1IAU0VUX1BBUkFNRVRFUgBHRVRfUEFSQU1FVEVSAEhQRV9VU0VSAFNFRV9PVEhFUgBIUEVfQ0JfQ0hVTktfSEVBREVSAE1LQ0FMRU5EQVIAU0VUVVAAV0VCX1NFUlZFUl9JU19ET1dOAFRFQVJET1dOAEhQRV9DTE9TRURfQ09OTkVDVElPTgBIRVVSSVNUSUNfRVhQSVJBVElPTgBESVNDT05ORUNURURfT1BFUkFUSU9OAE5PTl9BVVRIT1JJVEFUSVZFX0lORk9STUFUSU9OAEhQRV9JTlZBTElEX1ZFUlNJT04ASFBFX0NCX01FU1NBR0VfQkVHSU4AU0lURV9JU19GUk9aRU4ASFBFX0lOVkFMSURfSEVBREVSX1RPS0VOAElOVkFMSURfVE9LRU4ARk9SQklEREVOAEVOSEFOQ0VfWU9VUl9DQUxNAEhQRV9JTlZBTElEX1VSTABCTE9DS0VEX0JZX1BBUkVOVEFMX0NPTlRST0wATUtDT0wAQUNMAEhQRV9JTlRFUk5BTABSRVFVRVNUX0hFQURFUl9GSUVMRFNfVE9PX0xBUkdFX1VOT0ZGSUNJQUwASFBFX09LAFVOTElOSwBVTkxPQ0sAUFJJAFJFVFJZX1dJVEgASFBFX0lOVkFMSURfQ09OVEVOVF9MRU5HVEgASFBFX1VORVhQRUNURURfQ09OVEVOVF9MRU5HVEgARkxVU0gAUFJPUFBBVENIAE0tU0VBUkNIAFVSSV9UT09fTE9ORwBQUk9DRVNTSU5HAE1JU0NFTExBTkVPVVNfUEVSU0lTVEVOVF9XQVJOSU5HAE1JU0NFTExBTkVPVVNfV0FSTklORwBIUEVfSU5WQUxJRF9UUkFOU0ZFUl9FTkNPRElORwBFeHBlY3RlZCBDUkxGAEhQRV9JTlZBTElEX0NIVU5LX1NJWkUATU9WRQBDT05USU5VRQBIUEVfQ0JfU1RBVFVTX0NPTVBMRVRFAEhQRV9DQl9IRUFERVJTX0NPTVBMRVRFAEhQRV9DQl9WRVJTSU9OX0NPTVBMRVRFAEhQRV9DQl9VUkxfQ09NUExFVEUASFBFX0NCX0NIVU5LX0NPTVBMRVRFAEhQRV9DQl9IRUFERVJfVkFMVUVfQ09NUExFVEUASFBFX0NCX0NIVU5LX0VYVEVOU0lPTl9WQUxVRV9DT01QTEVURQBIUEVfQ0JfQ0hVTktfRVhURU5TSU9OX05BTUVfQ09NUExFVEUASFBFX0NCX01FU1NBR0VfQ09NUExFVEUASFBFX0NCX01FVEhPRF9DT01QTEVURQBIUEVfQ0JfSEVBREVSX0ZJRUxEX0NPTVBMRVRFAERFTEVURQBIUEVfSU5WQUxJRF9FT0ZfU1RBVEUASU5WQUxJRF9TU0xfQ0VSVElGSUNBVEUAUEFVU0UATk9fUkVTUE9OU0UAVU5TVVBQT1JURURfTUVESUFfVFlQRQBHT05FAE5PVF9BQ0NFUFRBQkxFAFNFUlZJQ0VfVU5BVkFJTEFCTEUAUkFOR0VfTk9UX1NBVElTRklBQkxFAE9SSUdJTl9JU19VTlJFQUNIQUJMRQBSRVNQT05TRV9JU19TVEFMRQBQVVJHRQBNRVJHRQBSRVFVRVNUX0hFQURFUl9GSUVMRFNfVE9PX0xBUkdFAFJFUVVFU1RfSEVBREVSX1RPT19MQVJHRQBQQVlMT0FEX1RPT19MQVJHRQBJTlNVRkZJQ0lFTlRfU1RPUkFHRQBIUEVfUEFVU0VEX1VQR1JBREUASFBFX1BBVVNFRF9IMl9VUEdSQURFAFNPVVJDRQBBTk5PVU5DRQBUUkFDRQBIUEVfVU5FWFBFQ1RFRF9TUEFDRQBERVNDUklCRQBVTlNVQlNDUklCRQBSRUNPUkQASFBFX0lOVkFMSURfTUVUSE9EAE5PVF9GT1VORABQUk9QRklORABVTkJJTkQAUkVCSU5EAFVOQVVUSE9SSVpFRABNRVRIT0RfTk9UX0FMTE9XRUQASFRUUF9WRVJTSU9OX05PVF9TVVBQT1JURUQAQUxSRUFEWV9SRVBPUlRFRABBQ0NFUFRFRABOT1RfSU1QTEVNRU5URUQATE9PUF9ERVRFQ1RFRABIUEVfQ1JfRVhQRUNURUQASFBFX0xGX0VYUEVDVEVEAENSRUFURUQASU1fVVNFRABIUEVfUEFVU0VEAFRJTUVPVVRfT0NDVVJFRABQQVlNRU5UX1JFUVVJUkVEAFBSRUNPTkRJVElPTl9SRVFVSVJFRABQUk9YWV9BVVRIRU5USUNBVElPTl9SRVFVSVJFRABORVRXT1JLX0FVVEhFTlRJQ0FUSU9OX1JFUVVJUkVEAExFTkdUSF9SRVFVSVJFRABTU0xfQ0VSVElGSUNBVEVfUkVRVUlSRUQAVVBHUkFERV9SRVFVSVJFRABQQUdFX0VYUElSRUQAUFJFQ09ORElUSU9OX0ZBSUxFRABFWFBFQ1RBVElPTl9GQUlMRUQAUkVWQUxJREFUSU9OX0ZBSUxFRABTU0xfSEFORFNIQUtFX0ZBSUxFRABMT0NLRUQAVFJBTlNGT1JNQVRJT05fQVBQTElFRABOT1RfTU9ESUZJRUQATk9UX0VYVEVOREVEAEJBTkRXSURUSF9MSU1JVF9FWENFRURFRABTSVRFX0lTX09WRVJMT0FERUQASEVBRABFeHBlY3RlZCBIVFRQLwAAXhMAACYTAAAwEAAA8BcAAJ0TAAAVEgAAORcAAPASAAAKEAAAdRIAAK0SAACCEwAATxQAAH8QAACgFQAAIxQAAIkSAACLFAAATRUAANQRAADPFAAAEBgAAMkWAADcFgAAwREAAOAXAAC7FAAAdBQAAHwVAADlFAAACBcAAB8QAABlFQAAoxQAACgVAAACFQAAmRUAACwQAACLGQAATw8AANQOAABqEAAAzhAAAAIXAACJDgAAbhMAABwTAABmFAAAVhcAAMETAADNEwAAbBMAAGgXAABmFwAAXxcAACITAADODwAAaQ4AANgOAABjFgAAyxMAAKoOAAAoFwAAJhcAAMUTAABdFgAA6BEAAGcTAABlEwAA8hYAAHMTAAAdFwAA+RYAAPMRAADPDgAAzhUAAAwSAACzEQAApREAAGEQAAAyFwAAuxMAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIDAgICAgIAAAICAAICAAICAgICAgICAgIABAAAAAAAAgICAgICAgICAgICAgICAgICAgICAgICAgIAAAACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgACAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAACAAICAgICAAACAgACAgACAgICAgICAgICAAMABAAAAAICAgICAgICAgICAgICAgICAgICAgICAgICAAAAAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAAgACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbG9zZWVlcC1hbGl2ZQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBY2h1bmtlZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEAAQEBAQEAAAEBAAEBAAEBAQEBAQEBAQEAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABlY3Rpb25lbnQtbGVuZ3Rob25yb3h5LWNvbm5lY3Rpb24AAAAAAAAAAAAAAAAAAAByYW5zZmVyLWVuY29kaW5ncGdyYWRlDQoNCg0KU00NCg0KVFRQL0NFL1RTUC8AAAAAAAAAAAAAAAABAgABAwAAAAAAAAAAAAAAAAAAAAAAAAQBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAQIAAQMAAAAAAAAAAAAAAAAAAAAAAAAEAQEFAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAEAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAAAAQAAAgAAAAAAAAAAAAAAAAAAAAAAAAMEAAAEBAQEBAQEBAQEBAUEBAQEBAQEBAQEBAQABAAGBwQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEAAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAEAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwAAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAABAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAIAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABOT1VOQ0VFQ0tPVVRORUNURVRFQ1JJQkVMVVNIRVRFQURTRUFSQ0hSR0VDVElWSVRZTEVOREFSVkVPVElGWVBUSU9OU0NIU0VBWVNUQVRDSEdFT1JESVJFQ1RPUlRSQ0hQQVJBTUVURVJVUkNFQlNDUklCRUFSRE9XTkFDRUlORE5LQ0tVQlNDUklCRUhUVFAvQURUUC8=' - - -/***/ }), - -/***/ 6442: -/***/ ((module) => { - -module.exports = 'AGFzbQEAAAABMAhgAX8Bf2ADf39/AX9gBH9/f38Bf2AAAGADf39/AGABfwBgAn9/AGAGf39/f39/AALLAQgDZW52GHdhc21fb25faGVhZGVyc19jb21wbGV0ZQACA2VudhV3YXNtX29uX21lc3NhZ2VfYmVnaW4AAANlbnYLd2FzbV9vbl91cmwAAQNlbnYOd2FzbV9vbl9zdGF0dXMAAQNlbnYUd2FzbV9vbl9oZWFkZXJfZmllbGQAAQNlbnYUd2FzbV9vbl9oZWFkZXJfdmFsdWUAAQNlbnYMd2FzbV9vbl9ib2R5AAEDZW52GHdhc21fb25fbWVzc2FnZV9jb21wbGV0ZQAAA0ZFAwMEAAAFAAAAAAAABQEFAAUFBQAABgAAAAAGBgYGAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAAABAQcAAAUFAwABBAUBcAESEgUDAQACBggBfwFBgNQECwfRBSIGbWVtb3J5AgALX2luaXRpYWxpemUACRlfX2luZGlyZWN0X2Z1bmN0aW9uX3RhYmxlAQALbGxodHRwX2luaXQAChhsbGh0dHBfc2hvdWxkX2tlZXBfYWxpdmUAQQxsbGh0dHBfYWxsb2MADAZtYWxsb2MARgtsbGh0dHBfZnJlZQANBGZyZWUASA9sbGh0dHBfZ2V0X3R5cGUADhVsbGh0dHBfZ2V0X2h0dHBfbWFqb3IADxVsbGh0dHBfZ2V0X2h0dHBfbWlub3IAEBFsbGh0dHBfZ2V0X21ldGhvZAARFmxsaHR0cF9nZXRfc3RhdHVzX2NvZGUAEhJsbGh0dHBfZ2V0X3VwZ3JhZGUAEwxsbGh0dHBfcmVzZXQAFA5sbGh0dHBfZXhlY3V0ZQAVFGxsaHR0cF9zZXR0aW5nc19pbml0ABYNbGxodHRwX2ZpbmlzaAAXDGxsaHR0cF9wYXVzZQAYDWxsaHR0cF9yZXN1bWUAGRtsbGh0dHBfcmVzdW1lX2FmdGVyX3VwZ3JhZGUAGhBsbGh0dHBfZ2V0X2Vycm5vABsXbGxodHRwX2dldF9lcnJvcl9yZWFzb24AHBdsbGh0dHBfc2V0X2Vycm9yX3JlYXNvbgAdFGxsaHR0cF9nZXRfZXJyb3JfcG9zAB4RbGxodHRwX2Vycm5vX25hbWUAHxJsbGh0dHBfbWV0aG9kX25hbWUAIBJs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IAH9CwMAIABBMGogAf0LAwAgAEEgaiAB/QsDACAAQd0BNgIcQQALewEBfwJAIAAoAgwiAw0AAkAgACgCBEUNACAAIAE2AgQLAkAgACABIAIQxICAgAAiAw0AIAAoAgwPCyAAIAM2AhxBACEDIAAoAgQiAUUNACAAIAEgAiAAKAIIEYGAgIAAACIBRQ0AIAAgAjYCFCAAIAE2AgwgASEDCyADC+TzAQMOfwN+BH8jgICAgABBEGsiAySAgICAACABIQQgASEFIAEhBiABIQcgASEIIAEhCSABIQogASELIAEhDCABIQ0gASEOIAEhDwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAAKAIcIhBBf2oO3QHaAQHZAQIDBAUGBwgJCgsMDQ7YAQ8Q1wEREtYBExQVFhcYGRob4AHfARwdHtUBHyAhIiMkJdQBJicoKSorLNMB0gEtLtEB0AEvMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUbbAUdISUrPAc4BS80BTMwBTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEB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QAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIBAOxwEAAQID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YWNrIGVycm9yAGBvbl9jaHVua19leHRlbnNpb25fdmFsdWVgIGNhbGxiYWNrIGVycm9yAGBvbl9zdGF0dXNfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl92ZXJzaW9uX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fdXJsX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9oZWFkZXJfdmFsdWVfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9tZXNzYWdlX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fbWV0aG9kX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25faGVhZGVyX2ZpZWxkX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX25hbWVgIGNhbGxiYWNrIGVycm9yAFVuZXhwZWN0ZWQgY2hhciBpbiB1cmwgc2VydmVyAEludmFsaWQgaGVhZGVyIHZhbHVlIGNoYXIASW52YWxpZCBoZWFkZXIgZmllbGQgY2hhcgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3ZlcnNpb24ASW52YWxpZCBtaW5vciB2ZXJzaW9uAEludmFsaWQgbWFqb3IgdmVyc2lvbgBFeHBlY3RlZCBzcGFjZSBhZnRlciB2ZXJzaW9uAEV4cGVjdGVkIENSTEYgYWZ0ZXIgdmVyc2lvbgBJbnZhbGlkIEhUVFAgdmVyc2lvbgBJbnZhbGlkIGhlYWRlciB0b2tlbgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3VybABJbnZhbGlkIGNoYXJhY3RlcnMgaW4gdXJsAFVuZXhwZWN0ZWQgc3RhcnQgY2hhciBpbiB1cmwARG91YmxlIEAgaW4gdXJsAEVtcHR5IENvbnRlbnQtTGVuZ3RoAEludmFsaWQgY2hhcmFjdGVyIGluIENvbnRlbnQtTGVuZ3RoAER1cGxpY2F0ZSBDb250ZW50LUxlbmd0aABJbnZhbGlkIGNoYXIgaW4gdXJsIHBhdGgAQ29udGVudC1MZW5ndGggY2FuJ3QgYmUgcHJlc2VudCB3aXRoIFRyYW5zZmVyLUVuY29kaW5nAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIHNpemUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfdmFsdWUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9jaHVua19leHRlbnNpb25fdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyB2YWx1ZQBNaXNzaW5nIGV4cGVjdGVkIExGIGFmdGVyIGhlYWRlciB2YWx1ZQBJbnZhbGlkIGBUcmFuc2Zlci1FbmNvZGluZ2AgaGVhZGVyIHZhbHVlAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGUgdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBxdW90ZWQgdmFsdWUAUGF1c2VkIGJ5IG9uX2hlYWRlcnNfY29tcGxldGUASW52YWxpZCBFT0Ygc3RhdGUAb25fcmVzZXQgcGF1c2UAb25fY2h1bmtfaGVhZGVyIHBhdXNlAG9uX21lc3NhZ2VfYmVnaW4gcGF1c2UAb25fY2h1bmtfZXh0ZW5zaW9uX3ZhbHVlIHBhdXNlAG9uX3N0YXR1c19jb21wbGV0ZSBwYXVzZQBvbl92ZXJzaW9uX2NvbXBsZXRlIHBhdXNlAG9uX3VybF9jb21wbGV0ZSBwYXVzZQBvbl9jaHVua19jb21wbGV0ZSBwYXVzZQBvbl9oZWFkZXJfdmFsdWVfY29tcGxldGUgcGF1c2UAb25fbWVzc2FnZV9jb21wbGV0ZSBwYXVzZQBvbl9tZXRob2RfY29tcGxldGUgcGF1c2UAb25faGVhZGVyX2ZpZWxkX2NvbXBsZXRlIHBhdXNlAG9uX2NodW5rX2V4dGVuc2lvbl9uYW1lIHBhdXNlAFVuZXhwZWN0ZWQgc3BhY2UgYWZ0ZXIgc3RhcnQgbGluZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX2NodW5rX2V4dGVuc2lvbl9uYW1lAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgbmFtZQBQYXVzZSBvbiBDT05ORUNUL1VwZ3JhZGUAUGF1c2Ugb24gUFJJL1VwZ3JhZGUARXhwZWN0ZWQgSFRUUC8yIENvbm5lY3Rpb24gUHJlZmFjZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX21ldGhvZABFeHBlY3RlZCBzcGFjZSBhZnRlciBtZXRob2QAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfZmllbGQAUGF1c2VkAEludmFsaWQgd29yZCBlbmNvdW50ZXJlZABJbnZhbGlkIG1ldGhvZCBlbmNvdW50ZXJlZABVbmV4cGVjdGVkIGNoYXIgaW4gdXJsIHNjaGVtYQBSZXF1ZXN0IGhhcyBpbnZhbGlkIGBUcmFuc2Zlci1FbmNvZGluZ2AAU1dJVENIX1BST1hZAFVTRV9QUk9YWQBNS0FDVElWSVRZAFVOUFJPQ0VTU0FCTEVfRU5USVRZAENPUFkATU9WRURfUEVSTUFORU5UTFkAVE9PX0VBUkxZAE5PVElGWQBGQUlMRURfREVQRU5ERU5DWQBCQURfR0FURVdBWQBQTEFZAFBVVABDSEVDS09VVABHQVRFV0FZX1RJTUVPVVQAUkVRVUVTVF9USU1FT1VUAE5FVFdPUktfQ09OTkVDVF9USU1FT1VUAENPTk5FQ1RJT05fVElNRU9VVABMT0dJTl9USU1FT1VUAE5FVFdPUktfUkVBRF9USU1FT1VUAFBPU1QATUlTRElSRUNURURfUkVRVUVTVABDTElFTlRfQ0xPU0VEX1JFUVVFU1QAQ0xJRU5UX0NMT1NFRF9MT0FEX0JBTEFOQ0VEX1JFUVVFU1QAQkFEX1JFUVVFU1QASFRUUF9SRVFVRVNUX1NFTlRfVE9fSFRUUFNfUE9SVABSRVBPUlQASU1fQV9URUFQT1QAUkVTRVRfQ09OVEVOVABOT19DT05URU5UAFBBUlRJQUxfQ09OVEVOVABIUEVfSU5WQUxJRF9DT05TVEFOVABIUEVfQ0JfUkVTRVQAR0VUAEhQRV9TVFJJQ1QAQ09ORkxJQ1QAVEVNUE9SQVJZX1JFRElSRUNUAFBFUk1BTkVOVF9SRURJUkVDVABDT05ORUNUAE1VTFRJX1NUQVRVUwBIUEVfSU5WQUxJRF9TVEFUVVMAVE9PX01BTllfUkVRVUVTVFMARUFSTFlfSElOVFMAVU5BVkFJTEFCTEVfRk9SX0xFR0FMX1JFQVNPTlMAT1BUSU9OUwBTV0lUQ0hJTkdfUFJPVE9DT0xTAFZBUklBTlRfQUxTT19ORUdPVElBVEVTAE1VTFRJUExFX0NIT0lDRVMASU5URVJOQUxfU0VSVkVSX0VSUk9SAFdFQl9TRVJWRVJfVU5LTk9XTl9FUlJPUgBSQUlMR1VOX0VSUk9SAElERU5USVRZX1BST1ZJREVSX0FVVEhFTlRJQ0FUSU9OX0VSUk9SAFNTTF9DRVJUSUZJQ0FURV9FUlJPUgBJTlZBTElEX1hfRk9SV0FSREVEX0ZPUgBTRVRfUEFSQU1FVEVSAEdFVF9QQVJBTUVURVIASFBFX1VTRVIAU0VFX09USEVSAEhQRV9DQl9DSFVOS19IRUFERVIATUtDQUxFTkRBUgBTRVRVUABXRUJfU0VSVkVSX0lTX0RPV04AVEVBUkRPV04ASFBFX0NMT1NFRF9DT05ORUNUSU9OAEhFVVJJU1RJQ19FWFBJUkFUSU9OAERJU0NPTk5FQ1RFRF9PUEVSQVRJT04ATk9OX0FVVEhPUklUQVRJVkVfSU5GT1JNQVRJT04ASFBFX0lOVkFMSURfVkVSU0lPTgBIUEVfQ0JfTUVTU0FHRV9CRUdJTgBTSVRFX0lTX0ZST1pFTgBIUEVfSU5WQUxJRF9IRUFERVJfVE9LRU4ASU5WQUxJRF9UT0tFTgBGT1JCSURERU4ARU5IQU5DRV9ZT1VSX0NBTE0ASFBFX0lOVkFMSURfVVJMAEJMT0NLRURfQllfUEFSRU5UQUxfQ09OVFJPTABNS0NPTABBQ0wASFBFX0lOVEVSTkFMAFJFUVVFU1RfSEVBREVSX0ZJRUxEU19UT09fTEFSR0VfVU5PRkZJQ0lBTABIUEVfT0sAVU5MSU5LAFVOTE9DSwBQUkkAUkVUUllfV0lUSABIUEVfSU5WQUxJRF9DT05URU5UX0xFTkdUSABIUEVfVU5FWFBFQ1RFRF9DT05URU5UX0xFTkdUSABGTFVTSABQUk9QUEFUQ0gATS1TRUFSQ0gAVVJJX1RPT19MT05HAFBST0NFU1NJTkcATUlTQ0VMTEFORU9VU19QRVJTSVNURU5UX1dBUk5JTkcATUlTQ0VMTEFORU9VU19XQVJOSU5HAEhQRV9JTlZBTElEX1RSQU5TRkVSX0VOQ09ESU5HAEV4cGVjdGVkIENSTEYASFBFX0lOVkFMSURfQ0hVTktfU0laRQBNT1ZFAENPTlRJTlVFAEhQRV9DQl9TVEFUVVNfQ09NUExFVEUASFBFX0NCX0hFQURFUlNfQ09NUExFVEUASFBFX0NCX1ZFUlNJT05fQ09NUExFVEUASFBFX0NCX1VSTF9DT01QTEVURQBIUEVfQ0JfQ0hVTktfQ09NUExFVEUASFBFX0NCX0hFQURFUl9WQUxVRV9DT01QTEVURQBIUEVfQ0JfQ0hVTktfRVhURU5TSU9OX1ZBTFVFX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19FWFRFTlNJT05fTkFNRV9DT01QTEVURQBIUEVfQ0JfTUVTU0FHRV9DT01QTEVURQBIUEVfQ0JfTUVUSE9EX0NPTVBMRVRFAEhQRV9DQl9IRUFERVJfRklFTERfQ09NUExFVEUAREVMRVRFAEhQRV9JTlZBTElEX0VPRl9TVEFURQBJTlZBTElEX1NTTF9DRVJUSUZJQ0FURQBQQVVTRQBOT19SRVNQT05TRQBVTlNVUFBPUlRFRF9NRURJQV9UWVBFAEdPTkUATk9UX0FDQ0VQVEFCTEUAU0VSVklDRV9VTkFWQUlMQUJMRQBSQU5HRV9OT1RfU0FUSVNGSUFCTEUAT1JJR0lOX0lTX1VOUkVBQ0hBQkxFAFJFU1BPTlNFX0lTX1NUQUxFAFBVUkdFAE1FUkdFAFJFUVVFU1RfSEVBREVSX0ZJRUxEU19UT09fTEFSR0UAUkVRVUVTVF9IRUFERVJfVE9PX0xBUkdFAFBBWUxPQURfVE9PX0xBUkdFAElOU1VGRklDSUVOVF9TVE9SQUdFAEhQRV9QQVVTRURfVVBHUkFERQBIUEVfUEFVU0VEX0gyX1VQR1JBREUAU09VUkNFAEFOTk9VTkNFAFRSQUNFAEhQRV9VTkVYUEVDVEVEX1NQQUNFAERFU0NSSUJFAFVOU1VCU0NSSUJFAFJFQ09SRABIUEVfSU5WQUxJRF9NRVRIT0QATk9UX0ZPVU5EAFBST1BGSU5EAFVOQklORABSRUJJTkQAVU5BVVRIT1JJWkVEAE1FVEhPRF9OT1RfQUxMT1dFRABIVFRQX1ZFUlNJT05fTk9UX1NVUFBPUlRFRABBTFJFQURZX1JFUE9SVEVEAEFDQ0VQVEVEAE5PVF9JTVBMRU1FTlRFRABMT09QX0RFVEVDVEVEAEhQRV9DUl9FWFBFQ1RFRABIUEVfTEZfRVhQRUNURUQAQ1JFQVRFRABJTV9VU0VEAEhQRV9QQVVTRUQAVElNRU9VVF9PQ0NVUkVEAFBBWU1FTlRfUkVRVUlSRUQAUFJFQ09ORElUSU9OX1JFUVVJUkVEAFBST1hZX0FVVEhFTlRJQ0FUSU9OX1JFUVVJUkVEAE5FVFdPUktfQVVUSEVOVElDQVRJT05fUkVRVUlSRUQATEVOR1RIX1JFUVVJUkVEAFNTTF9DRVJUSUZJQ0FURV9SRVFVSVJFRABVUEdSQURFX1JFUVVJUkVEAFBBR0VfRVhQSVJFRABQUkVDT05ESVRJT05fRkFJTEVEAEVYUEVDVEFUSU9OX0ZBSUxFRABSRVZBTElEQVRJT05fRkFJTEVEAFNTTF9IQU5EU0hBS0VfRkFJTEVEAExPQ0tFRABUUkFOU0ZPUk1BVElPTl9BUFBMSUVEAE5PVF9NT0RJRklFRABOT1RfRVhURU5ERUQAQkFORFdJRFRIX0xJTUlUX0VYQ0VFREVEAFNJVEVfSVNfT1ZFUkxPQURFRABIRUFEAEV4cGVjdGVkIEhUVFAvAABeEwAAJhMAADAQAADwFwAAnRMAABUSAAA5FwAA8BIAAAoQAAB1EgAArRIAAIITAABPFAAAfxAAAKAVAAAjFAAAiRIAAIsUAABNFQAA1BEAAM8UAAAQGAAAyRYAANwWAADBEQAA4BcAALsUAAB0FAAAfBUAAOUUAAAIFwAAHxAAAGUVAACjFAAAKBUAAAIVAACZFQAALBAAAIsZAABPDwAA1A4AAGoQAADOEAAAAhcAAIkOAABuEwAAHBMAAGYUAABWFwAAwRMAAM0TAABsEwAAaBcAAGYXAABfFwAAIhMAAM4PAABpDgAA2A4AAGMWAADLEwAAqg4AACgXAAAmFwAAxRMAAF0WAADoEQAAZxMAAGUTAADyFgAAcxMAAB0XAAD5FgAA8xEAAM8OAADOFQAADBIAALMRAAClEQAAYRAAADIXAAC7EwAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgMCAgICAgAAAgIAAgIAAgICAgICAgICAgAEAAAAAAACAgICAgICAgICAgICAgICAgICAgICAgICAgAAAAICAgICAgICAgICAgICAgICAgICAgICAgICAgICAAIAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgICAgIAAAICAAICAAICAgICAgICAgIAAwAEAAAAAgICAgICAgICAgICAgICAgICAgICAgICAgIAAAACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgACAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsb3NlZWVwLWFsaXZlAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQFjaHVua2VkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQABAQEBAQAAAQEAAQEAAQEBAQEBAQEBAQAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGVjdGlvbmVudC1sZW5ndGhvbnJveHktY29ubmVjdGlvbgAAAAAAAAAAAAAAAAAAAHJhbnNmZXItZW5jb2RpbmdwZ3JhZGUNCg0KDQpTTQ0KDQpUVFAvQ0UvVFNQLwAAAAAAAAAAAAAAAAECAAEDAAAAAAAAAAAAAAAAAAAAAAAABAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAAAAAAAAABAgABAwAAAAAAAAAAAAAAAAAAAAAAAAQBAQUBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAAAAAAAAQAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAAAAAAAAAABAAACAAAAAAAAAAAAAAAAAAAAAAAAAwQAAAQEBAQEBAQEBAQEBQQEBAQEBAQEBAQEBAAEAAYHBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQABAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAQAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAEAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAgAAAAACAAAAAAAAAAAAAAAAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwAAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE5PVU5DRUVDS09VVE5FQ1RFVEVDUklCRUxVU0hFVEVBRFNFQVJDSFJHRUNUSVZJVFlMRU5EQVJWRU9USUZZUFRJT05TQ0hTRUFZU1RBVENIR0VPUkRJUkVDVE9SVFJDSFBBUkFNRVRFUlVSQ0VCU0NSSUJFQVJET1dOQUNFSU5ETktDS1VCU0NSSUJFSFRUUC9BRFRQLw==' - - -/***/ }), - -/***/ 7728: -/***/ ((__unused_webpack_module, exports) => { - -"use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.enumToMap = void 0; -function enumToMap(obj) { - const res = {}; - Object.keys(obj).forEach((key) => { - const value = obj[key]; - if (typeof value === 'number') { - res[key] = value; - } - }); - return res; -} -exports.enumToMap = enumToMap; -//# sourceMappingURL=utils.js.map - -/***/ }), - -/***/ 8180: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { kClients } = __nccwpck_require__(1439) -const Agent = __nccwpck_require__(8162) -const { - kAgent, - kMockAgentSet, - kMockAgentGet, - kDispatches, - kIsMockActive, - kNetConnect, - kGetNetConnect, - kOptions, - kFactory -} = __nccwpck_require__(5056) -const MockClient = __nccwpck_require__(624) -const MockPool = __nccwpck_require__(3429) -const { matchValue, buildMockOptions } = __nccwpck_require__(2178) -const { InvalidArgumentError, UndiciError } = __nccwpck_require__(5767) -const Dispatcher = __nccwpck_require__(1312) -const Pluralizer = __nccwpck_require__(4615) -const PendingInterceptorsFormatter = __nccwpck_require__(2524) - -class FakeWeakRef { - constructor (value) { - this.value = value - } - - deref () { - return this.value - } -} - -class MockAgent extends Dispatcher { - constructor (opts) { - super(opts) - - this[kNetConnect] = true - this[kIsMockActive] = true - - // Instantiate Agent and encapsulate - if ((opts && opts.agent && typeof opts.agent.dispatch !== 'function')) { - throw new InvalidArgumentError('Argument opts.agent must implement Agent') - } - const agent = opts && opts.agent ? opts.agent : new Agent(opts) - this[kAgent] = agent - - this[kClients] = agent[kClients] - this[kOptions] = buildMockOptions(opts) - } - - get (origin) { - let dispatcher = this[kMockAgentGet](origin) - - if (!dispatcher) { - dispatcher = this[kFactory](origin) - this[kMockAgentSet](origin, dispatcher) - } - return dispatcher - } - - dispatch (opts, handler) { - // Call MockAgent.get to perform additional setup before dispatching as normal - this.get(opts.origin) - return this[kAgent].dispatch(opts, handler) - } - - async close () { - await this[kAgent].close() - this[kClients].clear() - } - - deactivate () { - this[kIsMockActive] = false - } - - activate () { - this[kIsMockActive] = true - } - - enableNetConnect (matcher) { - if (typeof matcher === 'string' || typeof matcher === 'function' || matcher instanceof RegExp) { - if (Array.isArray(this[kNetConnect])) { - this[kNetConnect].push(matcher) - } else { - this[kNetConnect] = [matcher] - } - } else if (typeof matcher === 'undefined') { - this[kNetConnect] = true - } else { - throw new InvalidArgumentError('Unsupported matcher. Must be one of String|Function|RegExp.') - } - } - - disableNetConnect () { - this[kNetConnect] = false - } - - // This is required to bypass issues caused by using global symbols - see: - // https://github.com/nodejs/undici/issues/1447 - get isMockActive () { - return this[kIsMockActive] - } - - [kMockAgentSet] (origin, dispatcher) { - this[kClients].set(origin, new FakeWeakRef(dispatcher)) - } - - [kFactory] (origin) { - const mockOptions = Object.assign({ agent: this }, this[kOptions]) - return this[kOptions] && this[kOptions].connections === 1 - ? new MockClient(origin, mockOptions) - : new MockPool(origin, mockOptions) - } - - [kMockAgentGet] (origin) { - // First check if we can immediately find it - const ref = this[kClients].get(origin) - if (ref) { - return ref.deref() - } - - // If the origin is not a string create a dummy parent pool and return to user - if (typeof origin !== 'string') { - const dispatcher = this[kFactory]('http://localhost:9999') - this[kMockAgentSet](origin, dispatcher) - return dispatcher - } - - // If we match, create a pool and assign the same dispatches - for (const [keyMatcher, nonExplicitRef] of Array.from(this[kClients])) { - const nonExplicitDispatcher = nonExplicitRef.deref() - if (nonExplicitDispatcher && typeof keyMatcher !== 'string' && matchValue(keyMatcher, origin)) { - const dispatcher = this[kFactory](origin) - this[kMockAgentSet](origin, dispatcher) - dispatcher[kDispatches] = nonExplicitDispatcher[kDispatches] - return dispatcher - } - } - } - - [kGetNetConnect] () { - return this[kNetConnect] - } - - pendingInterceptors () { - const mockAgentClients = this[kClients] - - return Array.from(mockAgentClients.entries()) - .flatMap(([origin, scope]) => scope.deref()[kDispatches].map(dispatch => ({ ...dispatch, origin }))) - .filter(({ pending }) => pending) - } - - assertNoPendingInterceptors ({ pendingInterceptorsFormatter = new PendingInterceptorsFormatter() } = {}) { - const pending = this.pendingInterceptors() - - if (pending.length === 0) { - return - } - - const pluralizer = new Pluralizer('interceptor', 'interceptors').pluralize(pending.length) - - throw new UndiciError(` -${pluralizer.count} ${pluralizer.noun} ${pluralizer.is} pending: - -${pendingInterceptorsFormatter.format(pending)} -`.trim()) - } -} - -module.exports = MockAgent - - -/***/ }), - -/***/ 624: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { promisify } = __nccwpck_require__(3837) -const Client = __nccwpck_require__(8224) -const { buildMockDispatch } = __nccwpck_require__(2178) -const { - kDispatches, - kMockAgent, - kClose, - kOriginalClose, - kOrigin, - kOriginalDispatch, - kConnected -} = __nccwpck_require__(5056) -const { MockInterceptor } = __nccwpck_require__(5666) -const Symbols = __nccwpck_require__(1439) -const { InvalidArgumentError } = __nccwpck_require__(5767) - -/** - * MockClient provides an API that extends the Client to influence the mockDispatches. - */ -class MockClient extends Client { - constructor (origin, opts) { - super(origin, opts) - - if (!opts || !opts.agent || typeof opts.agent.dispatch !== 'function') { - throw new InvalidArgumentError('Argument opts.agent must implement Agent') - } - - this[kMockAgent] = opts.agent - this[kOrigin] = origin - this[kDispatches] = [] - this[kConnected] = 1 - this[kOriginalDispatch] = this.dispatch - this[kOriginalClose] = this.close.bind(this) - - this.dispatch = buildMockDispatch.call(this) - this.close = this[kClose] - } - - get [Symbols.kConnected] () { - return this[kConnected] - } - - /** - * Sets up the base interceptor for mocking replies from undici. - */ - intercept (opts) { - return new MockInterceptor(opts, this[kDispatches]) - } - - async [kClose] () { - await promisify(this[kOriginalClose])() - this[kConnected] = 0 - this[kMockAgent][Symbols.kClients].delete(this[kOrigin]) - } -} - -module.exports = MockClient - - -/***/ }), - -/***/ 463: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { UndiciError } = __nccwpck_require__(5767) - -class MockNotMatchedError extends UndiciError { - constructor (message) { - super(message) - Error.captureStackTrace(this, MockNotMatchedError) - this.name = 'MockNotMatchedError' - this.message = message || 'The request does not match any registered mock dispatches' - this.code = 'UND_MOCK_ERR_MOCK_NOT_MATCHED' - } -} - -module.exports = { - MockNotMatchedError -} - - -/***/ }), - -/***/ 5666: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { getResponseData, buildKey, addMockDispatch } = __nccwpck_require__(2178) -const { - kDispatches, - kDispatchKey, - kDefaultHeaders, - kDefaultTrailers, - kContentLength, - kMockDispatch -} = __nccwpck_require__(5056) -const { InvalidArgumentError } = __nccwpck_require__(5767) -const { buildURL } = __nccwpck_require__(6223) - -/** - * Defines the scope API for an interceptor reply - */ -class MockScope { - constructor (mockDispatch) { - this[kMockDispatch] = mockDispatch - } - - /** - * Delay a reply by a set amount in ms. - */ - delay (waitInMs) { - if (typeof waitInMs !== 'number' || !Number.isInteger(waitInMs) || waitInMs <= 0) { - throw new InvalidArgumentError('waitInMs must be a valid integer > 0') - } - - this[kMockDispatch].delay = waitInMs - return this - } - - /** - * For a defined reply, never mark as consumed. - */ - persist () { - this[kMockDispatch].persist = true - return this - } - - /** - * Allow one to define a reply for a set amount of matching requests. - */ - times (repeatTimes) { - if (typeof repeatTimes !== 'number' || !Number.isInteger(repeatTimes) || repeatTimes <= 0) { - throw new InvalidArgumentError('repeatTimes must be a valid integer > 0') - } - - this[kMockDispatch].times = repeatTimes - return this - } -} - -/** - * Defines an interceptor for a Mock - */ -class MockInterceptor { - constructor (opts, mockDispatches) { - if (typeof opts !== 'object') { - throw new InvalidArgumentError('opts must be an object') - } - if (typeof opts.path === 'undefined') { - throw new InvalidArgumentError('opts.path must be defined') - } - if (typeof opts.method === 'undefined') { - opts.method = 'GET' - } - // See https://github.com/nodejs/undici/issues/1245 - // As per RFC 3986, clients are not supposed to send URI - // fragments to servers when they retrieve a document, - if (typeof opts.path === 'string') { - if (opts.query) { - opts.path = buildURL(opts.path, opts.query) - } else { - // Matches https://github.com/nodejs/undici/blob/main/lib/fetch/index.js#L1811 - const parsedURL = new URL(opts.path, 'data://') - opts.path = parsedURL.pathname + parsedURL.search - } - } - if (typeof opts.method === 'string') { - opts.method = opts.method.toUpperCase() - } - - this[kDispatchKey] = buildKey(opts) - this[kDispatches] = mockDispatches - this[kDefaultHeaders] = {} - this[kDefaultTrailers] = {} - this[kContentLength] = false - } - - createMockScopeDispatchData (statusCode, data, responseOptions = {}) { - const responseData = getResponseData(data) - const contentLength = this[kContentLength] ? { 'content-length': responseData.length } : {} - const headers = { ...this[kDefaultHeaders], ...contentLength, ...responseOptions.headers } - const trailers = { ...this[kDefaultTrailers], ...responseOptions.trailers } - - return { statusCode, data, headers, trailers } - } - - validateReplyParameters (statusCode, data, responseOptions) { - if (typeof statusCode === 'undefined') { - throw new InvalidArgumentError('statusCode must be defined') - } - if (typeof data === 'undefined') { - throw new InvalidArgumentError('data must be defined') - } - if (typeof responseOptions !== 'object') { - throw new InvalidArgumentError('responseOptions must be an object') - } - } - - /** - * Mock an undici request with a defined reply. - */ - reply (replyData) { - // Values of reply aren't available right now as they - // can only be available when the reply callback is invoked. - if (typeof replyData === 'function') { - // We'll first wrap the provided callback in another function, - // this function will properly resolve the data from the callback - // when invoked. - const wrappedDefaultsCallback = (opts) => { - // Our reply options callback contains the parameter for statusCode, data and options. - const resolvedData = replyData(opts) - - // Check if it is in the right format - if (typeof resolvedData !== 'object') { - throw new InvalidArgumentError('reply options callback must return an object') - } - - const { statusCode, data = '', responseOptions = {} } = resolvedData - this.validateReplyParameters(statusCode, data, responseOptions) - // Since the values can be obtained immediately we return them - // from this higher order function that will be resolved later. - return { - ...this.createMockScopeDispatchData(statusCode, data, responseOptions) - } - } - - // Add usual dispatch data, but this time set the data parameter to function that will eventually provide data. - const newMockDispatch = addMockDispatch(this[kDispatches], this[kDispatchKey], wrappedDefaultsCallback) - return new MockScope(newMockDispatch) - } - - // We can have either one or three parameters, if we get here, - // we should have 1-3 parameters. So we spread the arguments of - // this function to obtain the parameters, since replyData will always - // just be the statusCode. - const [statusCode, data = '', responseOptions = {}] = [...arguments] - this.validateReplyParameters(statusCode, data, responseOptions) - - // Send in-already provided data like usual - const dispatchData = this.createMockScopeDispatchData(statusCode, data, responseOptions) - const newMockDispatch = addMockDispatch(this[kDispatches], this[kDispatchKey], dispatchData) - return new MockScope(newMockDispatch) - } - - /** - * Mock an undici request with a defined error. - */ - replyWithError (error) { - if (typeof error === 'undefined') { - throw new InvalidArgumentError('error must be defined') - } - - const newMockDispatch = addMockDispatch(this[kDispatches], this[kDispatchKey], { error }) - return new MockScope(newMockDispatch) - } - - /** - * Set default reply headers on the interceptor for subsequent replies - */ - defaultReplyHeaders (headers) { - if (typeof headers === 'undefined') { - throw new InvalidArgumentError('headers must be defined') - } - - this[kDefaultHeaders] = headers - return this - } - - /** - * Set default reply trailers on the interceptor for subsequent replies - */ - defaultReplyTrailers (trailers) { - if (typeof trailers === 'undefined') { - throw new InvalidArgumentError('trailers must be defined') - } - - this[kDefaultTrailers] = trailers - return this - } - - /** - * Set reply content length header for replies on the interceptor - */ - replyContentLength () { - this[kContentLength] = true - return this - } -} - -module.exports.MockInterceptor = MockInterceptor -module.exports.MockScope = MockScope - - -/***/ }), - -/***/ 3429: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { promisify } = __nccwpck_require__(3837) -const Pool = __nccwpck_require__(9729) -const { buildMockDispatch } = __nccwpck_require__(2178) -const { - kDispatches, - kMockAgent, - kClose, - kOriginalClose, - kOrigin, - kOriginalDispatch, - kConnected -} = __nccwpck_require__(5056) -const { MockInterceptor } = __nccwpck_require__(5666) -const Symbols = __nccwpck_require__(1439) -const { InvalidArgumentError } = __nccwpck_require__(5767) - -/** - * MockPool provides an API that extends the Pool to influence the mockDispatches. - */ -class MockPool extends Pool { - constructor (origin, opts) { - super(origin, opts) - - if (!opts || !opts.agent || typeof opts.agent.dispatch !== 'function') { - throw new InvalidArgumentError('Argument opts.agent must implement Agent') - } - - this[kMockAgent] = opts.agent - this[kOrigin] = origin - this[kDispatches] = [] - this[kConnected] = 1 - this[kOriginalDispatch] = this.dispatch - this[kOriginalClose] = this.close.bind(this) - - this.dispatch = buildMockDispatch.call(this) - this.close = this[kClose] - } - - get [Symbols.kConnected] () { - return this[kConnected] - } - - /** - * Sets up the base interceptor for mocking replies from undici. - */ - intercept (opts) { - return new MockInterceptor(opts, this[kDispatches]) - } - - async [kClose] () { - await promisify(this[kOriginalClose])() - this[kConnected] = 0 - this[kMockAgent][Symbols.kClients].delete(this[kOrigin]) - } -} - -module.exports = MockPool - - -/***/ }), - -/***/ 5056: -/***/ ((module) => { - -"use strict"; - - -module.exports = { - kAgent: Symbol('agent'), - kOptions: Symbol('options'), - kFactory: Symbol('factory'), - kDispatches: Symbol('dispatches'), - kDispatchKey: Symbol('dispatch key'), - kDefaultHeaders: Symbol('default headers'), - kDefaultTrailers: Symbol('default trailers'), - kContentLength: Symbol('content length'), - kMockAgent: Symbol('mock agent'), - kMockAgentSet: Symbol('mock agent set'), - kMockAgentGet: Symbol('mock agent get'), - kMockDispatch: Symbol('mock dispatch'), - kClose: Symbol('close'), - kOriginalClose: Symbol('original agent close'), - kOrigin: Symbol('origin'), - kIsMockActive: Symbol('is mock active'), - kNetConnect: Symbol('net connect'), - kGetNetConnect: Symbol('get net connect'), - kConnected: Symbol('connected') -} - - -/***/ }), - -/***/ 2178: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { MockNotMatchedError } = __nccwpck_require__(463) -const { - kDispatches, - kMockAgent, - kOriginalDispatch, - kOrigin, - kGetNetConnect -} = __nccwpck_require__(5056) -const { buildURL, nop } = __nccwpck_require__(6223) -const { STATUS_CODES } = __nccwpck_require__(3685) -const { - types: { - isPromise - } -} = __nccwpck_require__(3837) - -function matchValue (match, value) { - if (typeof match === 'string') { - return match === value - } - if (match instanceof RegExp) { - return match.test(value) - } - if (typeof match === 'function') { - return match(value) === true - } - return false -} - -function lowerCaseEntries (headers) { - return Object.fromEntries( - Object.entries(headers).map(([headerName, headerValue]) => { - return [headerName.toLocaleLowerCase(), headerValue] - }) - ) -} - -/** - * @param {import('../../index').Headers|string[]|Record<string, string>} headers - * @param {string} key - */ -function getHeaderByName (headers, key) { - if (Array.isArray(headers)) { - for (let i = 0; i < headers.length; i += 2) { - if (headers[i].toLocaleLowerCase() === key.toLocaleLowerCase()) { - return headers[i + 1] - } - } - - return undefined - } else if (typeof headers.get === 'function') { - return headers.get(key) - } else { - return lowerCaseEntries(headers)[key.toLocaleLowerCase()] - } -} - -/** @param {string[]} headers */ -function buildHeadersFromArray (headers) { // fetch HeadersList - const clone = headers.slice() - const entries = [] - for (let index = 0; index < clone.length; index += 2) { - entries.push([clone[index], clone[index + 1]]) - } - return Object.fromEntries(entries) -} - -function matchHeaders (mockDispatch, headers) { - if (typeof mockDispatch.headers === 'function') { - if (Array.isArray(headers)) { // fetch HeadersList - headers = buildHeadersFromArray(headers) - } - return mockDispatch.headers(headers ? lowerCaseEntries(headers) : {}) - } - if (typeof mockDispatch.headers === 'undefined') { - return true - } - if (typeof headers !== 'object' || typeof mockDispatch.headers !== 'object') { - return false - } - - for (const [matchHeaderName, matchHeaderValue] of Object.entries(mockDispatch.headers)) { - const headerValue = getHeaderByName(headers, matchHeaderName) - - if (!matchValue(matchHeaderValue, headerValue)) { - return false - } - } - return true -} - -function safeUrl (path) { - if (typeof path !== 'string') { - return path - } - - const pathSegments = path.split('?') - - if (pathSegments.length !== 2) { - return path - } - - const qp = new URLSearchParams(pathSegments.pop()) - qp.sort() - return [...pathSegments, qp.toString()].join('?') -} - -function matchKey (mockDispatch, { path, method, body, headers }) { - const pathMatch = matchValue(mockDispatch.path, path) - const methodMatch = matchValue(mockDispatch.method, method) - const bodyMatch = typeof mockDispatch.body !== 'undefined' ? matchValue(mockDispatch.body, body) : true - const headersMatch = matchHeaders(mockDispatch, headers) - return pathMatch && methodMatch && bodyMatch && headersMatch -} - -function getResponseData (data) { - if (Buffer.isBuffer(data)) { - return data - } else if (typeof data === 'object') { - return JSON.stringify(data) - } else { - return data.toString() - } -} - -function getMockDispatch (mockDispatches, key) { - const basePath = key.query ? buildURL(key.path, key.query) : key.path - const resolvedPath = typeof basePath === 'string' ? safeUrl(basePath) : basePath - - // Match path - let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path }) => matchValue(safeUrl(path), resolvedPath)) - if (matchedMockDispatches.length === 0) { - throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`) - } - - // Match method - matchedMockDispatches = matchedMockDispatches.filter(({ method }) => matchValue(method, key.method)) - if (matchedMockDispatches.length === 0) { - throw new MockNotMatchedError(`Mock dispatch not matched for method '${key.method}'`) - } - - // Match body - matchedMockDispatches = matchedMockDispatches.filter(({ body }) => typeof body !== 'undefined' ? matchValue(body, key.body) : true) - if (matchedMockDispatches.length === 0) { - throw new MockNotMatchedError(`Mock dispatch not matched for body '${key.body}'`) - } - - // Match headers - matchedMockDispatches = matchedMockDispatches.filter((mockDispatch) => matchHeaders(mockDispatch, key.headers)) - if (matchedMockDispatches.length === 0) { - throw new MockNotMatchedError(`Mock dispatch not matched for headers '${typeof key.headers === 'object' ? JSON.stringify(key.headers) : key.headers}'`) - } - - return matchedMockDispatches[0] -} - -function addMockDispatch (mockDispatches, key, data) { - const baseData = { timesInvoked: 0, times: 1, persist: false, consumed: false } - const replyData = typeof data === 'function' ? { callback: data } : { ...data } - const newMockDispatch = { ...baseData, ...key, pending: true, data: { error: null, ...replyData } } - mockDispatches.push(newMockDispatch) - return newMockDispatch -} - -function deleteMockDispatch (mockDispatches, key) { - const index = mockDispatches.findIndex(dispatch => { - if (!dispatch.consumed) { - return false - } - return matchKey(dispatch, key) - }) - if (index !== -1) { - mockDispatches.splice(index, 1) - } -} - -function buildKey (opts) { - const { path, method, body, headers, query } = opts - return { - path, - method, - body, - headers, - query - } -} - -function generateKeyValues (data) { - return Object.entries(data).reduce((keyValuePairs, [key, value]) => [ - ...keyValuePairs, - Buffer.from(`${key}`), - Array.isArray(value) ? value.map(x => Buffer.from(`${x}`)) : Buffer.from(`${value}`) - ], []) -} - -/** - * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Status - * @param {number} statusCode - */ -function getStatusText (statusCode) { - return STATUS_CODES[statusCode] || 'unknown' -} - -async function getResponse (body) { - const buffers = [] - for await (const data of body) { - buffers.push(data) - } - return Buffer.concat(buffers).toString('utf8') -} - -/** - * Mock dispatch function used to simulate undici dispatches - */ -function mockDispatch (opts, handler) { - // Get mock dispatch from built key - const key = buildKey(opts) - const mockDispatch = getMockDispatch(this[kDispatches], key) - - mockDispatch.timesInvoked++ - - // Here's where we resolve a callback if a callback is present for the dispatch data. - if (mockDispatch.data.callback) { - mockDispatch.data = { ...mockDispatch.data, ...mockDispatch.data.callback(opts) } - } - - // Parse mockDispatch data - const { data: { statusCode, data, headers, trailers, error }, delay, persist } = mockDispatch - const { timesInvoked, times } = mockDispatch - - // If it's used up and not persistent, mark as consumed - mockDispatch.consumed = !persist && timesInvoked >= times - mockDispatch.pending = timesInvoked < times - - // If specified, trigger dispatch error - if (error !== null) { - deleteMockDispatch(this[kDispatches], key) - handler.onError(error) - return true - } - - // Handle the request with a delay if necessary - if (typeof delay === 'number' && delay > 0) { - setTimeout(() => { - handleReply(this[kDispatches]) - }, delay) - } else { - handleReply(this[kDispatches]) - } - - function handleReply (mockDispatches, _data = data) { - // fetch's HeadersList is a 1D string array - const optsHeaders = Array.isArray(opts.headers) - ? buildHeadersFromArray(opts.headers) - : opts.headers - const body = typeof _data === 'function' - ? _data({ ...opts, headers: optsHeaders }) - : _data - - // util.types.isPromise is likely needed for jest. - if (isPromise(body)) { - // If handleReply is asynchronous, throwing an error - // in the callback will reject the promise, rather than - // synchronously throw the error, which breaks some tests. - // Rather, we wait for the callback to resolve if it is a - // promise, and then re-run handleReply with the new body. - body.then((newData) => handleReply(mockDispatches, newData)) - return - } - - const responseData = getResponseData(body) - const responseHeaders = generateKeyValues(headers) - const responseTrailers = generateKeyValues(trailers) - - handler.abort = nop - handler.onHeaders(statusCode, responseHeaders, resume, getStatusText(statusCode)) - handler.onData(Buffer.from(responseData)) - handler.onComplete(responseTrailers) - deleteMockDispatch(mockDispatches, key) - } - - function resume () {} - - return true -} - -function buildMockDispatch () { - const agent = this[kMockAgent] - const origin = this[kOrigin] - const originalDispatch = this[kOriginalDispatch] - - return function dispatch (opts, handler) { - if (agent.isMockActive) { - try { - mockDispatch.call(this, opts, handler) - } catch (error) { - if (error instanceof MockNotMatchedError) { - const netConnect = agent[kGetNetConnect]() - if (netConnect === false) { - throw new MockNotMatchedError(`${error.message}: subsequent request to origin ${origin} was not allowed (net.connect disabled)`) - } - if (checkNetConnect(netConnect, origin)) { - originalDispatch.call(this, opts, handler) - } else { - throw new MockNotMatchedError(`${error.message}: subsequent request to origin ${origin} was not allowed (net.connect is not enabled for this origin)`) - } - } else { - throw error - } - } - } else { - originalDispatch.call(this, opts, handler) - } - } -} - -function checkNetConnect (netConnect, origin) { - const url = new URL(origin) - if (netConnect === true) { - return true - } else if (Array.isArray(netConnect) && netConnect.some((matcher) => matchValue(matcher, url.host))) { - return true - } - return false -} - -function buildMockOptions (opts) { - if (opts) { - const { agent, ...mockOptions } = opts - return mockOptions - } -} - -module.exports = { - getResponseData, - getMockDispatch, - addMockDispatch, - deleteMockDispatch, - buildKey, - generateKeyValues, - matchValue, - getResponse, - getStatusText, - mockDispatch, - buildMockDispatch, - checkNetConnect, - buildMockOptions, - getHeaderByName -} - - -/***/ }), - -/***/ 2524: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { Transform } = __nccwpck_require__(2781) -const { Console } = __nccwpck_require__(6206) - -/** - * Gets the output of `console.table(…)` as a string. - */ -module.exports = class PendingInterceptorsFormatter { - constructor ({ disableColors } = {}) { - this.transform = new Transform({ - transform (chunk, _enc, cb) { - cb(null, chunk) - } - }) - - this.logger = new Console({ - stdout: this.transform, - inspectOptions: { - colors: !disableColors && !process.env.CI - } - }) - } - - format (pendingInterceptors) { - const withPrettyHeaders = pendingInterceptors.map( - ({ method, path, data: { statusCode }, persist, times, timesInvoked, origin }) => ({ - Method: method, - Origin: origin, - Path: path, - 'Status code': statusCode, - Persistent: persist ? '✅' : '❌', - Invocations: timesInvoked, - Remaining: persist ? Infinity : times - timesInvoked - })) - - this.logger.table(withPrettyHeaders) - return this.transform.read().toString() - } -} - - -/***/ }), - -/***/ 4615: -/***/ ((module) => { - -"use strict"; - - -const singulars = { - pronoun: 'it', - is: 'is', - was: 'was', - this: 'this' -} - -const plurals = { - pronoun: 'they', - is: 'are', - was: 'were', - this: 'these' -} - -module.exports = class Pluralizer { - constructor (singular, plural) { - this.singular = singular - this.plural = plural - } - - pluralize (count) { - const one = count === 1 - const keys = one ? singulars : plurals - const noun = one ? this.singular : this.plural - return { ...keys, count, noun } - } -} - - -/***/ }), - -/***/ 3408: -/***/ ((module) => { - -"use strict"; -/* eslint-disable */ - - - -// Extracted from node/lib/internal/fixed_queue.js - -// Currently optimal queue size, tested on V8 6.0 - 6.6. Must be power of two. -const kSize = 2048; -const kMask = kSize - 1; - -// The FixedQueue is implemented as a singly-linked list of fixed-size -// circular buffers. It looks something like this: -// -// head tail -// | | -// v v -// +-----------+ <-----\ +-----------+ <------\ +-----------+ -// | [null] | \----- | next | \------- | next | -// +-----------+ +-----------+ +-----------+ -// | item | <-- bottom | item | <-- bottom | [empty] | -// | item | | item | | [empty] | -// | item | | item | | [empty] | -// | item | | item | | [empty] | -// | item | | item | bottom --> | item | -// | item | | item | | item | -// | ... | | ... | | ... | -// | item | | item | | item | -// | item | | item | | item | -// | [empty] | <-- top | item | | item | -// | [empty] | | item | | item | -// | [empty] | | [empty] | <-- top top --> | [empty] | -// +-----------+ +-----------+ +-----------+ -// -// Or, if there is only one circular buffer, it looks something -// like either of these: -// -// head tail head tail -// | | | | -// v v v v -// +-----------+ +-----------+ -// | [null] | | [null] | -// +-----------+ +-----------+ -// | [empty] | | item | -// | [empty] | | item | -// | item | <-- bottom top --> | [empty] | -// | item | | [empty] | -// | [empty] | <-- top bottom --> | item | -// | [empty] | | item | -// +-----------+ +-----------+ -// -// Adding a value means moving `top` forward by one, removing means -// moving `bottom` forward by one. After reaching the end, the queue -// wraps around. -// -// When `top === bottom` the current queue is empty and when -// `top + 1 === bottom` it's full. This wastes a single space of storage -// but allows much quicker checks. - -class FixedCircularBuffer { - constructor() { - this.bottom = 0; - this.top = 0; - this.list = new Array(kSize); - this.next = null; - } - - isEmpty() { - return this.top === this.bottom; - } - - isFull() { - return ((this.top + 1) & kMask) === this.bottom; - } - - push(data) { - this.list[this.top] = data; - this.top = (this.top + 1) & kMask; - } - - shift() { - const nextItem = this.list[this.bottom]; - if (nextItem === undefined) - return null; - this.list[this.bottom] = undefined; - this.bottom = (this.bottom + 1) & kMask; - return nextItem; - } -} - -module.exports = class FixedQueue { - constructor() { - this.head = this.tail = new FixedCircularBuffer(); - } - - isEmpty() { - return this.head.isEmpty(); - } - - push(data) { - if (this.head.isFull()) { - // Head is full: Creates a new queue, sets the old queue's `.next` to it, - // and sets it as the new main queue. - this.head = this.head.next = new FixedCircularBuffer(); - } - this.head.push(data); - } - - shift() { - const tail = this.tail; - const next = tail.shift(); - if (tail.isEmpty() && tail.next !== null) { - // If there is another queue, it forms the new tail. - this.tail = tail.next; - } - return next; - } -}; - - -/***/ }), - -/***/ 1273: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const DispatcherBase = __nccwpck_require__(8188) -const FixedQueue = __nccwpck_require__(3408) -const { kConnected, kSize, kRunning, kPending, kQueued, kBusy, kFree, kUrl, kClose, kDestroy, kDispatch } = __nccwpck_require__(1439) -const PoolStats = __nccwpck_require__(3860) - -const kClients = Symbol('clients') -const kNeedDrain = Symbol('needDrain') -const kQueue = Symbol('queue') -const kClosedResolve = Symbol('closed resolve') -const kOnDrain = Symbol('onDrain') -const kOnConnect = Symbol('onConnect') -const kOnDisconnect = Symbol('onDisconnect') -const kOnConnectionError = Symbol('onConnectionError') -const kGetDispatcher = Symbol('get dispatcher') -const kAddClient = Symbol('add client') -const kRemoveClient = Symbol('remove client') -const kStats = Symbol('stats') - -class PoolBase extends DispatcherBase { - constructor () { - super() - - this[kQueue] = new FixedQueue() - this[kClients] = [] - this[kQueued] = 0 - - const pool = this - - this[kOnDrain] = function onDrain (origin, targets) { - const queue = pool[kQueue] - - let needDrain = false - - while (!needDrain) { - const item = queue.shift() - if (!item) { - break - } - pool[kQueued]-- - needDrain = !this.dispatch(item.opts, item.handler) - } - - this[kNeedDrain] = needDrain - - if (!this[kNeedDrain] && pool[kNeedDrain]) { - pool[kNeedDrain] = false - pool.emit('drain', origin, [pool, ...targets]) - } - - if (pool[kClosedResolve] && queue.isEmpty()) { - Promise - .all(pool[kClients].map(c => c.close())) - .then(pool[kClosedResolve]) - } - } - - this[kOnConnect] = (origin, targets) => { - pool.emit('connect', origin, [pool, ...targets]) - } - - this[kOnDisconnect] = (origin, targets, err) => { - pool.emit('disconnect', origin, [pool, ...targets], err) - } - - this[kOnConnectionError] = (origin, targets, err) => { - pool.emit('connectionError', origin, [pool, ...targets], err) - } - - this[kStats] = new PoolStats(this) - } - - get [kBusy] () { - return this[kNeedDrain] - } - - get [kConnected] () { - return this[kClients].filter(client => client[kConnected]).length - } - - get [kFree] () { - return this[kClients].filter(client => client[kConnected] && !client[kNeedDrain]).length - } - - get [kPending] () { - let ret = this[kQueued] - for (const { [kPending]: pending } of this[kClients]) { - ret += pending - } - return ret - } - - get [kRunning] () { - let ret = 0 - for (const { [kRunning]: running } of this[kClients]) { - ret += running - } - return ret - } - - get [kSize] () { - let ret = this[kQueued] - for (const { [kSize]: size } of this[kClients]) { - ret += size - } - return ret - } - - get stats () { - return this[kStats] - } - - async [kClose] () { - if (this[kQueue].isEmpty()) { - return Promise.all(this[kClients].map(c => c.close())) - } else { - return new Promise((resolve) => { - this[kClosedResolve] = resolve - }) - } - } - - async [kDestroy] (err) { - while (true) { - const item = this[kQueue].shift() - if (!item) { - break - } - item.handler.onError(err) - } - - return Promise.all(this[kClients].map(c => c.destroy(err))) - } - - [kDispatch] (opts, handler) { - const dispatcher = this[kGetDispatcher]() - - if (!dispatcher) { - this[kNeedDrain] = true - this[kQueue].push({ opts, handler }) - this[kQueued]++ - } else if (!dispatcher.dispatch(opts, handler)) { - dispatcher[kNeedDrain] = true - this[kNeedDrain] = !this[kGetDispatcher]() - } - - return !this[kNeedDrain] - } - - [kAddClient] (client) { - client - .on('drain', this[kOnDrain]) - .on('connect', this[kOnConnect]) - .on('disconnect', this[kOnDisconnect]) - .on('connectionError', this[kOnConnectionError]) - - this[kClients].push(client) - - if (this[kNeedDrain]) { - process.nextTick(() => { - if (this[kNeedDrain]) { - this[kOnDrain](client[kUrl], [this, client]) - } - }) - } - - return this - } - - [kRemoveClient] (client) { - client.close(() => { - const idx = this[kClients].indexOf(client) - if (idx !== -1) { - this[kClients].splice(idx, 1) - } - }) - - this[kNeedDrain] = this[kClients].some(dispatcher => ( - !dispatcher[kNeedDrain] && - dispatcher.closed !== true && - dispatcher.destroyed !== true - )) - } -} - -module.exports = { - PoolBase, - kClients, - kNeedDrain, - kAddClient, - kRemoveClient, - kGetDispatcher -} - - -/***/ }), - -/***/ 3860: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -const { kFree, kConnected, kPending, kQueued, kRunning, kSize } = __nccwpck_require__(1439) -const kPool = Symbol('pool') - -class PoolStats { - constructor (pool) { - this[kPool] = pool - } - - get connected () { - return this[kPool][kConnected] - } - - get free () { - return this[kPool][kFree] - } - - get pending () { - return this[kPool][kPending] - } - - get queued () { - return this[kPool][kQueued] - } - - get running () { - return this[kPool][kRunning] - } - - get size () { - return this[kPool][kSize] - } -} - -module.exports = PoolStats - - -/***/ }), - -/***/ 9729: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { - PoolBase, - kClients, - kNeedDrain, - kAddClient, - kGetDispatcher -} = __nccwpck_require__(1273) -const Client = __nccwpck_require__(8224) -const { - InvalidArgumentError -} = __nccwpck_require__(5767) -const util = __nccwpck_require__(6223) -const { kUrl, kInterceptors } = __nccwpck_require__(1439) -const buildConnector = __nccwpck_require__(3311) - -const kOptions = Symbol('options') -const kConnections = Symbol('connections') -const kFactory = Symbol('factory') - -function defaultFactory (origin, opts) { - return new Client(origin, opts) -} - -class Pool extends PoolBase { - constructor (origin, { - connections, - factory = defaultFactory, - connect, - connectTimeout, - tls, - maxCachedSessions, - socketPath, - autoSelectFamily, - autoSelectFamilyAttemptTimeout, - allowH2, - ...options - } = {}) { - super() - - if (connections != null && (!Number.isFinite(connections) || connections < 0)) { - throw new InvalidArgumentError('invalid connections') - } - - if (typeof factory !== 'function') { - throw new InvalidArgumentError('factory must be a function.') - } - - if (connect != null && typeof connect !== 'function' && typeof connect !== 'object') { - throw new InvalidArgumentError('connect must be a function or an object') - } - - if (typeof connect !== 'function') { - connect = buildConnector({ - ...tls, - maxCachedSessions, - allowH2, - socketPath, - timeout: connectTimeout, - ...(util.nodeHasAutoSelectFamily && autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined), - ...connect - }) - } - - this[kInterceptors] = options.interceptors && options.interceptors.Pool && Array.isArray(options.interceptors.Pool) - ? options.interceptors.Pool - : [] - this[kConnections] = connections || null - this[kUrl] = util.parseOrigin(origin) - this[kOptions] = { ...util.deepClone(options), connect, allowH2 } - this[kOptions].interceptors = options.interceptors - ? { ...options.interceptors } - : undefined - this[kFactory] = factory - } - - [kGetDispatcher] () { - let dispatcher = this[kClients].find(dispatcher => !dispatcher[kNeedDrain]) - - if (dispatcher) { - return dispatcher - } - - if (!this[kConnections] || this[kClients].length < this[kConnections]) { - dispatcher = this[kFactory](this[kUrl], this[kOptions]) - this[kAddClient](dispatcher) - } - - return dispatcher - } -} - -module.exports = Pool - - -/***/ }), - -/***/ 2498: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { kProxy, kClose, kDestroy, kInterceptors } = __nccwpck_require__(1439) -const { URL } = __nccwpck_require__(7310) -const Agent = __nccwpck_require__(8162) -const Pool = __nccwpck_require__(9729) -const DispatcherBase = __nccwpck_require__(8188) -const { InvalidArgumentError, RequestAbortedError } = __nccwpck_require__(5767) -const buildConnector = __nccwpck_require__(3311) - -const kAgent = Symbol('proxy agent') -const kClient = Symbol('proxy client') -const kProxyHeaders = Symbol('proxy headers') -const kRequestTls = Symbol('request tls settings') -const kProxyTls = Symbol('proxy tls settings') -const kConnectEndpoint = Symbol('connect endpoint function') - -function defaultProtocolPort (protocol) { - return protocol === 'https:' ? 443 : 80 -} - -function buildProxyOptions (opts) { - if (typeof opts === 'string') { - opts = { uri: opts } - } - - if (!opts || !opts.uri) { - throw new InvalidArgumentError('Proxy opts.uri is mandatory') - } - - return { - uri: opts.uri, - protocol: opts.protocol || 'https' - } -} - -function defaultFactory (origin, opts) { - return new Pool(origin, opts) -} - -class ProxyAgent extends DispatcherBase { - constructor (opts) { - super(opts) - this[kProxy] = buildProxyOptions(opts) - this[kAgent] = new Agent(opts) - this[kInterceptors] = opts.interceptors && opts.interceptors.ProxyAgent && Array.isArray(opts.interceptors.ProxyAgent) - ? opts.interceptors.ProxyAgent - : [] - - if (typeof opts === 'string') { - opts = { uri: opts } - } - - if (!opts || !opts.uri) { - throw new InvalidArgumentError('Proxy opts.uri is mandatory') - } - - const { clientFactory = defaultFactory } = opts - - if (typeof clientFactory !== 'function') { - throw new InvalidArgumentError('Proxy opts.clientFactory must be a function.') - } - - this[kRequestTls] = opts.requestTls - this[kProxyTls] = opts.proxyTls - this[kProxyHeaders] = opts.headers || {} - - if (opts.auth && opts.token) { - throw new InvalidArgumentError('opts.auth cannot be used in combination with opts.token') - } else if (opts.auth) { - /* @deprecated in favour of opts.token */ - this[kProxyHeaders]['proxy-authorization'] = `Basic ${opts.auth}` - } else if (opts.token) { - this[kProxyHeaders]['proxy-authorization'] = opts.token - } - - const resolvedUrl = new URL(opts.uri) - const { origin, port, host } = resolvedUrl - - const connect = buildConnector({ ...opts.proxyTls }) - this[kConnectEndpoint] = buildConnector({ ...opts.requestTls }) - this[kClient] = clientFactory(resolvedUrl, { connect }) - this[kAgent] = new Agent({ - ...opts, - connect: async (opts, callback) => { - let requestedHost = opts.host - if (!opts.port) { - requestedHost += `:${defaultProtocolPort(opts.protocol)}` - } - try { - const { socket, statusCode } = await this[kClient].connect({ - origin, - port, - path: requestedHost, - signal: opts.signal, - headers: { - ...this[kProxyHeaders], - host - } - }) - if (statusCode !== 200) { - socket.on('error', () => {}).destroy() - callback(new RequestAbortedError('Proxy response !== 200 when HTTP Tunneling')) - } - if (opts.protocol !== 'https:') { - callback(null, socket) - return - } - let servername - if (this[kRequestTls]) { - servername = this[kRequestTls].servername - } else { - servername = opts.servername - } - this[kConnectEndpoint]({ ...opts, servername, httpSocket: socket }, callback) - } catch (err) { - callback(err) - } - } - }) - } - - dispatch (opts, handler) { - const { host } = new URL(opts.origin) - const headers = buildHeaders(opts.headers) - throwIfProxyAuthIsSent(headers) - return this[kAgent].dispatch( - { - ...opts, - headers: { - ...headers, - host - } - }, - handler - ) - } - - async [kClose] () { - await this[kAgent].close() - await this[kClient].close() - } - - async [kDestroy] () { - await this[kAgent].destroy() - await this[kClient].destroy() - } -} - -/** - * @param {string[] | Record<string, string>} headers - * @returns {Record<string, string>} - */ -function buildHeaders (headers) { - // When using undici.fetch, the headers list is stored - // as an array. - if (Array.isArray(headers)) { - /** @type {Record<string, string>} */ - const headersPair = {} - - for (let i = 0; i < headers.length; i += 2) { - headersPair[headers[i]] = headers[i + 1] - } - - return headersPair - } - - return headers -} - -/** - * @param {Record<string, string>} headers - * - * Previous versions of ProxyAgent suggests the Proxy-Authorization in request headers - * Nevertheless, it was changed and to avoid a security vulnerability by end users - * this check was created. - * It should be removed in the next major version for performance reasons - */ -function throwIfProxyAuthIsSent (headers) { - const existProxyAuth = headers && Object.keys(headers) - .find((key) => key.toLowerCase() === 'proxy-authorization') - if (existProxyAuth) { - throw new InvalidArgumentError('Proxy-Authorization should be sent in ProxyAgent constructor') - } -} - -module.exports = ProxyAgent - - -/***/ }), - -/***/ 8581: -/***/ ((module) => { - -"use strict"; - - -let fastNow = Date.now() -let fastNowTimeout - -const fastTimers = [] - -function onTimeout () { - fastNow = Date.now() - - let len = fastTimers.length - let idx = 0 - while (idx < len) { - const timer = fastTimers[idx] - - if (timer.state === 0) { - timer.state = fastNow + timer.delay - } else if (timer.state > 0 && fastNow >= timer.state) { - timer.state = -1 - timer.callback(timer.opaque) - } - - if (timer.state === -1) { - timer.state = -2 - if (idx !== len - 1) { - fastTimers[idx] = fastTimers.pop() - } else { - fastTimers.pop() - } - len -= 1 - } else { - idx += 1 - } - } - - if (fastTimers.length > 0) { - refreshTimeout() - } -} - -function refreshTimeout () { - if (fastNowTimeout && fastNowTimeout.refresh) { - fastNowTimeout.refresh() - } else { - clearTimeout(fastNowTimeout) - fastNowTimeout = setTimeout(onTimeout, 1e3) - if (fastNowTimeout.unref) { - fastNowTimeout.unref() - } - } -} - -class Timeout { - constructor (callback, delay, opaque) { - this.callback = callback - this.delay = delay - this.opaque = opaque - - // -2 not in timer list - // -1 in timer list but inactive - // 0 in timer list waiting for time - // > 0 in timer list waiting for time to expire - this.state = -2 - - this.refresh() - } - - refresh () { - if (this.state === -2) { - fastTimers.push(this) - if (!fastNowTimeout || fastTimers.length === 1) { - refreshTimeout() - } - } - - this.state = 0 - } - - clear () { - this.state = -1 - } -} - -module.exports = { - setTimeout (callback, delay, opaque) { - return delay < 1e3 - ? setTimeout(callback, delay, opaque) - : new Timeout(callback, delay, opaque) - }, - clearTimeout (timeout) { - if (timeout instanceof Timeout) { - timeout.clear() - } else { - clearTimeout(timeout) - } - } -} - - -/***/ }), - -/***/ 7610: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const diagnosticsChannel = __nccwpck_require__(7643) -const { uid, states } = __nccwpck_require__(4009) -const { - kReadyState, - kSentClose, - kByteParser, - kReceivedClose -} = __nccwpck_require__(4295) -const { fireEvent, failWebsocketConnection } = __nccwpck_require__(1310) -const { CloseEvent } = __nccwpck_require__(3458) -const { makeRequest } = __nccwpck_require__(8619) -const { fetching } = __nccwpck_require__(3360) -const { Headers } = __nccwpck_require__(7967) -const { getGlobalDispatcher } = __nccwpck_require__(398) -const { kHeadersList } = __nccwpck_require__(1439) - -const channels = {} -channels.open = diagnosticsChannel.channel('undici:websocket:open') -channels.close = diagnosticsChannel.channel('undici:websocket:close') -channels.socketError = diagnosticsChannel.channel('undici:websocket:socket_error') - -/** @type {import('crypto')} */ -let crypto -try { - crypto = __nccwpck_require__(6113) -} catch { - -} - -/** - * @see https://websockets.spec.whatwg.org/#concept-websocket-establish - * @param {URL} url - * @param {string|string[]} protocols - * @param {import('./websocket').WebSocket} ws - * @param {(response: any) => void} onEstablish - * @param {Partial<import('../../types/websocket').WebSocketInit>} options - */ -function establishWebSocketConnection (url, protocols, ws, onEstablish, options) { - // 1. Let requestURL be a copy of url, with its scheme set to "http", if url’s - // scheme is "ws", and to "https" otherwise. - const requestURL = url - - requestURL.protocol = url.protocol === 'ws:' ? 'http:' : 'https:' - - // 2. Let request be a new request, whose URL is requestURL, client is client, - // service-workers mode is "none", referrer is "no-referrer", mode is - // "websocket", credentials mode is "include", cache mode is "no-store" , - // and redirect mode is "error". - const request = makeRequest({ - urlList: [requestURL], - serviceWorkers: 'none', - referrer: 'no-referrer', - mode: 'websocket', - credentials: 'include', - cache: 'no-store', - redirect: 'error' - }) - - // Note: undici extension, allow setting custom headers. - if (options.headers) { - const headersList = new Headers(options.headers)[kHeadersList] - - request.headersList = headersList - } - - // 3. Append (`Upgrade`, `websocket`) to request’s header list. - // 4. Append (`Connection`, `Upgrade`) to request’s header list. - // Note: both of these are handled by undici currently. - // https://github.com/nodejs/undici/blob/68c269c4144c446f3f1220951338daef4a6b5ec4/lib/client.js#L1397 - - // 5. Let keyValue be a nonce consisting of a randomly selected - // 16-byte value that has been forgiving-base64-encoded and - // isomorphic encoded. - const keyValue = crypto.randomBytes(16).toString('base64') - - // 6. Append (`Sec-WebSocket-Key`, keyValue) to request’s - // header list. - request.headersList.append('sec-websocket-key', keyValue) - - // 7. Append (`Sec-WebSocket-Version`, `13`) to request’s - // header list. - request.headersList.append('sec-websocket-version', '13') - - // 8. For each protocol in protocols, combine - // (`Sec-WebSocket-Protocol`, protocol) in request’s header - // list. - for (const protocol of protocols) { - request.headersList.append('sec-websocket-protocol', protocol) - } - - // 9. Let permessageDeflate be a user-agent defined - // "permessage-deflate" extension header value. - // https://github.com/mozilla/gecko-dev/blob/ce78234f5e653a5d3916813ff990f053510227bc/netwerk/protocol/websocket/WebSocketChannel.cpp#L2673 - // TODO: enable once permessage-deflate is supported - const permessageDeflate = '' // 'permessage-deflate; 15' - - // 10. Append (`Sec-WebSocket-Extensions`, permessageDeflate) to - // request’s header list. - // request.headersList.append('sec-websocket-extensions', permessageDeflate) - - // 11. Fetch request with useParallelQueue set to true, and - // processResponse given response being these steps: - const controller = fetching({ - request, - useParallelQueue: true, - dispatcher: options.dispatcher ?? getGlobalDispatcher(), - processResponse (response) { - // 1. If response is a network error or its status is not 101, - // fail the WebSocket connection. - if (response.type === 'error' || response.status !== 101) { - failWebsocketConnection(ws, 'Received network error or non-101 status code.') - return - } - - // 2. If protocols is not the empty list and extracting header - // list values given `Sec-WebSocket-Protocol` and response’s - // header list results in null, failure, or the empty byte - // sequence, then fail the WebSocket connection. - if (protocols.length !== 0 && !response.headersList.get('Sec-WebSocket-Protocol')) { - failWebsocketConnection(ws, 'Server did not respond with sent protocols.') - return - } - - // 3. Follow the requirements stated step 2 to step 6, inclusive, - // of the last set of steps in section 4.1 of The WebSocket - // Protocol to validate response. This either results in fail - // the WebSocket connection or the WebSocket connection is - // established. - - // 2. If the response lacks an |Upgrade| header field or the |Upgrade| - // header field contains a value that is not an ASCII case- - // insensitive match for the value "websocket", the client MUST - // _Fail the WebSocket Connection_. - if (response.headersList.get('Upgrade')?.toLowerCase() !== 'websocket') { - failWebsocketConnection(ws, 'Server did not set Upgrade header to "websocket".') - return - } - - // 3. If the response lacks a |Connection| header field or the - // |Connection| header field doesn't contain a token that is an - // ASCII case-insensitive match for the value "Upgrade", the client - // MUST _Fail the WebSocket Connection_. - if (response.headersList.get('Connection')?.toLowerCase() !== 'upgrade') { - failWebsocketConnection(ws, 'Server did not set Connection header to "upgrade".') - return - } - - // 4. If the response lacks a |Sec-WebSocket-Accept| header field or - // the |Sec-WebSocket-Accept| contains a value other than the - // base64-encoded SHA-1 of the concatenation of the |Sec-WebSocket- - // Key| (as a string, not base64-decoded) with the string "258EAFA5- - // E914-47DA-95CA-C5AB0DC85B11" but ignoring any leading and - // trailing whitespace, the client MUST _Fail the WebSocket - // Connection_. - const secWSAccept = response.headersList.get('Sec-WebSocket-Accept') - const digest = crypto.createHash('sha1').update(keyValue + uid).digest('base64') - if (secWSAccept !== digest) { - failWebsocketConnection(ws, 'Incorrect hash received in Sec-WebSocket-Accept header.') - return - } - - // 5. If the response includes a |Sec-WebSocket-Extensions| header - // field and this header field indicates the use of an extension - // that was not present in the client's handshake (the server has - // indicated an extension not requested by the client), the client - // MUST _Fail the WebSocket Connection_. (The parsing of this - // header field to determine which extensions are requested is - // discussed in Section 9.1.) - const secExtension = response.headersList.get('Sec-WebSocket-Extensions') - - if (secExtension !== null && secExtension !== permessageDeflate) { - failWebsocketConnection(ws, 'Received different permessage-deflate than the one set.') - return - } - - // 6. If the response includes a |Sec-WebSocket-Protocol| header field - // and this header field indicates the use of a subprotocol that was - // not present in the client's handshake (the server has indicated a - // subprotocol not requested by the client), the client MUST _Fail - // the WebSocket Connection_. - const secProtocol = response.headersList.get('Sec-WebSocket-Protocol') - - if (secProtocol !== null && secProtocol !== request.headersList.get('Sec-WebSocket-Protocol')) { - failWebsocketConnection(ws, 'Protocol was not set in the opening handshake.') - return - } - - response.socket.on('data', onSocketData) - response.socket.on('close', onSocketClose) - response.socket.on('error', onSocketError) - - if (channels.open.hasSubscribers) { - channels.open.publish({ - address: response.socket.address(), - protocol: secProtocol, - extensions: secExtension - }) - } - - onEstablish(response) - } - }) - - return controller -} - -/** - * @param {Buffer} chunk - */ -function onSocketData (chunk) { - if (!this.ws[kByteParser].write(chunk)) { - this.pause() - } -} - -/** - * @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol - * @see https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.4 - */ -function onSocketClose () { - const { ws } = this - - // If the TCP connection was closed after the - // WebSocket closing handshake was completed, the WebSocket connection - // is said to have been closed _cleanly_. - const wasClean = ws[kSentClose] && ws[kReceivedClose] - - let code = 1005 - let reason = '' - - const result = ws[kByteParser].closingInfo - - if (result) { - code = result.code ?? 1005 - reason = result.reason - } else if (!ws[kSentClose]) { - // If _The WebSocket - // Connection is Closed_ and no Close control frame was received by the - // endpoint (such as could occur if the underlying transport connection - // is lost), _The WebSocket Connection Close Code_ is considered to be - // 1006. - code = 1006 - } - - // 1. Change the ready state to CLOSED (3). - ws[kReadyState] = states.CLOSED - - // 2. If the user agent was required to fail the WebSocket - // connection, or if the WebSocket connection was closed - // after being flagged as full, fire an event named error - // at the WebSocket object. - // TODO - - // 3. Fire an event named close at the WebSocket object, - // using CloseEvent, with the wasClean attribute - // initialized to true if the connection closed cleanly - // and false otherwise, the code attribute initialized to - // the WebSocket connection close code, and the reason - // attribute initialized to the result of applying UTF-8 - // decode without BOM to the WebSocket connection close - // reason. - fireEvent('close', ws, CloseEvent, { - wasClean, code, reason - }) - - if (channels.close.hasSubscribers) { - channels.close.publish({ - websocket: ws, - code, - reason - }) - } -} - -function onSocketError (error) { - const { ws } = this - - ws[kReadyState] = states.CLOSING - - if (channels.socketError.hasSubscribers) { - channels.socketError.publish(error) - } - - this.destroy() -} - -module.exports = { - establishWebSocketConnection -} - - -/***/ }), - -/***/ 4009: -/***/ ((module) => { - -"use strict"; - - -// This is a Globally Unique Identifier unique used -// to validate that the endpoint accepts websocket -// connections. -// See https://www.rfc-editor.org/rfc/rfc6455.html#section-1.3 -const uid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' - -/** @type {PropertyDescriptor} */ -const staticPropertyDescriptors = { - enumerable: true, - writable: false, - configurable: false -} - -const states = { - CONNECTING: 0, - OPEN: 1, - CLOSING: 2, - CLOSED: 3 -} - -const opcodes = { - CONTINUATION: 0x0, - TEXT: 0x1, - BINARY: 0x2, - CLOSE: 0x8, - PING: 0x9, - PONG: 0xA -} - -const maxUnsigned16Bit = 2 ** 16 - 1 // 65535 - -const parserStates = { - INFO: 0, - PAYLOADLENGTH_16: 2, - PAYLOADLENGTH_64: 3, - READ_DATA: 4 -} - -const emptyBuffer = Buffer.allocUnsafe(0) - -module.exports = { - uid, - staticPropertyDescriptors, - states, - opcodes, - maxUnsigned16Bit, - parserStates, - emptyBuffer -} - - -/***/ }), - -/***/ 3458: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { webidl } = __nccwpck_require__(5337) -const { kEnumerableProperty } = __nccwpck_require__(6223) -const { MessagePort } = __nccwpck_require__(1267) - -/** - * @see https://html.spec.whatwg.org/multipage/comms.html#messageevent - */ -class MessageEvent extends Event { - #eventInit - - constructor (type, eventInitDict = {}) { - webidl.argumentLengthCheck(arguments, 1, { header: 'MessageEvent constructor' }) - - type = webidl.converters.DOMString(type) - eventInitDict = webidl.converters.MessageEventInit(eventInitDict) - - super(type, eventInitDict) - - this.#eventInit = eventInitDict - } - - get data () { - webidl.brandCheck(this, MessageEvent) - - return this.#eventInit.data - } - - get origin () { - webidl.brandCheck(this, MessageEvent) - - return this.#eventInit.origin - } - - get lastEventId () { - webidl.brandCheck(this, MessageEvent) - - return this.#eventInit.lastEventId - } - - get source () { - webidl.brandCheck(this, MessageEvent) - - return this.#eventInit.source - } - - get ports () { - webidl.brandCheck(this, MessageEvent) - - if (!Object.isFrozen(this.#eventInit.ports)) { - Object.freeze(this.#eventInit.ports) - } - - return this.#eventInit.ports - } - - initMessageEvent ( - type, - bubbles = false, - cancelable = false, - data = null, - origin = '', - lastEventId = '', - source = null, - ports = [] - ) { - webidl.brandCheck(this, MessageEvent) - - webidl.argumentLengthCheck(arguments, 1, { header: 'MessageEvent.initMessageEvent' }) - - return new MessageEvent(type, { - bubbles, cancelable, data, origin, lastEventId, source, ports - }) - } -} - -/** - * @see https://websockets.spec.whatwg.org/#the-closeevent-interface - */ -class CloseEvent extends Event { - #eventInit - - constructor (type, eventInitDict = {}) { - webidl.argumentLengthCheck(arguments, 1, { header: 'CloseEvent constructor' }) - - type = webidl.converters.DOMString(type) - eventInitDict = webidl.converters.CloseEventInit(eventInitDict) - - super(type, eventInitDict) - - this.#eventInit = eventInitDict - } - - get wasClean () { - webidl.brandCheck(this, CloseEvent) - - return this.#eventInit.wasClean - } - - get code () { - webidl.brandCheck(this, CloseEvent) - - return this.#eventInit.code - } - - get reason () { - webidl.brandCheck(this, CloseEvent) - - return this.#eventInit.reason - } -} - -// https://html.spec.whatwg.org/multipage/webappapis.html#the-errorevent-interface -class ErrorEvent extends Event { - #eventInit - - constructor (type, eventInitDict) { - webidl.argumentLengthCheck(arguments, 1, { header: 'ErrorEvent constructor' }) - - super(type, eventInitDict) - - type = webidl.converters.DOMString(type) - eventInitDict = webidl.converters.ErrorEventInit(eventInitDict ?? {}) - - this.#eventInit = eventInitDict - } - - get message () { - webidl.brandCheck(this, ErrorEvent) - - return this.#eventInit.message - } - - get filename () { - webidl.brandCheck(this, ErrorEvent) - - return this.#eventInit.filename - } - - get lineno () { - webidl.brandCheck(this, ErrorEvent) - - return this.#eventInit.lineno - } - - get colno () { - webidl.brandCheck(this, ErrorEvent) - - return this.#eventInit.colno - } - - get error () { - webidl.brandCheck(this, ErrorEvent) - - return this.#eventInit.error - } -} - -Object.defineProperties(MessageEvent.prototype, { - [Symbol.toStringTag]: { - value: 'MessageEvent', - configurable: true - }, - data: kEnumerableProperty, - origin: kEnumerableProperty, - lastEventId: kEnumerableProperty, - source: kEnumerableProperty, - ports: kEnumerableProperty, - initMessageEvent: kEnumerableProperty -}) - -Object.defineProperties(CloseEvent.prototype, { - [Symbol.toStringTag]: { - value: 'CloseEvent', - configurable: true - }, - reason: kEnumerableProperty, - code: kEnumerableProperty, - wasClean: kEnumerableProperty -}) - -Object.defineProperties(ErrorEvent.prototype, { - [Symbol.toStringTag]: { - value: 'ErrorEvent', - configurable: true - }, - message: kEnumerableProperty, - filename: kEnumerableProperty, - lineno: kEnumerableProperty, - colno: kEnumerableProperty, - error: kEnumerableProperty -}) - -webidl.converters.MessagePort = webidl.interfaceConverter(MessagePort) - -webidl.converters['sequence<MessagePort>'] = webidl.sequenceConverter( - webidl.converters.MessagePort -) - -const eventInit = [ - { - key: 'bubbles', - converter: webidl.converters.boolean, - defaultValue: false - }, - { - key: 'cancelable', - converter: webidl.converters.boolean, - defaultValue: false - }, - { - key: 'composed', - converter: webidl.converters.boolean, - defaultValue: false - } -] - -webidl.converters.MessageEventInit = webidl.dictionaryConverter([ - ...eventInit, - { - key: 'data', - converter: webidl.converters.any, - defaultValue: null - }, - { - key: 'origin', - converter: webidl.converters.USVString, - defaultValue: '' - }, - { - key: 'lastEventId', - converter: webidl.converters.DOMString, - defaultValue: '' - }, - { - key: 'source', - // Node doesn't implement WindowProxy or ServiceWorker, so the only - // valid value for source is a MessagePort. - converter: webidl.nullableConverter(webidl.converters.MessagePort), - defaultValue: null - }, - { - key: 'ports', - converter: webidl.converters['sequence<MessagePort>'], - get defaultValue () { - return [] - } - } -]) - -webidl.converters.CloseEventInit = webidl.dictionaryConverter([ - ...eventInit, - { - key: 'wasClean', - converter: webidl.converters.boolean, - defaultValue: false - }, - { - key: 'code', - converter: webidl.converters['unsigned short'], - defaultValue: 0 - }, - { - key: 'reason', - converter: webidl.converters.USVString, - defaultValue: '' - } -]) - -webidl.converters.ErrorEventInit = webidl.dictionaryConverter([ - ...eventInit, - { - key: 'message', - converter: webidl.converters.DOMString, - defaultValue: '' - }, - { - key: 'filename', - converter: webidl.converters.USVString, - defaultValue: '' - }, - { - key: 'lineno', - converter: webidl.converters['unsigned long'], - defaultValue: 0 - }, - { - key: 'colno', - converter: webidl.converters['unsigned long'], - defaultValue: 0 - }, - { - key: 'error', - converter: webidl.converters.any - } -]) - -module.exports = { - MessageEvent, - CloseEvent, - ErrorEvent -} - - -/***/ }), - -/***/ 9262: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { maxUnsigned16Bit } = __nccwpck_require__(4009) - -/** @type {import('crypto')} */ -let crypto -try { - crypto = __nccwpck_require__(6113) -} catch { - -} - -class WebsocketFrameSend { - /** - * @param {Buffer|undefined} data - */ - constructor (data) { - this.frameData = data - this.maskKey = crypto.randomBytes(4) - } - - createFrame (opcode) { - const bodyLength = this.frameData?.byteLength ?? 0 - - /** @type {number} */ - let payloadLength = bodyLength // 0-125 - let offset = 6 - - if (bodyLength > maxUnsigned16Bit) { - offset += 8 // payload length is next 8 bytes - payloadLength = 127 - } else if (bodyLength > 125) { - offset += 2 // payload length is next 2 bytes - payloadLength = 126 - } - - const buffer = Buffer.allocUnsafe(bodyLength + offset) - - // Clear first 2 bytes, everything else is overwritten - buffer[0] = buffer[1] = 0 - buffer[0] |= 0x80 // FIN - buffer[0] = (buffer[0] & 0xF0) + opcode // opcode - - /*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> */ - buffer[offset - 4] = this.maskKey[0] - buffer[offset - 3] = this.maskKey[1] - buffer[offset - 2] = this.maskKey[2] - buffer[offset - 1] = this.maskKey[3] - - buffer[1] = payloadLength - - if (payloadLength === 126) { - buffer.writeUInt16BE(bodyLength, 2) - } else if (payloadLength === 127) { - // Clear extended payload length - buffer[2] = buffer[3] = 0 - buffer.writeUIntBE(bodyLength, 4, 6) - } - - buffer[1] |= 0x80 // MASK - - // mask body - for (let i = 0; i < bodyLength; i++) { - buffer[offset + i] = this.frameData[i] ^ this.maskKey[i % 4] - } - - return buffer - } -} - -module.exports = { - WebsocketFrameSend -} - - -/***/ }), - -/***/ 1213: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { Writable } = __nccwpck_require__(2781) -const diagnosticsChannel = __nccwpck_require__(7643) -const { parserStates, opcodes, states, emptyBuffer } = __nccwpck_require__(4009) -const { kReadyState, kSentClose, kResponse, kReceivedClose } = __nccwpck_require__(4295) -const { isValidStatusCode, failWebsocketConnection, websocketMessageReceived } = __nccwpck_require__(1310) -const { WebsocketFrameSend } = __nccwpck_require__(9262) - -// This code was influenced by ws released under the MIT license. -// Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com> -// Copyright (c) 2013 Arnout Kazemier and contributors -// Copyright (c) 2016 Luigi Pinca and contributors - -const channels = {} -channels.ping = diagnosticsChannel.channel('undici:websocket:ping') -channels.pong = diagnosticsChannel.channel('undici:websocket:pong') - -class ByteParser extends Writable { - #buffers = [] - #byteOffset = 0 - - #state = parserStates.INFO - - #info = {} - #fragments = [] - - constructor (ws) { - super() - - this.ws = ws - } - - /** - * @param {Buffer} chunk - * @param {() => void} callback - */ - _write (chunk, _, callback) { - this.#buffers.push(chunk) - this.#byteOffset += chunk.length - - this.run(callback) - } - - /** - * Runs whenever a new chunk is received. - * Callback is called whenever there are no more chunks buffering, - * or not enough bytes are buffered to parse. - */ - run (callback) { - while (true) { - if (this.#state === parserStates.INFO) { - // If there aren't enough bytes to parse the payload length, etc. - if (this.#byteOffset < 2) { - return callback() - } - - const buffer = this.consume(2) - - this.#info.fin = (buffer[0] & 0x80) !== 0 - this.#info.opcode = buffer[0] & 0x0F - - // If we receive a fragmented message, we use the type of the first - // frame to parse the full message as binary/text, when it's terminated - this.#info.originalOpcode ??= this.#info.opcode - - this.#info.fragmented = !this.#info.fin && this.#info.opcode !== opcodes.CONTINUATION - - if (this.#info.fragmented && this.#info.opcode !== opcodes.BINARY && this.#info.opcode !== opcodes.TEXT) { - // Only text and binary frames can be fragmented - failWebsocketConnection(this.ws, 'Invalid frame type was fragmented.') - return - } - - const payloadLength = buffer[1] & 0x7F - - if (payloadLength <= 125) { - this.#info.payloadLength = payloadLength - this.#state = parserStates.READ_DATA - } else if (payloadLength === 126) { - this.#state = parserStates.PAYLOADLENGTH_16 - } else if (payloadLength === 127) { - this.#state = parserStates.PAYLOADLENGTH_64 - } - - if (this.#info.fragmented && payloadLength > 125) { - // A fragmented frame can't be fragmented itself - failWebsocketConnection(this.ws, 'Fragmented frame exceeded 125 bytes.') - return - } else if ( - (this.#info.opcode === opcodes.PING || - this.#info.opcode === opcodes.PONG || - this.#info.opcode === opcodes.CLOSE) && - payloadLength > 125 - ) { - // Control frames can have a payload length of 125 bytes MAX - failWebsocketConnection(this.ws, 'Payload length for control frame exceeded 125 bytes.') - return - } else if (this.#info.opcode === opcodes.CLOSE) { - if (payloadLength === 1) { - failWebsocketConnection(this.ws, 'Received close frame with a 1-byte body.') - return - } - - const body = this.consume(payloadLength) - - this.#info.closeInfo = this.parseCloseBody(false, body) - - if (!this.ws[kSentClose]) { - // If an endpoint receives a Close frame and did not previously send a - // Close frame, the endpoint MUST send a Close frame in response. (When - // sending a Close frame in response, the endpoint typically echos the - // status code it received.) - const body = Buffer.allocUnsafe(2) - body.writeUInt16BE(this.#info.closeInfo.code, 0) - const closeFrame = new WebsocketFrameSend(body) - - this.ws[kResponse].socket.write( - closeFrame.createFrame(opcodes.CLOSE), - (err) => { - if (!err) { - this.ws[kSentClose] = true - } - } - ) - } - - // Upon either sending or receiving a Close control frame, it is said - // that _The WebSocket Closing Handshake is Started_ and that the - // WebSocket connection is in the CLOSING state. - this.ws[kReadyState] = states.CLOSING - this.ws[kReceivedClose] = true - - this.end() - - return - } else if (this.#info.opcode === opcodes.PING) { - // Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in - // response, unless it already received a Close frame. - // A Pong frame sent in response to a Ping frame must have identical - // "Application data" - - const body = this.consume(payloadLength) - - if (!this.ws[kReceivedClose]) { - const frame = new WebsocketFrameSend(body) - - this.ws[kResponse].socket.write(frame.createFrame(opcodes.PONG)) - - if (channels.ping.hasSubscribers) { - channels.ping.publish({ - payload: body - }) - } - } - - this.#state = parserStates.INFO - - if (this.#byteOffset > 0) { - continue - } else { - callback() - return - } - } else if (this.#info.opcode === opcodes.PONG) { - // A Pong frame MAY be sent unsolicited. This serves as a - // unidirectional heartbeat. A response to an unsolicited Pong frame is - // not expected. - - const body = this.consume(payloadLength) - - if (channels.pong.hasSubscribers) { - channels.pong.publish({ - payload: body - }) - } - - if (this.#byteOffset > 0) { - continue - } else { - callback() - return - } - } - } else if (this.#state === parserStates.PAYLOADLENGTH_16) { - if (this.#byteOffset < 2) { - return callback() - } - - const buffer = this.consume(2) - - this.#info.payloadLength = buffer.readUInt16BE(0) - this.#state = parserStates.READ_DATA - } else if (this.#state === parserStates.PAYLOADLENGTH_64) { - if (this.#byteOffset < 8) { - return callback() - } - - const buffer = this.consume(8) - const upper = buffer.readUInt32BE(0) - - // 2^31 is the maxinimum bytes an arraybuffer can contain - // on 32-bit systems. Although, on 64-bit systems, this is - // 2^53-1 bytes. - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_array_length - // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/common/globals.h;drc=1946212ac0100668f14eb9e2843bdd846e510a1e;bpv=1;bpt=1;l=1275 - // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/objects/js-array-buffer.h;l=34;drc=1946212ac0100668f14eb9e2843bdd846e510a1e - if (upper > 2 ** 31 - 1) { - failWebsocketConnection(this.ws, 'Received payload length > 2^31 bytes.') - return - } - - const lower = buffer.readUInt32BE(4) - - this.#info.payloadLength = (upper << 8) + lower - this.#state = parserStates.READ_DATA - } else if (this.#state === parserStates.READ_DATA) { - if (this.#byteOffset < this.#info.payloadLength) { - // If there is still more data in this chunk that needs to be read - return callback() - } else if (this.#byteOffset >= this.#info.payloadLength) { - // If the server sent multiple frames in a single chunk - - const body = this.consume(this.#info.payloadLength) - - this.#fragments.push(body) - - // If the frame is unfragmented, or a fragmented frame was terminated, - // a message was received - if (!this.#info.fragmented || (this.#info.fin && this.#info.opcode === opcodes.CONTINUATION)) { - const fullMessage = Buffer.concat(this.#fragments) - - websocketMessageReceived(this.ws, this.#info.originalOpcode, fullMessage) - - this.#info = {} - this.#fragments.length = 0 - } - - this.#state = parserStates.INFO - } - } - - if (this.#byteOffset > 0) { - continue - } else { - callback() - break - } - } - } - - /** - * Take n bytes from the buffered Buffers - * @param {number} n - * @returns {Buffer|null} - */ - consume (n) { - if (n > this.#byteOffset) { - return null - } else if (n === 0) { - return emptyBuffer - } - - if (this.#buffers[0].length === n) { - this.#byteOffset -= this.#buffers[0].length - return this.#buffers.shift() - } - - const buffer = Buffer.allocUnsafe(n) - let offset = 0 - - while (offset !== n) { - const next = this.#buffers[0] - const { length } = next - - if (length + offset === n) { - buffer.set(this.#buffers.shift(), offset) - break - } else if (length + offset > n) { - buffer.set(next.subarray(0, n - offset), offset) - this.#buffers[0] = next.subarray(n - offset) - break - } else { - buffer.set(this.#buffers.shift(), offset) - offset += next.length - } - } - - this.#byteOffset -= n - - return buffer - } - - parseCloseBody (onlyCode, data) { - // https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.5 - /** @type {number|undefined} */ - let code - - if (data.length >= 2) { - // _The WebSocket Connection Close Code_ is - // defined as the status code (Section 7.4) contained in the first Close - // control frame received by the application - code = data.readUInt16BE(0) - } - - if (onlyCode) { - if (!isValidStatusCode(code)) { - return null - } - - return { code } - } - - // https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.6 - /** @type {Buffer} */ - let reason = data.subarray(2) - - // Remove BOM - if (reason[0] === 0xEF && reason[1] === 0xBB && reason[2] === 0xBF) { - reason = reason.subarray(3) - } - - if (code !== undefined && !isValidStatusCode(code)) { - return null - } - - try { - // TODO: optimize this - reason = new TextDecoder('utf-8', { fatal: true }).decode(reason) - } catch { - return null - } - - return { code, reason } - } - - get closingInfo () { - return this.#info.closeInfo - } -} - -module.exports = { - ByteParser -} - - -/***/ }), - -/***/ 4295: -/***/ ((module) => { - -"use strict"; - - -module.exports = { - kWebSocketURL: Symbol('url'), - kReadyState: Symbol('ready state'), - kController: Symbol('controller'), - kResponse: Symbol('response'), - kBinaryType: Symbol('binary type'), - kSentClose: Symbol('sent close'), - kReceivedClose: Symbol('received close'), - kByteParser: Symbol('byte parser') -} - - -/***/ }), - -/***/ 1310: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { kReadyState, kController, kResponse, kBinaryType, kWebSocketURL } = __nccwpck_require__(4295) -const { states, opcodes } = __nccwpck_require__(4009) -const { MessageEvent, ErrorEvent } = __nccwpck_require__(3458) - -/* globals Blob */ - -/** - * @param {import('./websocket').WebSocket} ws - */ -function isEstablished (ws) { - // If the server's response is validated as provided for above, it is - // said that _The WebSocket Connection is Established_ and that the - // WebSocket Connection is in the OPEN state. - return ws[kReadyState] === states.OPEN -} - -/** - * @param {import('./websocket').WebSocket} ws - */ -function isClosing (ws) { - // Upon either sending or receiving a Close control frame, it is said - // that _The WebSocket Closing Handshake is Started_ and that the - // WebSocket connection is in the CLOSING state. - return ws[kReadyState] === states.CLOSING -} - -/** - * @param {import('./websocket').WebSocket} ws - */ -function isClosed (ws) { - return ws[kReadyState] === states.CLOSED -} - -/** - * @see https://dom.spec.whatwg.org/#concept-event-fire - * @param {string} e - * @param {EventTarget} target - * @param {EventInit | undefined} eventInitDict - */ -function fireEvent (e, target, eventConstructor = Event, eventInitDict) { - // 1. If eventConstructor is not given, then let eventConstructor be Event. - - // 2. Let event be the result of creating an event given eventConstructor, - // in the relevant realm of target. - // 3. Initialize event’s type attribute to e. - const event = new eventConstructor(e, eventInitDict) // eslint-disable-line new-cap - - // 4. Initialize any other IDL attributes of event as described in the - // invocation of this algorithm. - - // 5. Return the result of dispatching event at target, with legacy target - // override flag set if set. - target.dispatchEvent(event) -} - -/** - * @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol - * @param {import('./websocket').WebSocket} ws - * @param {number} type Opcode - * @param {Buffer} data application data - */ -function websocketMessageReceived (ws, type, data) { - // 1. If ready state is not OPEN (1), then return. - if (ws[kReadyState] !== states.OPEN) { - return - } - - // 2. Let dataForEvent be determined by switching on type and binary type: - let dataForEvent - - if (type === opcodes.TEXT) { - // -> type indicates that the data is Text - // a new DOMString containing data - try { - dataForEvent = new TextDecoder('utf-8', { fatal: true }).decode(data) - } catch { - failWebsocketConnection(ws, 'Received invalid UTF-8 in text frame.') - return - } - } else if (type === opcodes.BINARY) { - if (ws[kBinaryType] === 'blob') { - // -> type indicates that the data is Binary and binary type is "blob" - // a new Blob object, created in the relevant Realm of the WebSocket - // object, that represents data as its raw data - dataForEvent = new Blob([data]) - } else { - // -> type indicates that the data is Binary and binary type is "arraybuffer" - // a new ArrayBuffer object, created in the relevant Realm of the - // WebSocket object, whose contents are data - dataForEvent = new Uint8Array(data).buffer - } - } - - // 3. Fire an event named message at the WebSocket object, using MessageEvent, - // with the origin attribute initialized to the serialization of the WebSocket - // object’s url's origin, and the data attribute initialized to dataForEvent. - fireEvent('message', ws, MessageEvent, { - origin: ws[kWebSocketURL].origin, - data: dataForEvent - }) -} - -/** - * @see https://datatracker.ietf.org/doc/html/rfc6455 - * @see https://datatracker.ietf.org/doc/html/rfc2616 - * @see https://bugs.chromium.org/p/chromium/issues/detail?id=398407 - * @param {string} protocol - */ -function isValidSubprotocol (protocol) { - // If present, this value indicates one - // or more comma-separated subprotocol the client wishes to speak, - // ordered by preference. The elements that comprise this value - // MUST be non-empty strings with characters in the range U+0021 to - // U+007E not including separator characters as defined in - // [RFC2616] and MUST all be unique strings. - if (protocol.length === 0) { - return false - } - - for (const char of protocol) { - const code = char.charCodeAt(0) - - if ( - code < 0x21 || - code > 0x7E || - char === '(' || - char === ')' || - char === '<' || - char === '>' || - char === '@' || - char === ',' || - char === ';' || - char === ':' || - char === '\\' || - char === '"' || - char === '/' || - char === '[' || - char === ']' || - char === '?' || - char === '=' || - char === '{' || - char === '}' || - code === 32 || // SP - code === 9 // HT - ) { - return false - } - } - - return true -} - -/** - * @see https://datatracker.ietf.org/doc/html/rfc6455#section-7-4 - * @param {number} code - */ -function isValidStatusCode (code) { - if (code >= 1000 && code < 1015) { - return ( - code !== 1004 && // reserved - code !== 1005 && // "MUST NOT be set as a status code" - code !== 1006 // "MUST NOT be set as a status code" - ) - } - - return code >= 3000 && code <= 4999 -} - -/** - * @param {import('./websocket').WebSocket} ws - * @param {string|undefined} reason - */ -function failWebsocketConnection (ws, reason) { - const { [kController]: controller, [kResponse]: response } = ws - - controller.abort() - - if (response?.socket && !response.socket.destroyed) { - response.socket.destroy() - } - - if (reason) { - fireEvent('error', ws, ErrorEvent, { - error: new Error(reason) - }) - } -} - -module.exports = { - isEstablished, - isClosing, - isClosed, - fireEvent, - isValidSubprotocol, - isValidStatusCode, - failWebsocketConnection, - websocketMessageReceived -} - - -/***/ }), - -/***/ 6624: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const { webidl } = __nccwpck_require__(5337) -const { DOMException } = __nccwpck_require__(7213) -const { URLSerializer } = __nccwpck_require__(6822) -const { getGlobalOrigin } = __nccwpck_require__(4428) -const { staticPropertyDescriptors, states, opcodes, emptyBuffer } = __nccwpck_require__(4009) -const { - kWebSocketURL, - kReadyState, - kController, - kBinaryType, - kResponse, - kSentClose, - kByteParser -} = __nccwpck_require__(4295) -const { isEstablished, isClosing, isValidSubprotocol, failWebsocketConnection, fireEvent } = __nccwpck_require__(1310) -const { establishWebSocketConnection } = __nccwpck_require__(7610) -const { WebsocketFrameSend } = __nccwpck_require__(9262) -const { ByteParser } = __nccwpck_require__(1213) -const { kEnumerableProperty, isBlobLike } = __nccwpck_require__(6223) -const { getGlobalDispatcher } = __nccwpck_require__(398) -const { types } = __nccwpck_require__(3837) - -let experimentalWarned = false - -// https://websockets.spec.whatwg.org/#interface-definition -class WebSocket extends EventTarget { - #events = { - open: null, - error: null, - close: null, - message: null - } - - #bufferedAmount = 0 - #protocol = '' - #extensions = '' - - /** - * @param {string} url - * @param {string|string[]} protocols - */ - constructor (url, protocols = []) { - super() - - webidl.argumentLengthCheck(arguments, 1, { header: 'WebSocket constructor' }) - - if (!experimentalWarned) { - experimentalWarned = true - process.emitWarning('WebSockets are experimental, expect them to change at any time.', { - code: 'UNDICI-WS' - }) - } - - const options = webidl.converters['DOMString or sequence<DOMString> or WebSocketInit'](protocols) - - url = webidl.converters.USVString(url) - protocols = options.protocols - - // 1. Let baseURL be this's relevant settings object's API base URL. - const baseURL = getGlobalOrigin() - - // 1. Let urlRecord be the result of applying the URL parser to url with baseURL. - let urlRecord - - try { - urlRecord = new URL(url, baseURL) - } catch (e) { - // 3. If urlRecord is failure, then throw a "SyntaxError" DOMException. - throw new DOMException(e, 'SyntaxError') - } - - // 4. If urlRecord’s scheme is "http", then set urlRecord’s scheme to "ws". - if (urlRecord.protocol === 'http:') { - urlRecord.protocol = 'ws:' - } else if (urlRecord.protocol === 'https:') { - // 5. Otherwise, if urlRecord’s scheme is "https", set urlRecord’s scheme to "wss". - urlRecord.protocol = 'wss:' - } - - // 6. If urlRecord’s scheme is not "ws" or "wss", then throw a "SyntaxError" DOMException. - if (urlRecord.protocol !== 'ws:' && urlRecord.protocol !== 'wss:') { - throw new DOMException( - `Expected a ws: or wss: protocol, got ${urlRecord.protocol}`, - 'SyntaxError' - ) - } - - // 7. If urlRecord’s fragment is non-null, then throw a "SyntaxError" - // DOMException. - if (urlRecord.hash || urlRecord.href.endsWith('#')) { - throw new DOMException('Got fragment', 'SyntaxError') - } - - // 8. If protocols is a string, set protocols to a sequence consisting - // of just that string. - if (typeof protocols === 'string') { - protocols = [protocols] - } - - // 9. If any of the values in protocols occur more than once or otherwise - // fail to match the requirements for elements that comprise the value - // of `Sec-WebSocket-Protocol` fields as defined by The WebSocket - // protocol, then throw a "SyntaxError" DOMException. - if (protocols.length !== new Set(protocols.map(p => p.toLowerCase())).size) { - throw new DOMException('Invalid Sec-WebSocket-Protocol value', 'SyntaxError') - } - - if (protocols.length > 0 && !protocols.every(p => isValidSubprotocol(p))) { - throw new DOMException('Invalid Sec-WebSocket-Protocol value', 'SyntaxError') - } - - // 10. Set this's url to urlRecord. - this[kWebSocketURL] = new URL(urlRecord.href) - - // 11. Let client be this's relevant settings object. - - // 12. Run this step in parallel: - - // 1. Establish a WebSocket connection given urlRecord, protocols, - // and client. - this[kController] = establishWebSocketConnection( - urlRecord, - protocols, - this, - (response) => this.#onConnectionEstablished(response), - options - ) - - // Each WebSocket object has an associated ready state, which is a - // number representing the state of the connection. Initially it must - // be CONNECTING (0). - this[kReadyState] = WebSocket.CONNECTING - - // The extensions attribute must initially return the empty string. - - // The protocol attribute must initially return the empty string. - - // Each WebSocket object has an associated binary type, which is a - // BinaryType. Initially it must be "blob". - this[kBinaryType] = 'blob' - } - - /** - * @see https://websockets.spec.whatwg.org/#dom-websocket-close - * @param {number|undefined} code - * @param {string|undefined} reason - */ - close (code = undefined, reason = undefined) { - webidl.brandCheck(this, WebSocket) - - if (code !== undefined) { - code = webidl.converters['unsigned short'](code, { clamp: true }) - } - - if (reason !== undefined) { - reason = webidl.converters.USVString(reason) - } - - // 1. If code is present, but is neither an integer equal to 1000 nor an - // integer in the range 3000 to 4999, inclusive, throw an - // "InvalidAccessError" DOMException. - if (code !== undefined) { - if (code !== 1000 && (code < 3000 || code > 4999)) { - throw new DOMException('invalid code', 'InvalidAccessError') - } - } - - let reasonByteLength = 0 - - // 2. If reason is present, then run these substeps: - if (reason !== undefined) { - // 1. Let reasonBytes be the result of encoding reason. - // 2. If reasonBytes is longer than 123 bytes, then throw a - // "SyntaxError" DOMException. - reasonByteLength = Buffer.byteLength(reason) - - if (reasonByteLength > 123) { - throw new DOMException( - `Reason must be less than 123 bytes; received ${reasonByteLength}`, - 'SyntaxError' - ) - } - } - - // 3. Run the first matching steps from the following list: - if (this[kReadyState] === WebSocket.CLOSING || this[kReadyState] === WebSocket.CLOSED) { - // If this's ready state is CLOSING (2) or CLOSED (3) - // Do nothing. - } else if (!isEstablished(this)) { - // If the WebSocket connection is not yet established - // Fail the WebSocket connection and set this's ready state - // to CLOSING (2). - failWebsocketConnection(this, 'Connection was closed before it was established.') - this[kReadyState] = WebSocket.CLOSING - } else if (!isClosing(this)) { - // If the WebSocket closing handshake has not yet been started - // Start the WebSocket closing handshake and set this's ready - // state to CLOSING (2). - // - If neither code nor reason is present, the WebSocket Close - // message must not have a body. - // - If code is present, then the status code to use in the - // WebSocket Close message must be the integer given by code. - // - If reason is also present, then reasonBytes must be - // provided in the Close message after the status code. - - const frame = new WebsocketFrameSend() - - // If neither code nor reason is present, the WebSocket Close - // message must not have a body. - - // If code is present, then the status code to use in the - // WebSocket Close message must be the integer given by code. - if (code !== undefined && reason === undefined) { - frame.frameData = Buffer.allocUnsafe(2) - frame.frameData.writeUInt16BE(code, 0) - } else if (code !== undefined && reason !== undefined) { - // If reason is also present, then reasonBytes must be - // provided in the Close message after the status code. - frame.frameData = Buffer.allocUnsafe(2 + reasonByteLength) - frame.frameData.writeUInt16BE(code, 0) - // the body MAY contain UTF-8-encoded data with value /reason/ - frame.frameData.write(reason, 2, 'utf-8') - } else { - frame.frameData = emptyBuffer - } - - /** @type {import('stream').Duplex} */ - const socket = this[kResponse].socket - - socket.write(frame.createFrame(opcodes.CLOSE), (err) => { - if (!err) { - this[kSentClose] = true - } - }) - - // Upon either sending or receiving a Close control frame, it is said - // that _The WebSocket Closing Handshake is Started_ and that the - // WebSocket connection is in the CLOSING state. - this[kReadyState] = states.CLOSING - } else { - // Otherwise - // Set this's ready state to CLOSING (2). - this[kReadyState] = WebSocket.CLOSING - } - } - - /** - * @see https://websockets.spec.whatwg.org/#dom-websocket-send - * @param {NodeJS.TypedArray|ArrayBuffer|Blob|string} data - */ - send (data) { - webidl.brandCheck(this, WebSocket) - - webidl.argumentLengthCheck(arguments, 1, { header: 'WebSocket.send' }) - - data = webidl.converters.WebSocketSendData(data) - - // 1. If this's ready state is CONNECTING, then throw an - // "InvalidStateError" DOMException. - if (this[kReadyState] === WebSocket.CONNECTING) { - throw new DOMException('Sent before connected.', 'InvalidStateError') - } - - // 2. Run the appropriate set of steps from the following list: - // https://datatracker.ietf.org/doc/html/rfc6455#section-6.1 - // https://datatracker.ietf.org/doc/html/rfc6455#section-5.2 - - if (!isEstablished(this) || isClosing(this)) { - return - } - - /** @type {import('stream').Duplex} */ - const socket = this[kResponse].socket - - // If data is a string - if (typeof data === 'string') { - // If the WebSocket connection is established and the WebSocket - // closing handshake has not yet started, then the user agent - // must send a WebSocket Message comprised of the data argument - // using a text frame opcode; if the data cannot be sent, e.g. - // because it would need to be buffered but the buffer is full, - // the user agent must flag the WebSocket as full and then close - // the WebSocket connection. Any invocation of this method with a - // string argument that does not throw an exception must increase - // the bufferedAmount attribute by the number of bytes needed to - // express the argument as UTF-8. - - const value = Buffer.from(data) - const frame = new WebsocketFrameSend(value) - const buffer = frame.createFrame(opcodes.TEXT) - - this.#bufferedAmount += value.byteLength - socket.write(buffer, () => { - this.#bufferedAmount -= value.byteLength - }) - } else if (types.isArrayBuffer(data)) { - // If the WebSocket connection is established, and the WebSocket - // closing handshake has not yet started, then the user agent must - // send a WebSocket Message comprised of data using a binary frame - // opcode; if the data cannot be sent, e.g. because it would need - // to be buffered but the buffer is full, the user agent must flag - // the WebSocket as full and then close the WebSocket connection. - // The data to be sent is the data stored in the buffer described - // by the ArrayBuffer object. Any invocation of this method with an - // ArrayBuffer argument that does not throw an exception must - // increase the bufferedAmount attribute by the length of the - // ArrayBuffer in bytes. - - const value = Buffer.from(data) - const frame = new WebsocketFrameSend(value) - const buffer = frame.createFrame(opcodes.BINARY) - - this.#bufferedAmount += value.byteLength - socket.write(buffer, () => { - this.#bufferedAmount -= value.byteLength - }) - } else if (ArrayBuffer.isView(data)) { - // If the WebSocket connection is established, and the WebSocket - // closing handshake has not yet started, then the user agent must - // send a WebSocket Message comprised of data using a binary frame - // opcode; if the data cannot be sent, e.g. because it would need to - // be buffered but the buffer is full, the user agent must flag the - // WebSocket as full and then close the WebSocket connection. The - // data to be sent is the data stored in the section of the buffer - // described by the ArrayBuffer object that data references. Any - // invocation of this method with this kind of argument that does - // not throw an exception must increase the bufferedAmount attribute - // by the length of data’s buffer in bytes. - - const ab = Buffer.from(data, data.byteOffset, data.byteLength) - - const frame = new WebsocketFrameSend(ab) - const buffer = frame.createFrame(opcodes.BINARY) - - this.#bufferedAmount += ab.byteLength - socket.write(buffer, () => { - this.#bufferedAmount -= ab.byteLength - }) - } else if (isBlobLike(data)) { - // If the WebSocket connection is established, and the WebSocket - // closing handshake has not yet started, then the user agent must - // send a WebSocket Message comprised of data using a binary frame - // opcode; if the data cannot be sent, e.g. because it would need to - // be buffered but the buffer is full, the user agent must flag the - // WebSocket as full and then close the WebSocket connection. The data - // to be sent is the raw data represented by the Blob object. Any - // invocation of this method with a Blob argument that does not throw - // an exception must increase the bufferedAmount attribute by the size - // of the Blob object’s raw data, in bytes. - - const frame = new WebsocketFrameSend() - - data.arrayBuffer().then((ab) => { - const value = Buffer.from(ab) - frame.frameData = value - const buffer = frame.createFrame(opcodes.BINARY) - - this.#bufferedAmount += value.byteLength - socket.write(buffer, () => { - this.#bufferedAmount -= value.byteLength - }) - }) - } - } - - get readyState () { - webidl.brandCheck(this, WebSocket) - - // The readyState getter steps are to return this's ready state. - return this[kReadyState] - } - - get bufferedAmount () { - webidl.brandCheck(this, WebSocket) - - return this.#bufferedAmount - } - - get url () { - webidl.brandCheck(this, WebSocket) - - // The url getter steps are to return this's url, serialized. - return URLSerializer(this[kWebSocketURL]) - } - - get extensions () { - webidl.brandCheck(this, WebSocket) - - return this.#extensions - } - - get protocol () { - webidl.brandCheck(this, WebSocket) - - return this.#protocol - } - - get onopen () { - webidl.brandCheck(this, WebSocket) - - return this.#events.open - } - - set onopen (fn) { - webidl.brandCheck(this, WebSocket) - - if (this.#events.open) { - this.removeEventListener('open', this.#events.open) - } - - if (typeof fn === 'function') { - this.#events.open = fn - this.addEventListener('open', fn) - } else { - this.#events.open = null - } - } - - get onerror () { - webidl.brandCheck(this, WebSocket) - - return this.#events.error - } - - set onerror (fn) { - webidl.brandCheck(this, WebSocket) - - if (this.#events.error) { - this.removeEventListener('error', this.#events.error) - } - - if (typeof fn === 'function') { - this.#events.error = fn - this.addEventListener('error', fn) - } else { - this.#events.error = null - } - } - - get onclose () { - webidl.brandCheck(this, WebSocket) - - return this.#events.close - } - - set onclose (fn) { - webidl.brandCheck(this, WebSocket) - - if (this.#events.close) { - this.removeEventListener('close', this.#events.close) - } - - if (typeof fn === 'function') { - this.#events.close = fn - this.addEventListener('close', fn) - } else { - this.#events.close = null - } - } - - get onmessage () { - webidl.brandCheck(this, WebSocket) - - return this.#events.message - } - - set onmessage (fn) { - webidl.brandCheck(this, WebSocket) - - if (this.#events.message) { - this.removeEventListener('message', this.#events.message) - } - - if (typeof fn === 'function') { - this.#events.message = fn - this.addEventListener('message', fn) - } else { - this.#events.message = null - } - } - - get binaryType () { - webidl.brandCheck(this, WebSocket) - - return this[kBinaryType] - } - - set binaryType (type) { - webidl.brandCheck(this, WebSocket) - - if (type !== 'blob' && type !== 'arraybuffer') { - this[kBinaryType] = 'blob' - } else { - this[kBinaryType] = type - } - } - - /** - * @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol - */ - #onConnectionEstablished (response) { - // processResponse is called when the "response’s header list has been received and initialized." - // once this happens, the connection is open - this[kResponse] = response - - const parser = new ByteParser(this) - parser.on('drain', function onParserDrain () { - this.ws[kResponse].socket.resume() - }) - - response.socket.ws = this - this[kByteParser] = parser - - // 1. Change the ready state to OPEN (1). - this[kReadyState] = states.OPEN - - // 2. Change the extensions attribute’s value to the extensions in use, if - // it is not the null value. - // https://datatracker.ietf.org/doc/html/rfc6455#section-9.1 - const extensions = response.headersList.get('sec-websocket-extensions') - - if (extensions !== null) { - this.#extensions = extensions - } - - // 3. Change the protocol attribute’s value to the subprotocol in use, if - // it is not the null value. - // https://datatracker.ietf.org/doc/html/rfc6455#section-1.9 - const protocol = response.headersList.get('sec-websocket-protocol') - - if (protocol !== null) { - this.#protocol = protocol - } - - // 4. Fire an event named open at the WebSocket object. - fireEvent('open', this) - } -} - -// https://websockets.spec.whatwg.org/#dom-websocket-connecting -WebSocket.CONNECTING = WebSocket.prototype.CONNECTING = states.CONNECTING -// https://websockets.spec.whatwg.org/#dom-websocket-open -WebSocket.OPEN = WebSocket.prototype.OPEN = states.OPEN -// https://websockets.spec.whatwg.org/#dom-websocket-closing -WebSocket.CLOSING = WebSocket.prototype.CLOSING = states.CLOSING -// https://websockets.spec.whatwg.org/#dom-websocket-closed -WebSocket.CLOSED = WebSocket.prototype.CLOSED = states.CLOSED - -Object.defineProperties(WebSocket.prototype, { - CONNECTING: staticPropertyDescriptors, - OPEN: staticPropertyDescriptors, - CLOSING: staticPropertyDescriptors, - CLOSED: staticPropertyDescriptors, - url: kEnumerableProperty, - readyState: kEnumerableProperty, - bufferedAmount: kEnumerableProperty, - onopen: kEnumerableProperty, - onerror: kEnumerableProperty, - onclose: kEnumerableProperty, - close: kEnumerableProperty, - onmessage: kEnumerableProperty, - binaryType: kEnumerableProperty, - send: kEnumerableProperty, - extensions: kEnumerableProperty, - protocol: kEnumerableProperty, - [Symbol.toStringTag]: { - value: 'WebSocket', - writable: false, - enumerable: false, - configurable: true - } -}) - -Object.defineProperties(WebSocket, { - CONNECTING: staticPropertyDescriptors, - OPEN: staticPropertyDescriptors, - CLOSING: staticPropertyDescriptors, - CLOSED: staticPropertyDescriptors -}) - -webidl.converters['sequence<DOMString>'] = webidl.sequenceConverter( - webidl.converters.DOMString -) - -webidl.converters['DOMString or sequence<DOMString>'] = function (V) { - if (webidl.util.Type(V) === 'Object' && Symbol.iterator in V) { - return webidl.converters['sequence<DOMString>'](V) - } - - return webidl.converters.DOMString(V) -} - -// This implements the propsal made in https://github.com/whatwg/websockets/issues/42 -webidl.converters.WebSocketInit = webidl.dictionaryConverter([ - { - key: 'protocols', - converter: webidl.converters['DOMString or sequence<DOMString>'], - get defaultValue () { - return [] - } - }, - { - key: 'dispatcher', - converter: (V) => V, - get defaultValue () { - return getGlobalDispatcher() - } - }, - { - key: 'headers', - converter: webidl.nullableConverter(webidl.converters.HeadersInit) - } -]) - -webidl.converters['DOMString or sequence<DOMString> or WebSocketInit'] = function (V) { - if (webidl.util.Type(V) === 'Object' && !(Symbol.iterator in V)) { - return webidl.converters.WebSocketInit(V) - } - - return { protocols: webidl.converters['DOMString or sequence<DOMString>'](V) } -} - -webidl.converters.WebSocketSendData = function (V) { - if (webidl.util.Type(V) === 'Object') { - if (isBlobLike(V)) { - return webidl.converters.Blob(V, { strict: false }) - } - - if (ArrayBuffer.isView(V) || types.isAnyArrayBuffer(V)) { - return webidl.converters.BufferSource(V) - } - } - - return webidl.converters.USVString(V) -} - -module.exports = { - WebSocket -} - - -/***/ }), - -/***/ 8860: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -Object.defineProperty(exports, "v1", ({ - enumerable: true, - get: function () { - return _v.default; - } -})); -Object.defineProperty(exports, "v3", ({ - enumerable: true, - get: function () { - return _v2.default; - } -})); -Object.defineProperty(exports, "v4", ({ - enumerable: true, - get: function () { - return _v3.default; - } -})); -Object.defineProperty(exports, "v5", ({ - enumerable: true, - get: function () { - return _v4.default; - } -})); -Object.defineProperty(exports, "NIL", ({ - enumerable: true, - get: function () { - return _nil.default; - } -})); -Object.defineProperty(exports, "version", ({ - enumerable: true, - get: function () { - return _version.default; - } -})); -Object.defineProperty(exports, "validate", ({ - enumerable: true, - get: function () { - return _validate.default; - } -})); -Object.defineProperty(exports, "stringify", ({ - enumerable: true, - get: function () { - return _stringify.default; - } -})); -Object.defineProperty(exports, "parse", ({ - enumerable: true, - get: function () { - return _parse.default; - } -})); - -var _v = _interopRequireDefault(__nccwpck_require__(2078)); - -var _v2 = _interopRequireDefault(__nccwpck_require__(7788)); - -var _v3 = _interopRequireDefault(__nccwpck_require__(4205)); - -var _v4 = _interopRequireDefault(__nccwpck_require__(2795)); - -var _nil = _interopRequireDefault(__nccwpck_require__(2162)); - -var _version = _interopRequireDefault(__nccwpck_require__(5315)); - -var _validate = _interopRequireDefault(__nccwpck_require__(6192)); - -var _stringify = _interopRequireDefault(__nccwpck_require__(5354)); - -var _parse = _interopRequireDefault(__nccwpck_require__(861)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -/***/ }), - -/***/ 1755: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _crypto = _interopRequireDefault(__nccwpck_require__(6113)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function md5(bytes) { - if (Array.isArray(bytes)) { - bytes = Buffer.from(bytes); - } else if (typeof bytes === 'string') { - bytes = Buffer.from(bytes, 'utf8'); - } - - return _crypto.default.createHash('md5').update(bytes).digest(); -} - -var _default = md5; -exports["default"] = _default; - -/***/ }), - -/***/ 2162: -/***/ ((__unused_webpack_module, exports) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; -var _default = '00000000-0000-0000-0000-000000000000'; -exports["default"] = _default; - -/***/ }), - -/***/ 861: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _validate = _interopRequireDefault(__nccwpck_require__(6192)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function parse(uuid) { - if (!(0, _validate.default)(uuid)) { - throw TypeError('Invalid UUID'); - } - - let v; - const arr = new Uint8Array(16); // Parse ########-....-....-....-............ - - arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; - arr[1] = v >>> 16 & 0xff; - arr[2] = v >>> 8 & 0xff; - arr[3] = v & 0xff; // Parse ........-####-....-....-............ - - arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; - arr[5] = v & 0xff; // Parse ........-....-####-....-............ - - arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; - arr[7] = v & 0xff; // Parse ........-....-....-####-............ - - arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; - arr[9] = v & 0xff; // Parse ........-....-....-....-############ - // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) - - arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; - arr[11] = v / 0x100000000 & 0xff; - arr[12] = v >>> 24 & 0xff; - arr[13] = v >>> 16 & 0xff; - arr[14] = v >>> 8 & 0xff; - arr[15] = v & 0xff; - return arr; -} - -var _default = parse; -exports["default"] = _default; - -/***/ }), - -/***/ 4003: -/***/ ((__unused_webpack_module, exports) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; -var _default = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; -exports["default"] = _default; - -/***/ }), - -/***/ 8795: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = rng; - -var _crypto = _interopRequireDefault(__nccwpck_require__(6113)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -const rnds8Pool = new Uint8Array(256); // # of random values to pre-allocate - -let poolPtr = rnds8Pool.length; - -function rng() { - if (poolPtr > rnds8Pool.length - 16) { - _crypto.default.randomFillSync(rnds8Pool); - - poolPtr = 0; - } - - return rnds8Pool.slice(poolPtr, poolPtr += 16); -} - -/***/ }), - -/***/ 3899: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _crypto = _interopRequireDefault(__nccwpck_require__(6113)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function sha1(bytes) { - if (Array.isArray(bytes)) { - bytes = Buffer.from(bytes); - } else if (typeof bytes === 'string') { - bytes = Buffer.from(bytes, 'utf8'); - } - - return _crypto.default.createHash('sha1').update(bytes).digest(); -} - -var _default = sha1; -exports["default"] = _default; - -/***/ }), - -/***/ 5354: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _validate = _interopRequireDefault(__nccwpck_require__(6192)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -/** - * Convert array of 16 byte values to UUID string format of the form: - * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX - */ -const byteToHex = []; - -for (let i = 0; i < 256; ++i) { - byteToHex.push((i + 0x100).toString(16).substr(1)); -} - -function stringify(arr, offset = 0) { - // Note: Be careful editing this code! It's been tuned for performance - // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 - const uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one - // of the following: - // - One or more input array values don't map to a hex octet (leading to - // "undefined" in the uuid) - // - Invalid input values for the RFC `version` or `variant` fields - - if (!(0, _validate.default)(uuid)) { - throw TypeError('Stringified UUID is invalid'); - } - - return uuid; -} - -var _default = stringify; -exports["default"] = _default; - -/***/ }), - -/***/ 2078: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _rng = _interopRequireDefault(__nccwpck_require__(8795)); - -var _stringify = _interopRequireDefault(__nccwpck_require__(5354)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -// **`v1()` - Generate time-based UUID** -// -// Inspired by https://github.com/LiosK/UUID.js -// and http://docs.python.org/library/uuid.html -let _nodeId; - -let _clockseq; // Previous uuid creation time - - -let _lastMSecs = 0; -let _lastNSecs = 0; // See https://github.com/uuidjs/uuid for API details - -function v1(options, buf, offset) { - let i = buf && offset || 0; - const b = buf || new Array(16); - options = options || {}; - let node = options.node || _nodeId; - let clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq; // node and clockseq need to be initialized to random values if they're not - // specified. We do this lazily to minimize issues related to insufficient - // system entropy. See #189 - - if (node == null || clockseq == null) { - const seedBytes = options.random || (options.rng || _rng.default)(); - - if (node == null) { - // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) - node = _nodeId = [seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]]; - } - - if (clockseq == null) { - // Per 4.2.2, randomize (14 bit) clockseq - clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff; - } - } // UUID timestamps are 100 nano-second units since the Gregorian epoch, - // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so - // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs' - // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00. - - - let msecs = options.msecs !== undefined ? options.msecs : Date.now(); // Per 4.2.1.2, use count of uuid's generated during the current clock - // cycle to simulate higher resolution clock - - let nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1; // Time since last uuid creation (in msecs) - - const dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 10000; // Per 4.2.1.2, Bump clockseq on clock regression - - if (dt < 0 && options.clockseq === undefined) { - clockseq = clockseq + 1 & 0x3fff; - } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new - // time interval - - - if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) { - nsecs = 0; - } // Per 4.2.1.2 Throw error if too many uuids are requested - - - if (nsecs >= 10000) { - throw new Error("uuid.v1(): Can't create more than 10M uuids/sec"); - } - - _lastMSecs = msecs; - _lastNSecs = nsecs; - _clockseq = clockseq; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch - - msecs += 12219292800000; // `time_low` - - const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; - b[i++] = tl >>> 24 & 0xff; - b[i++] = tl >>> 16 & 0xff; - b[i++] = tl >>> 8 & 0xff; - b[i++] = tl & 0xff; // `time_mid` - - const tmh = msecs / 0x100000000 * 10000 & 0xfffffff; - b[i++] = tmh >>> 8 & 0xff; - b[i++] = tmh & 0xff; // `time_high_and_version` - - b[i++] = tmh >>> 24 & 0xf | 0x10; // include version - - b[i++] = tmh >>> 16 & 0xff; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) - - b[i++] = clockseq >>> 8 | 0x80; // `clock_seq_low` - - b[i++] = clockseq & 0xff; // `node` - - for (let n = 0; n < 6; ++n) { - b[i + n] = node[n]; - } - - return buf || (0, _stringify.default)(b); -} - -var _default = v1; -exports["default"] = _default; - -/***/ }), - -/***/ 7788: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _v = _interopRequireDefault(__nccwpck_require__(9629)); - -var _md = _interopRequireDefault(__nccwpck_require__(1755)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -const v3 = (0, _v.default)('v3', 0x30, _md.default); -var _default = v3; -exports["default"] = _default; - -/***/ }), - -/***/ 9629: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = _default; -exports.URL = exports.DNS = void 0; - -var _stringify = _interopRequireDefault(__nccwpck_require__(5354)); - -var _parse = _interopRequireDefault(__nccwpck_require__(861)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function stringToBytes(str) { - str = unescape(encodeURIComponent(str)); // UTF8 escape - - const bytes = []; - - for (let i = 0; i < str.length; ++i) { - bytes.push(str.charCodeAt(i)); - } - - return bytes; -} - -const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; -exports.DNS = DNS; -const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; -exports.URL = URL; - -function _default(name, version, hashfunc) { - function generateUUID(value, namespace, buf, offset) { - if (typeof value === 'string') { - value = stringToBytes(value); - } - - if (typeof namespace === 'string') { - namespace = (0, _parse.default)(namespace); - } - - if (namespace.length !== 16) { - throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); - } // Compute hash of namespace and value, Per 4.3 - // Future: Use spread syntax when supported on all platforms, e.g. `bytes = - // hashfunc([...namespace, ... value])` - - - let bytes = new Uint8Array(16 + value.length); - bytes.set(namespace); - bytes.set(value, namespace.length); - bytes = hashfunc(bytes); - bytes[6] = bytes[6] & 0x0f | version; - bytes[8] = bytes[8] & 0x3f | 0x80; - - if (buf) { - offset = offset || 0; - - for (let i = 0; i < 16; ++i) { - buf[offset + i] = bytes[i]; - } - - return buf; - } - - return (0, _stringify.default)(bytes); - } // Function#name is not settable on some platforms (#270) - - - try { - generateUUID.name = name; // eslint-disable-next-line no-empty - } catch (err) {} // For CommonJS default export support - - - generateUUID.DNS = DNS; - generateUUID.URL = URL; - return generateUUID; -} - -/***/ }), - -/***/ 4205: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _rng = _interopRequireDefault(__nccwpck_require__(8795)); - -var _stringify = _interopRequireDefault(__nccwpck_require__(5354)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function v4(options, buf, offset) { - options = options || {}; - - const rnds = options.random || (options.rng || _rng.default)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` - - - rnds[6] = rnds[6] & 0x0f | 0x40; - rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided - - if (buf) { - offset = offset || 0; - - for (let i = 0; i < 16; ++i) { - buf[offset + i] = rnds[i]; - } - - return buf; - } - - return (0, _stringify.default)(rnds); -} - -var _default = v4; -exports["default"] = _default; - -/***/ }), - -/***/ 2795: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _v = _interopRequireDefault(__nccwpck_require__(9629)); - -var _sha = _interopRequireDefault(__nccwpck_require__(3899)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -const v5 = (0, _v.default)('v5', 0x50, _sha.default); -var _default = v5; -exports["default"] = _default; - -/***/ }), - -/***/ 6192: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _regex = _interopRequireDefault(__nccwpck_require__(4003)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function validate(uuid) { - return typeof uuid === 'string' && _regex.default.test(uuid); -} - -var _default = validate; -exports["default"] = _default; - -/***/ }), - -/***/ 5315: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", ({ - value: true -})); -exports["default"] = void 0; - -var _validate = _interopRequireDefault(__nccwpck_require__(6192)); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function version(uuid) { - if (!(0, _validate.default)(uuid)) { - throw TypeError('Invalid UUID'); - } - - return parseInt(uuid.substr(14, 1), 16); -} - -var _default = version; -exports["default"] = _default; - -/***/ }), - -/***/ 9491: -/***/ ((module) => { - -"use strict"; -module.exports = require("assert"); - -/***/ }), - -/***/ 852: -/***/ ((module) => { - -"use strict"; -module.exports = require("async_hooks"); - -/***/ }), - -/***/ 4300: -/***/ ((module) => { - -"use strict"; -module.exports = require("buffer"); - -/***/ }), - -/***/ 6206: -/***/ ((module) => { - -"use strict"; -module.exports = require("console"); - -/***/ }), - -/***/ 6113: -/***/ ((module) => { - -"use strict"; -module.exports = require("crypto"); - -/***/ }), - -/***/ 7643: -/***/ ((module) => { - -"use strict"; -module.exports = require("diagnostics_channel"); - -/***/ }), - -/***/ 2361: -/***/ ((module) => { - -"use strict"; -module.exports = require("events"); - -/***/ }), - -/***/ 7147: -/***/ ((module) => { - -"use strict"; -module.exports = require("fs"); - -/***/ }), - -/***/ 3685: -/***/ ((module) => { - -"use strict"; -module.exports = require("http"); - -/***/ }), - -/***/ 5158: -/***/ ((module) => { - -"use strict"; -module.exports = require("http2"); - -/***/ }), - -/***/ 5687: -/***/ ((module) => { - -"use strict"; -module.exports = require("https"); - -/***/ }), - -/***/ 1808: -/***/ ((module) => { - -"use strict"; -module.exports = require("net"); - -/***/ }), - -/***/ 5673: -/***/ ((module) => { - -"use strict"; -module.exports = require("node:events"); - -/***/ }), - -/***/ 4492: -/***/ ((module) => { - -"use strict"; -module.exports = require("node:stream"); - -/***/ }), - -/***/ 7261: -/***/ ((module) => { - -"use strict"; -module.exports = require("node:util"); - -/***/ }), - -/***/ 2037: -/***/ ((module) => { - -"use strict"; -module.exports = require("os"); - -/***/ }), - -/***/ 1017: -/***/ ((module) => { - -"use strict"; -module.exports = require("path"); - -/***/ }), - -/***/ 4074: -/***/ ((module) => { - -"use strict"; -module.exports = require("perf_hooks"); - -/***/ }), - -/***/ 3477: -/***/ ((module) => { - -"use strict"; -module.exports = require("querystring"); - -/***/ }), - -/***/ 2781: -/***/ ((module) => { - -"use strict"; -module.exports = require("stream"); - -/***/ }), - -/***/ 5356: -/***/ ((module) => { - -"use strict"; -module.exports = require("stream/web"); - -/***/ }), - -/***/ 1576: -/***/ ((module) => { - -"use strict"; -module.exports = require("string_decoder"); - -/***/ }), - -/***/ 4404: -/***/ ((module) => { - -"use strict"; -module.exports = require("tls"); - -/***/ }), - -/***/ 7310: -/***/ ((module) => { - -"use strict"; -module.exports = require("url"); - -/***/ }), - -/***/ 3837: -/***/ ((module) => { - -"use strict"; -module.exports = require("util"); - -/***/ }), - -/***/ 9830: -/***/ ((module) => { - -"use strict"; -module.exports = require("util/types"); - -/***/ }), - -/***/ 1267: -/***/ ((module) => { - -"use strict"; -module.exports = require("worker_threads"); - -/***/ }), - -/***/ 9796: -/***/ ((module) => { - -"use strict"; -module.exports = require("zlib"); - -/***/ }), - -/***/ 3186: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const WritableStream = (__nccwpck_require__(4492).Writable) -const inherits = (__nccwpck_require__(7261).inherits) - -const StreamSearch = __nccwpck_require__(3331) - -const PartStream = __nccwpck_require__(5785) -const HeaderParser = __nccwpck_require__(8981) - -const DASH = 45 -const B_ONEDASH = Buffer.from('-') -const B_CRLF = Buffer.from('\r\n') -const EMPTY_FN = function () {} - -function Dicer (cfg) { - if (!(this instanceof Dicer)) { return new Dicer(cfg) } - WritableStream.call(this, cfg) - - if (!cfg || (!cfg.headerFirst && typeof cfg.boundary !== 'string')) { throw new TypeError('Boundary required') } - - if (typeof cfg.boundary === 'string') { this.setBoundary(cfg.boundary) } else { this._bparser = undefined } - - this._headerFirst = cfg.headerFirst - - this._dashes = 0 - this._parts = 0 - this._finished = false - this._realFinish = false - this._isPreamble = true - this._justMatched = false - this._firstWrite = true - this._inHeader = true - this._part = undefined - this._cb = undefined - this._ignoreData = false - this._partOpts = { highWaterMark: cfg.partHwm } - this._pause = false - - const self = this - this._hparser = new HeaderParser(cfg) - this._hparser.on('header', function (header) { - self._inHeader = false - self._part.emit('header', header) - }) -} -inherits(Dicer, WritableStream) - -Dicer.prototype.emit = function (ev) { - if (ev === 'finish' && !this._realFinish) { - if (!this._finished) { - const self = this - process.nextTick(function () { - self.emit('error', new Error('Unexpected end of multipart data')) - if (self._part && !self._ignoreData) { - const type = (self._isPreamble ? 'Preamble' : 'Part') - self._part.emit('error', new Error(type + ' terminated early due to unexpected end of multipart data')) - self._part.push(null) - process.nextTick(function () { - self._realFinish = true - self.emit('finish') - self._realFinish = false - }) - return - } - self._realFinish = true - self.emit('finish') - self._realFinish = false - }) - } - } else { WritableStream.prototype.emit.apply(this, arguments) } -} - -Dicer.prototype._write = function (data, encoding, cb) { - // ignore unexpected data (e.g. extra trailer data after finished) - if (!this._hparser && !this._bparser) { return cb() } - - if (this._headerFirst && this._isPreamble) { - if (!this._part) { - this._part = new PartStream(this._partOpts) - if (this._events.preamble) { this.emit('preamble', this._part) } else { this._ignore() } - } - const r = this._hparser.push(data) - if (!this._inHeader && r !== undefined && r < data.length) { data = data.slice(r) } else { return cb() } - } - - // allows for "easier" testing - if (this._firstWrite) { - this._bparser.push(B_CRLF) - this._firstWrite = false - } - - this._bparser.push(data) - - if (this._pause) { this._cb = cb } else { cb() } -} - -Dicer.prototype.reset = function () { - this._part = undefined - this._bparser = undefined - this._hparser = undefined -} - -Dicer.prototype.setBoundary = function (boundary) { - const self = this - this._bparser = new StreamSearch('\r\n--' + boundary) - this._bparser.on('info', function (isMatch, data, start, end) { - self._oninfo(isMatch, data, start, end) - }) -} - -Dicer.prototype._ignore = function () { - if (this._part && !this._ignoreData) { - this._ignoreData = true - this._part.on('error', EMPTY_FN) - // we must perform some kind of read on the stream even though we are - // ignoring the data, otherwise node's Readable stream will not emit 'end' - // after pushing null to the stream - this._part.resume() - } -} - -Dicer.prototype._oninfo = function (isMatch, data, start, end) { - let buf; const self = this; let i = 0; let r; let shouldWriteMore = true - - if (!this._part && this._justMatched && data) { - while (this._dashes < 2 && (start + i) < end) { - if (data[start + i] === DASH) { - ++i - ++this._dashes - } else { - if (this._dashes) { buf = B_ONEDASH } - this._dashes = 0 - break - } - } - if (this._dashes === 2) { - if ((start + i) < end && this._events.trailer) { this.emit('trailer', data.slice(start + i, end)) } - this.reset() - this._finished = true - // no more parts will be added - if (self._parts === 0) { - self._realFinish = true - self.emit('finish') - self._realFinish = false - } - } - if (this._dashes) { return } - } - if (this._justMatched) { this._justMatched = false } - if (!this._part) { - this._part = new PartStream(this._partOpts) - this._part._read = function (n) { - self._unpause() - } - if (this._isPreamble && this._events.preamble) { this.emit('preamble', this._part) } else if (this._isPreamble !== true && this._events.part) { this.emit('part', this._part) } else { this._ignore() } - if (!this._isPreamble) { this._inHeader = true } - } - if (data && start < end && !this._ignoreData) { - if (this._isPreamble || !this._inHeader) { - if (buf) { shouldWriteMore = this._part.push(buf) } - shouldWriteMore = this._part.push(data.slice(start, end)) - if (!shouldWriteMore) { this._pause = true } - } else if (!this._isPreamble && this._inHeader) { - if (buf) { this._hparser.push(buf) } - r = this._hparser.push(data.slice(start, end)) - if (!this._inHeader && r !== undefined && r < end) { this._oninfo(false, data, start + r, end) } - } - } - if (isMatch) { - this._hparser.reset() - if (this._isPreamble) { this._isPreamble = false } else { - if (start !== end) { - ++this._parts - this._part.on('end', function () { - if (--self._parts === 0) { - if (self._finished) { - self._realFinish = true - self.emit('finish') - self._realFinish = false - } else { - self._unpause() - } - } - }) - } - } - this._part.push(null) - this._part = undefined - this._ignoreData = false - this._justMatched = true - this._dashes = 0 - } -} - -Dicer.prototype._unpause = function () { - if (!this._pause) { return } - - this._pause = false - if (this._cb) { - const cb = this._cb - this._cb = undefined - cb() - } -} - -module.exports = Dicer - - -/***/ }), - -/***/ 8981: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const EventEmitter = (__nccwpck_require__(5673).EventEmitter) -const inherits = (__nccwpck_require__(7261).inherits) -const getLimit = __nccwpck_require__(4323) - -const StreamSearch = __nccwpck_require__(3331) - -const B_DCRLF = Buffer.from('\r\n\r\n') -const RE_CRLF = /\r\n/g -const RE_HDR = /^([^:]+):[ \t]?([\x00-\xFF]+)?$/ // eslint-disable-line no-control-regex - -function HeaderParser (cfg) { - EventEmitter.call(this) - - cfg = cfg || {} - const self = this - this.nread = 0 - this.maxed = false - this.npairs = 0 - this.maxHeaderPairs = getLimit(cfg, 'maxHeaderPairs', 2000) - this.maxHeaderSize = getLimit(cfg, 'maxHeaderSize', 80 * 1024) - this.buffer = '' - this.header = {} - this.finished = false - this.ss = new StreamSearch(B_DCRLF) - this.ss.on('info', function (isMatch, data, start, end) { - if (data && !self.maxed) { - if (self.nread + end - start >= self.maxHeaderSize) { - end = self.maxHeaderSize - self.nread + start - self.nread = self.maxHeaderSize - self.maxed = true - } else { self.nread += (end - start) } - - self.buffer += data.toString('binary', start, end) - } - if (isMatch) { self._finish() } - }) -} -inherits(HeaderParser, EventEmitter) - -HeaderParser.prototype.push = function (data) { - const r = this.ss.push(data) - if (this.finished) { return r } -} - -HeaderParser.prototype.reset = function () { - this.finished = false - this.buffer = '' - this.header = {} - this.ss.reset() -} - -HeaderParser.prototype._finish = function () { - if (this.buffer) { this._parseHeader() } - this.ss.matches = this.ss.maxMatches - const header = this.header - this.header = {} - this.buffer = '' - this.finished = true - this.nread = this.npairs = 0 - this.maxed = false - this.emit('header', header) -} - -HeaderParser.prototype._parseHeader = function () { - if (this.npairs === this.maxHeaderPairs) { return } - - const lines = this.buffer.split(RE_CRLF) - const len = lines.length - let m, h - - for (var i = 0; i < len; ++i) { // eslint-disable-line no-var - if (lines[i].length === 0) { continue } - if (lines[i][0] === '\t' || lines[i][0] === ' ') { - // folded header content - // RFC2822 says to just remove the CRLF and not the whitespace following - // it, so we follow the RFC and include the leading whitespace ... - if (h) { - this.header[h][this.header[h].length - 1] += lines[i] - continue - } - } - - const posColon = lines[i].indexOf(':') - if ( - posColon === -1 || - posColon === 0 - ) { - return - } - m = RE_HDR.exec(lines[i]) - h = m[1].toLowerCase() - this.header[h] = this.header[h] || [] - this.header[h].push((m[2] || '')) - if (++this.npairs === this.maxHeaderPairs) { break } - } -} - -module.exports = HeaderParser - - -/***/ }), - -/***/ 5785: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const inherits = (__nccwpck_require__(7261).inherits) -const ReadableStream = (__nccwpck_require__(4492).Readable) - -function PartStream (opts) { - ReadableStream.call(this, opts) -} -inherits(PartStream, ReadableStream) - -PartStream.prototype._read = function (n) {} - -module.exports = PartStream - - -/***/ }), - -/***/ 3331: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -/** - * Copyright Brian White. All rights reserved. - * - * @see https://github.com/mscdex/streamsearch - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Based heavily on the Streaming Boyer-Moore-Horspool C++ implementation - * by Hongli Lai at: https://github.com/FooBarWidget/boyer-moore-horspool - */ -const EventEmitter = (__nccwpck_require__(5673).EventEmitter) -const inherits = (__nccwpck_require__(7261).inherits) - -function SBMH (needle) { - if (typeof needle === 'string') { - needle = Buffer.from(needle) - } - - if (!Buffer.isBuffer(needle)) { - throw new TypeError('The needle has to be a String or a Buffer.') - } - - const needleLength = needle.length - - if (needleLength === 0) { - throw new Error('The needle cannot be an empty String/Buffer.') - } - - if (needleLength > 256) { - throw new Error('The needle cannot have a length bigger than 256.') - } - - this.maxMatches = Infinity - this.matches = 0 - - this._occ = new Array(256) - .fill(needleLength) // Initialize occurrence table. - this._lookbehind_size = 0 - this._needle = needle - this._bufpos = 0 - - this._lookbehind = Buffer.alloc(needleLength) - - // Populate occurrence table with analysis of the needle, - // ignoring last letter. - for (var i = 0; i < needleLength - 1; ++i) { // eslint-disable-line no-var - this._occ[needle[i]] = needleLength - 1 - i - } -} -inherits(SBMH, EventEmitter) - -SBMH.prototype.reset = function () { - this._lookbehind_size = 0 - this.matches = 0 - this._bufpos = 0 -} - -SBMH.prototype.push = function (chunk, pos) { - if (!Buffer.isBuffer(chunk)) { - chunk = Buffer.from(chunk, 'binary') - } - const chlen = chunk.length - this._bufpos = pos || 0 - let r - while (r !== chlen && this.matches < this.maxMatches) { r = this._sbmh_feed(chunk) } - return r -} - -SBMH.prototype._sbmh_feed = function (data) { - const len = data.length - const needle = this._needle - const needleLength = needle.length - const lastNeedleChar = needle[needleLength - 1] - - // Positive: points to a position in `data` - // pos == 3 points to data[3] - // Negative: points to a position in the lookbehind buffer - // pos == -2 points to lookbehind[lookbehind_size - 2] - let pos = -this._lookbehind_size - let ch - - if (pos < 0) { - // Lookbehind buffer is not empty. Perform Boyer-Moore-Horspool - // search with character lookup code that considers both the - // lookbehind buffer and the current round's haystack data. - // - // Loop until - // there is a match. - // or until - // we've moved past the position that requires the - // lookbehind buffer. In this case we switch to the - // optimized loop. - // or until - // the character to look at lies outside the haystack. - while (pos < 0 && pos <= len - needleLength) { - ch = this._sbmh_lookup_char(data, pos + needleLength - 1) - - if ( - ch === lastNeedleChar && - this._sbmh_memcmp(data, pos, needleLength - 1) - ) { - this._lookbehind_size = 0 - ++this.matches - this.emit('info', true) - - return (this._bufpos = pos + needleLength) - } - pos += this._occ[ch] - } - - // No match. - - if (pos < 0) { - // There's too few data for Boyer-Moore-Horspool to run, - // so let's use a different algorithm to skip as much as - // we can. - // Forward pos until - // the trailing part of lookbehind + data - // looks like the beginning of the needle - // or until - // pos == 0 - while (pos < 0 && !this._sbmh_memcmp(data, pos, len - pos)) { ++pos } - } - - if (pos >= 0) { - // Discard lookbehind buffer. - this.emit('info', false, this._lookbehind, 0, this._lookbehind_size) - this._lookbehind_size = 0 - } else { - // Cut off part of the lookbehind buffer that has - // been processed and append the entire haystack - // into it. - const bytesToCutOff = this._lookbehind_size + pos - if (bytesToCutOff > 0) { - // The cut off data is guaranteed not to contain the needle. - this.emit('info', false, this._lookbehind, 0, bytesToCutOff) - } - - this._lookbehind.copy(this._lookbehind, 0, bytesToCutOff, - this._lookbehind_size - bytesToCutOff) - this._lookbehind_size -= bytesToCutOff - - data.copy(this._lookbehind, this._lookbehind_size) - this._lookbehind_size += len - - this._bufpos = len - return len - } - } - - pos += (pos >= 0) * this._bufpos - - // Lookbehind buffer is now empty. We only need to check if the - // needle is in the haystack. - if (data.indexOf(needle, pos) !== -1) { - pos = data.indexOf(needle, pos) - ++this.matches - if (pos > 0) { this.emit('info', true, data, this._bufpos, pos) } else { this.emit('info', true) } - - return (this._bufpos = pos + needleLength) - } else { - pos = len - needleLength - } - - // There was no match. If there's trailing haystack data that we cannot - // match yet using the Boyer-Moore-Horspool algorithm (because the trailing - // data is less than the needle size) then match using a modified - // algorithm that starts matching from the beginning instead of the end. - // Whatever trailing data is left after running this algorithm is added to - // the lookbehind buffer. - while ( - pos < len && - ( - data[pos] !== needle[0] || - ( - (Buffer.compare( - data.subarray(pos, pos + len - pos), - needle.subarray(0, len - pos) - ) !== 0) - ) - ) - ) { - ++pos - } - if (pos < len) { - data.copy(this._lookbehind, 0, pos, pos + (len - pos)) - this._lookbehind_size = len - pos - } - - // Everything until pos is guaranteed not to contain needle data. - if (pos > 0) { this.emit('info', false, data, this._bufpos, pos < len ? pos : len) } - - this._bufpos = len - return len -} - -SBMH.prototype._sbmh_lookup_char = function (data, pos) { - return (pos < 0) - ? this._lookbehind[this._lookbehind_size + pos] - : data[pos] -} - -SBMH.prototype._sbmh_memcmp = function (data, pos, len) { - for (var i = 0; i < len; ++i) { // eslint-disable-line no-var - if (this._sbmh_lookup_char(data, pos + i) !== this._needle[i]) { return false } - } - return true -} - -module.exports = SBMH - - -/***/ }), - -/***/ 1702: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const WritableStream = (__nccwpck_require__(4492).Writable) -const { inherits } = __nccwpck_require__(7261) -const Dicer = __nccwpck_require__(3186) - -const MultipartParser = __nccwpck_require__(7435) -const UrlencodedParser = __nccwpck_require__(8604) -const parseParams = __nccwpck_require__(2693) - -function Busboy (opts) { - if (!(this instanceof Busboy)) { return new Busboy(opts) } - - if (typeof opts !== 'object') { - throw new TypeError('Busboy expected an options-Object.') - } - if (typeof opts.headers !== 'object') { - throw new TypeError('Busboy expected an options-Object with headers-attribute.') - } - if (typeof opts.headers['content-type'] !== 'string') { - throw new TypeError('Missing Content-Type-header.') - } - - const { - headers, - ...streamOptions - } = opts - - this.opts = { - autoDestroy: false, - ...streamOptions - } - WritableStream.call(this, this.opts) - - this._done = false - this._parser = this.getParserByHeaders(headers) - this._finished = false -} -inherits(Busboy, WritableStream) - -Busboy.prototype.emit = function (ev) { - if (ev === 'finish') { - if (!this._done) { - this._parser?.end() - return - } else if (this._finished) { - return - } - this._finished = true - } - WritableStream.prototype.emit.apply(this, arguments) -} - -Busboy.prototype.getParserByHeaders = function (headers) { - const parsed = parseParams(headers['content-type']) - - const cfg = { - defCharset: this.opts.defCharset, - fileHwm: this.opts.fileHwm, - headers, - highWaterMark: this.opts.highWaterMark, - isPartAFile: this.opts.isPartAFile, - limits: this.opts.limits, - parsedConType: parsed, - preservePath: this.opts.preservePath - } - - if (MultipartParser.detect.test(parsed[0])) { - return new MultipartParser(this, cfg) - } - if (UrlencodedParser.detect.test(parsed[0])) { - return new UrlencodedParser(this, cfg) - } - throw new Error('Unsupported Content-Type.') -} - -Busboy.prototype._write = function (chunk, encoding, cb) { - this._parser.write(chunk, cb) -} - -module.exports = Busboy -module.exports["default"] = Busboy -module.exports.Busboy = Busboy - -module.exports.Dicer = Dicer - - -/***/ }), - -/***/ 7435: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -// TODO: -// * support 1 nested multipart level -// (see second multipart example here: -// http://www.w3.org/TR/html401/interact/forms.html#didx-multipartform-data) -// * support limits.fieldNameSize -// -- this will require modifications to utils.parseParams - -const { Readable } = __nccwpck_require__(4492) -const { inherits } = __nccwpck_require__(7261) - -const Dicer = __nccwpck_require__(3186) - -const parseParams = __nccwpck_require__(2693) -const decodeText = __nccwpck_require__(9464) -const basename = __nccwpck_require__(1628) -const getLimit = __nccwpck_require__(4323) - -const RE_BOUNDARY = /^boundary$/i -const RE_FIELD = /^form-data$/i -const RE_CHARSET = /^charset$/i -const RE_FILENAME = /^filename$/i -const RE_NAME = /^name$/i - -Multipart.detect = /^multipart\/form-data/i -function Multipart (boy, cfg) { - let i - let len - const self = this - let boundary - const limits = cfg.limits - const isPartAFile = cfg.isPartAFile || ((fieldName, contentType, fileName) => (contentType === 'application/octet-stream' || fileName !== undefined)) - const parsedConType = cfg.parsedConType || [] - const defCharset = cfg.defCharset || 'utf8' - const preservePath = cfg.preservePath - const fileOpts = { highWaterMark: cfg.fileHwm } - - for (i = 0, len = parsedConType.length; i < len; ++i) { - if (Array.isArray(parsedConType[i]) && - RE_BOUNDARY.test(parsedConType[i][0])) { - boundary = parsedConType[i][1] - break - } - } - - function checkFinished () { - if (nends === 0 && finished && !boy._done) { - finished = false - self.end() - } - } - - if (typeof boundary !== 'string') { throw new Error('Multipart: Boundary not found') } - - const fieldSizeLimit = getLimit(limits, 'fieldSize', 1 * 1024 * 1024) - const fileSizeLimit = getLimit(limits, 'fileSize', Infinity) - const filesLimit = getLimit(limits, 'files', Infinity) - const fieldsLimit = getLimit(limits, 'fields', Infinity) - const partsLimit = getLimit(limits, 'parts', Infinity) - const headerPairsLimit = getLimit(limits, 'headerPairs', 2000) - const headerSizeLimit = getLimit(limits, 'headerSize', 80 * 1024) - - let nfiles = 0 - let nfields = 0 - let nends = 0 - let curFile - let curField - let finished = false - - this._needDrain = false - this._pause = false - this._cb = undefined - this._nparts = 0 - this._boy = boy - - const parserCfg = { - boundary, - maxHeaderPairs: headerPairsLimit, - maxHeaderSize: headerSizeLimit, - partHwm: fileOpts.highWaterMark, - highWaterMark: cfg.highWaterMark - } - - this.parser = new Dicer(parserCfg) - this.parser.on('drain', function () { - self._needDrain = false - if (self._cb && !self._pause) { - const cb = self._cb - self._cb = undefined - cb() - } - }).on('part', function onPart (part) { - if (++self._nparts > partsLimit) { - self.parser.removeListener('part', onPart) - self.parser.on('part', skipPart) - boy.hitPartsLimit = true - boy.emit('partsLimit') - return skipPart(part) - } - - // hack because streams2 _always_ doesn't emit 'end' until nextTick, so let - // us emit 'end' early since we know the part has ended if we are already - // seeing the next part - if (curField) { - const field = curField - field.emit('end') - field.removeAllListeners('end') - } - - part.on('header', function (header) { - let contype - let fieldname - let parsed - let charset - let encoding - let filename - let nsize = 0 - - if (header['content-type']) { - parsed = parseParams(header['content-type'][0]) - if (parsed[0]) { - contype = parsed[0].toLowerCase() - for (i = 0, len = parsed.length; i < len; ++i) { - if (RE_CHARSET.test(parsed[i][0])) { - charset = parsed[i][1].toLowerCase() - break - } - } - } - } - - if (contype === undefined) { contype = 'text/plain' } - if (charset === undefined) { charset = defCharset } - - if (header['content-disposition']) { - parsed = parseParams(header['content-disposition'][0]) - if (!RE_FIELD.test(parsed[0])) { return skipPart(part) } - for (i = 0, len = parsed.length; i < len; ++i) { - if (RE_NAME.test(parsed[i][0])) { - fieldname = parsed[i][1] - } else if (RE_FILENAME.test(parsed[i][0])) { - filename = parsed[i][1] - if (!preservePath) { filename = basename(filename) } - } - } - } else { return skipPart(part) } - - if (header['content-transfer-encoding']) { encoding = header['content-transfer-encoding'][0].toLowerCase() } else { encoding = '7bit' } - - let onData, - onEnd - - if (isPartAFile(fieldname, contype, filename)) { - // file/binary field - if (nfiles === filesLimit) { - if (!boy.hitFilesLimit) { - boy.hitFilesLimit = true - boy.emit('filesLimit') - } - return skipPart(part) - } - - ++nfiles - - if (!boy._events.file) { - self.parser._ignore() - return - } - - ++nends - const file = new FileStream(fileOpts) - curFile = file - file.on('end', function () { - --nends - self._pause = false - checkFinished() - if (self._cb && !self._needDrain) { - const cb = self._cb - self._cb = undefined - cb() - } - }) - file._read = function (n) { - if (!self._pause) { return } - self._pause = false - if (self._cb && !self._needDrain) { - const cb = self._cb - self._cb = undefined - cb() - } - } - boy.emit('file', fieldname, file, filename, encoding, contype) - - onData = function (data) { - if ((nsize += data.length) > fileSizeLimit) { - const extralen = fileSizeLimit - nsize + data.length - if (extralen > 0) { file.push(data.slice(0, extralen)) } - file.truncated = true - file.bytesRead = fileSizeLimit - part.removeAllListeners('data') - file.emit('limit') - return - } else if (!file.push(data)) { self._pause = true } - - file.bytesRead = nsize - } - - onEnd = function () { - curFile = undefined - file.push(null) - } - } else { - // non-file field - if (nfields === fieldsLimit) { - if (!boy.hitFieldsLimit) { - boy.hitFieldsLimit = true - boy.emit('fieldsLimit') - } - return skipPart(part) - } - - ++nfields - ++nends - let buffer = '' - let truncated = false - curField = part - - onData = function (data) { - if ((nsize += data.length) > fieldSizeLimit) { - const extralen = (fieldSizeLimit - (nsize - data.length)) - buffer += data.toString('binary', 0, extralen) - truncated = true - part.removeAllListeners('data') - } else { buffer += data.toString('binary') } - } - - onEnd = function () { - curField = undefined - if (buffer.length) { buffer = decodeText(buffer, 'binary', charset) } - boy.emit('field', fieldname, buffer, false, truncated, encoding, contype) - --nends - checkFinished() - } - } - - /* As of node@2efe4ab761666 (v0.10.29+/v0.11.14+), busboy had become - broken. Streams2/streams3 is a huge black box of confusion, but - somehow overriding the sync state seems to fix things again (and still - seems to work for previous node versions). - */ - part._readableState.sync = false - - part.on('data', onData) - part.on('end', onEnd) - }).on('error', function (err) { - if (curFile) { curFile.emit('error', err) } - }) - }).on('error', function (err) { - boy.emit('error', err) - }).on('finish', function () { - finished = true - checkFinished() - }) -} - -Multipart.prototype.write = function (chunk, cb) { - const r = this.parser.write(chunk) - if (r && !this._pause) { - cb() - } else { - this._needDrain = !r - this._cb = cb - } -} - -Multipart.prototype.end = function () { - const self = this - - if (self.parser.writable) { - self.parser.end() - } else if (!self._boy._done) { - process.nextTick(function () { - self._boy._done = true - self._boy.emit('finish') - }) - } -} - -function skipPart (part) { - part.resume() -} - -function FileStream (opts) { - Readable.call(this, opts) - - this.bytesRead = 0 - - this.truncated = false -} - -inherits(FileStream, Readable) - -FileStream.prototype._read = function (n) {} - -module.exports = Multipart - - -/***/ }), - -/***/ 8604: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const Decoder = __nccwpck_require__(8660) -const decodeText = __nccwpck_require__(9464) -const getLimit = __nccwpck_require__(4323) - -const RE_CHARSET = /^charset$/i - -UrlEncoded.detect = /^application\/x-www-form-urlencoded/i -function UrlEncoded (boy, cfg) { - const limits = cfg.limits - const parsedConType = cfg.parsedConType - this.boy = boy - - this.fieldSizeLimit = getLimit(limits, 'fieldSize', 1 * 1024 * 1024) - this.fieldNameSizeLimit = getLimit(limits, 'fieldNameSize', 100) - this.fieldsLimit = getLimit(limits, 'fields', Infinity) - - let charset - for (var i = 0, len = parsedConType.length; i < len; ++i) { // eslint-disable-line no-var - if (Array.isArray(parsedConType[i]) && - RE_CHARSET.test(parsedConType[i][0])) { - charset = parsedConType[i][1].toLowerCase() - break - } - } - - if (charset === undefined) { charset = cfg.defCharset || 'utf8' } - - this.decoder = new Decoder() - this.charset = charset - this._fields = 0 - this._state = 'key' - this._checkingBytes = true - this._bytesKey = 0 - this._bytesVal = 0 - this._key = '' - this._val = '' - this._keyTrunc = false - this._valTrunc = false - this._hitLimit = false -} - -UrlEncoded.prototype.write = function (data, cb) { - if (this._fields === this.fieldsLimit) { - if (!this.boy.hitFieldsLimit) { - this.boy.hitFieldsLimit = true - this.boy.emit('fieldsLimit') - } - return cb() - } - - let idxeq; let idxamp; let i; let p = 0; const len = data.length - - while (p < len) { - if (this._state === 'key') { - idxeq = idxamp = undefined - for (i = p; i < len; ++i) { - if (!this._checkingBytes) { ++p } - if (data[i] === 0x3D/* = */) { - idxeq = i - break - } else if (data[i] === 0x26/* & */) { - idxamp = i - break - } - if (this._checkingBytes && this._bytesKey === this.fieldNameSizeLimit) { - this._hitLimit = true - break - } else if (this._checkingBytes) { ++this._bytesKey } - } - - if (idxeq !== undefined) { - // key with assignment - if (idxeq > p) { this._key += this.decoder.write(data.toString('binary', p, idxeq)) } - this._state = 'val' - - this._hitLimit = false - this._checkingBytes = true - this._val = '' - this._bytesVal = 0 - this._valTrunc = false - this.decoder.reset() - - p = idxeq + 1 - } else if (idxamp !== undefined) { - // key with no assignment - ++this._fields - let key; const keyTrunc = this._keyTrunc - if (idxamp > p) { key = (this._key += this.decoder.write(data.toString('binary', p, idxamp))) } else { key = this._key } - - this._hitLimit = false - this._checkingBytes = true - this._key = '' - this._bytesKey = 0 - this._keyTrunc = false - this.decoder.reset() - - if (key.length) { - this.boy.emit('field', decodeText(key, 'binary', this.charset), - '', - keyTrunc, - false) - } - - p = idxamp + 1 - if (this._fields === this.fieldsLimit) { return cb() } - } else if (this._hitLimit) { - // we may not have hit the actual limit if there are encoded bytes... - if (i > p) { this._key += this.decoder.write(data.toString('binary', p, i)) } - p = i - if ((this._bytesKey = this._key.length) === this.fieldNameSizeLimit) { - // yep, we actually did hit the limit - this._checkingBytes = false - this._keyTrunc = true - } - } else { - if (p < len) { this._key += this.decoder.write(data.toString('binary', p)) } - p = len - } - } else { - idxamp = undefined - for (i = p; i < len; ++i) { - if (!this._checkingBytes) { ++p } - if (data[i] === 0x26/* & */) { - idxamp = i - break - } - if (this._checkingBytes && this._bytesVal === this.fieldSizeLimit) { - this._hitLimit = true - break - } else if (this._checkingBytes) { ++this._bytesVal } - } - - if (idxamp !== undefined) { - ++this._fields - if (idxamp > p) { this._val += this.decoder.write(data.toString('binary', p, idxamp)) } - this.boy.emit('field', decodeText(this._key, 'binary', this.charset), - decodeText(this._val, 'binary', this.charset), - this._keyTrunc, - this._valTrunc) - this._state = 'key' - - this._hitLimit = false - this._checkingBytes = true - this._key = '' - this._bytesKey = 0 - this._keyTrunc = false - this.decoder.reset() - - p = idxamp + 1 - if (this._fields === this.fieldsLimit) { return cb() } - } else if (this._hitLimit) { - // we may not have hit the actual limit if there are encoded bytes... - if (i > p) { this._val += this.decoder.write(data.toString('binary', p, i)) } - p = i - if ((this._val === '' && this.fieldSizeLimit === 0) || - (this._bytesVal = this._val.length) === this.fieldSizeLimit) { - // yep, we actually did hit the limit - this._checkingBytes = false - this._valTrunc = true - } - } else { - if (p < len) { this._val += this.decoder.write(data.toString('binary', p)) } - p = len - } - } - } - cb() -} - -UrlEncoded.prototype.end = function () { - if (this.boy._done) { return } - - if (this._state === 'key' && this._key.length > 0) { - this.boy.emit('field', decodeText(this._key, 'binary', this.charset), - '', - this._keyTrunc, - false) - } else if (this._state === 'val') { - this.boy.emit('field', decodeText(this._key, 'binary', this.charset), - decodeText(this._val, 'binary', this.charset), - this._keyTrunc, - this._valTrunc) - } - this.boy._done = true - this.boy.emit('finish') -} - -module.exports = UrlEncoded - - -/***/ }), - -/***/ 8660: -/***/ ((module) => { - -"use strict"; - - -const RE_PLUS = /\+/g - -const HEX = [ - 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 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, 1, 1, 1, 1, 1, 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 -] - -function Decoder () { - this.buffer = undefined -} -Decoder.prototype.write = function (str) { - // Replace '+' with ' ' before decoding - str = str.replace(RE_PLUS, ' ') - let res = '' - let i = 0; let p = 0; const len = str.length - for (; i < len; ++i) { - if (this.buffer !== undefined) { - if (!HEX[str.charCodeAt(i)]) { - res += '%' + this.buffer - this.buffer = undefined - --i // retry character - } else { - this.buffer += str[i] - ++p - if (this.buffer.length === 2) { - res += String.fromCharCode(parseInt(this.buffer, 16)) - this.buffer = undefined - } - } - } else if (str[i] === '%') { - if (i > p) { - res += str.substring(p, i) - p = i - } - this.buffer = '' - ++p - } - } - if (p < len && this.buffer === undefined) { res += str.substring(p) } - return res -} -Decoder.prototype.reset = function () { - this.buffer = undefined -} - -module.exports = Decoder - - -/***/ }), - -/***/ 1628: -/***/ ((module) => { - -"use strict"; - - -module.exports = function basename (path) { - if (typeof path !== 'string') { return '' } - for (var i = path.length - 1; i >= 0; --i) { // eslint-disable-line no-var - switch (path.charCodeAt(i)) { - case 0x2F: // '/' - case 0x5C: // '\' - path = path.slice(i + 1) - return (path === '..' || path === '.' ? '' : path) - } - } - return (path === '..' || path === '.' ? '' : path) -} - - -/***/ }), - -/***/ 9464: -/***/ (function(module) { - -"use strict"; - - -// Node has always utf-8 -const utf8Decoder = new TextDecoder('utf-8') -const textDecoders = new Map([ - ['utf-8', utf8Decoder], - ['utf8', utf8Decoder] -]) - -function getDecoder (charset) { - let lc - while (true) { - switch (charset) { - case 'utf-8': - case 'utf8': - return decoders.utf8 - case 'latin1': - case 'ascii': // TODO: Make these a separate, strict decoder? - case 'us-ascii': - case 'iso-8859-1': - case 'iso8859-1': - case 'iso88591': - case 'iso_8859-1': - case 'windows-1252': - case 'iso_8859-1:1987': - case 'cp1252': - case 'x-cp1252': - return decoders.latin1 - case 'utf16le': - case 'utf-16le': - case 'ucs2': - case 'ucs-2': - return decoders.utf16le - case 'base64': - return decoders.base64 - default: - if (lc === undefined) { - lc = true - charset = charset.toLowerCase() - continue - } - return decoders.other.bind(charset) - } - } -} - -const decoders = { - utf8: (data, sourceEncoding) => { - if (data.length === 0) { - return '' - } - if (typeof data === 'string') { - data = Buffer.from(data, sourceEncoding) - } - return data.utf8Slice(0, data.length) - }, - - latin1: (data, sourceEncoding) => { - if (data.length === 0) { - return '' - } - if (typeof data === 'string') { - return data - } - return data.latin1Slice(0, data.length) - }, - - utf16le: (data, sourceEncoding) => { - if (data.length === 0) { - return '' - } - if (typeof data === 'string') { - data = Buffer.from(data, sourceEncoding) - } - return data.ucs2Slice(0, data.length) - }, - - base64: (data, sourceEncoding) => { - if (data.length === 0) { - return '' - } - if (typeof data === 'string') { - data = Buffer.from(data, sourceEncoding) - } - return data.base64Slice(0, data.length) - }, - - other: (data, sourceEncoding) => { - if (data.length === 0) { - return '' - } - if (typeof data === 'string') { - data = Buffer.from(data, sourceEncoding) - } - - if (textDecoders.has(this.toString())) { - try { - return textDecoders.get(this).decode(data) - } catch (e) { } - } - return typeof data === 'string' - ? data - : data.toString() - } -} - -function decodeText (text, sourceEncoding, destEncoding) { - if (text) { - return getDecoder(destEncoding)(text, sourceEncoding) - } - return text -} - -module.exports = decodeText - - -/***/ }), - -/***/ 4323: -/***/ ((module) => { - -"use strict"; - - -module.exports = function getLimit (limits, name, defaultLimit) { - if ( - !limits || - limits[name] === undefined || - limits[name] === null - ) { return defaultLimit } - - if ( - typeof limits[name] !== 'number' || - isNaN(limits[name]) - ) { throw new TypeError('Limit ' + name + ' is not a valid number') } - - return limits[name] -} - - -/***/ }), - -/***/ 2693: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -/* eslint-disable object-property-newline */ - - -const decodeText = __nccwpck_require__(9464) - -const RE_ENCODED = /%[a-fA-F0-9][a-fA-F0-9]/g - -const EncodedLookup = { - '%00': '\x00', '%01': '\x01', '%02': '\x02', '%03': '\x03', '%04': '\x04', - '%05': '\x05', '%06': '\x06', '%07': '\x07', '%08': '\x08', '%09': '\x09', - '%0a': '\x0a', '%0A': '\x0a', '%0b': '\x0b', '%0B': '\x0b', '%0c': '\x0c', - '%0C': '\x0c', '%0d': '\x0d', '%0D': '\x0d', '%0e': '\x0e', '%0E': '\x0e', - '%0f': '\x0f', '%0F': '\x0f', '%10': '\x10', '%11': '\x11', '%12': '\x12', - '%13': '\x13', '%14': '\x14', '%15': '\x15', '%16': '\x16', '%17': '\x17', - '%18': '\x18', '%19': '\x19', '%1a': '\x1a', '%1A': '\x1a', '%1b': '\x1b', - '%1B': '\x1b', '%1c': '\x1c', '%1C': '\x1c', '%1d': '\x1d', '%1D': '\x1d', - '%1e': '\x1e', '%1E': '\x1e', '%1f': '\x1f', '%1F': '\x1f', '%20': '\x20', - '%21': '\x21', '%22': '\x22', '%23': '\x23', '%24': '\x24', '%25': '\x25', - '%26': '\x26', '%27': '\x27', '%28': '\x28', '%29': '\x29', '%2a': '\x2a', - '%2A': '\x2a', '%2b': '\x2b', '%2B': '\x2b', '%2c': '\x2c', '%2C': '\x2c', - '%2d': '\x2d', '%2D': '\x2d', '%2e': '\x2e', '%2E': '\x2e', '%2f': '\x2f', - '%2F': '\x2f', '%30': '\x30', '%31': '\x31', '%32': '\x32', '%33': '\x33', - '%34': '\x34', '%35': '\x35', '%36': '\x36', '%37': '\x37', '%38': '\x38', - '%39': '\x39', '%3a': '\x3a', '%3A': '\x3a', '%3b': '\x3b', '%3B': '\x3b', - '%3c': '\x3c', '%3C': '\x3c', '%3d': '\x3d', '%3D': '\x3d', '%3e': '\x3e', - '%3E': '\x3e', '%3f': '\x3f', '%3F': '\x3f', '%40': '\x40', '%41': '\x41', - '%42': '\x42', '%43': '\x43', '%44': '\x44', '%45': '\x45', '%46': '\x46', - '%47': '\x47', '%48': '\x48', '%49': '\x49', '%4a': '\x4a', '%4A': '\x4a', - '%4b': '\x4b', '%4B': '\x4b', '%4c': '\x4c', '%4C': '\x4c', '%4d': '\x4d', - '%4D': '\x4d', '%4e': '\x4e', '%4E': '\x4e', '%4f': '\x4f', '%4F': '\x4f', - '%50': '\x50', '%51': '\x51', '%52': '\x52', '%53': '\x53', '%54': '\x54', - '%55': '\x55', '%56': '\x56', '%57': '\x57', '%58': '\x58', '%59': '\x59', - '%5a': '\x5a', '%5A': '\x5a', '%5b': '\x5b', '%5B': '\x5b', '%5c': '\x5c', - '%5C': '\x5c', '%5d': '\x5d', '%5D': '\x5d', '%5e': '\x5e', '%5E': '\x5e', - '%5f': '\x5f', '%5F': '\x5f', '%60': '\x60', '%61': '\x61', '%62': '\x62', - '%63': '\x63', '%64': '\x64', '%65': '\x65', '%66': '\x66', '%67': '\x67', - '%68': '\x68', '%69': '\x69', '%6a': '\x6a', '%6A': '\x6a', '%6b': '\x6b', - '%6B': '\x6b', '%6c': '\x6c', '%6C': '\x6c', '%6d': '\x6d', '%6D': '\x6d', - '%6e': '\x6e', '%6E': '\x6e', '%6f': '\x6f', '%6F': '\x6f', '%70': '\x70', - '%71': '\x71', '%72': '\x72', '%73': '\x73', '%74': '\x74', '%75': '\x75', - '%76': '\x76', '%77': '\x77', '%78': '\x78', '%79': '\x79', '%7a': '\x7a', - '%7A': '\x7a', '%7b': '\x7b', '%7B': '\x7b', '%7c': '\x7c', '%7C': '\x7c', - '%7d': '\x7d', '%7D': '\x7d', '%7e': '\x7e', '%7E': '\x7e', '%7f': '\x7f', - '%7F': '\x7f', '%80': '\x80', '%81': '\x81', '%82': '\x82', '%83': '\x83', - '%84': '\x84', '%85': '\x85', '%86': '\x86', '%87': '\x87', '%88': '\x88', - '%89': '\x89', '%8a': '\x8a', '%8A': '\x8a', '%8b': '\x8b', '%8B': '\x8b', - '%8c': '\x8c', '%8C': '\x8c', '%8d': '\x8d', '%8D': '\x8d', '%8e': '\x8e', - '%8E': '\x8e', '%8f': '\x8f', '%8F': '\x8f', '%90': '\x90', '%91': '\x91', - '%92': '\x92', '%93': '\x93', '%94': '\x94', '%95': '\x95', '%96': '\x96', - '%97': '\x97', '%98': '\x98', '%99': '\x99', '%9a': '\x9a', '%9A': '\x9a', - '%9b': '\x9b', '%9B': '\x9b', '%9c': '\x9c', '%9C': '\x9c', '%9d': '\x9d', - '%9D': '\x9d', '%9e': '\x9e', '%9E': '\x9e', '%9f': '\x9f', '%9F': '\x9f', - '%a0': '\xa0', '%A0': '\xa0', '%a1': '\xa1', '%A1': '\xa1', '%a2': '\xa2', - '%A2': '\xa2', '%a3': '\xa3', '%A3': '\xa3', '%a4': '\xa4', '%A4': '\xa4', - '%a5': '\xa5', '%A5': '\xa5', '%a6': '\xa6', '%A6': '\xa6', '%a7': '\xa7', - '%A7': '\xa7', '%a8': '\xa8', '%A8': '\xa8', '%a9': '\xa9', '%A9': '\xa9', - '%aa': '\xaa', '%Aa': '\xaa', '%aA': '\xaa', '%AA': '\xaa', '%ab': '\xab', - '%Ab': '\xab', '%aB': '\xab', '%AB': '\xab', '%ac': '\xac', '%Ac': '\xac', - '%aC': '\xac', '%AC': '\xac', '%ad': '\xad', '%Ad': '\xad', '%aD': '\xad', - '%AD': '\xad', '%ae': '\xae', '%Ae': '\xae', '%aE': '\xae', '%AE': '\xae', - '%af': '\xaf', '%Af': '\xaf', '%aF': '\xaf', '%AF': '\xaf', '%b0': '\xb0', - '%B0': '\xb0', '%b1': '\xb1', '%B1': '\xb1', '%b2': '\xb2', '%B2': '\xb2', - '%b3': '\xb3', '%B3': '\xb3', '%b4': '\xb4', '%B4': '\xb4', '%b5': '\xb5', - '%B5': '\xb5', '%b6': '\xb6', '%B6': '\xb6', '%b7': '\xb7', '%B7': '\xb7', - '%b8': '\xb8', '%B8': '\xb8', '%b9': '\xb9', '%B9': '\xb9', '%ba': '\xba', - '%Ba': '\xba', '%bA': '\xba', '%BA': '\xba', '%bb': '\xbb', '%Bb': '\xbb', - '%bB': '\xbb', '%BB': '\xbb', '%bc': '\xbc', '%Bc': '\xbc', '%bC': '\xbc', - '%BC': '\xbc', '%bd': '\xbd', '%Bd': '\xbd', '%bD': '\xbd', '%BD': '\xbd', - '%be': '\xbe', '%Be': '\xbe', '%bE': '\xbe', '%BE': '\xbe', '%bf': '\xbf', - '%Bf': '\xbf', '%bF': '\xbf', '%BF': '\xbf', '%c0': '\xc0', '%C0': '\xc0', - '%c1': '\xc1', '%C1': '\xc1', '%c2': '\xc2', '%C2': '\xc2', '%c3': '\xc3', - '%C3': '\xc3', '%c4': '\xc4', '%C4': '\xc4', '%c5': '\xc5', '%C5': '\xc5', - '%c6': '\xc6', '%C6': '\xc6', '%c7': '\xc7', '%C7': '\xc7', '%c8': '\xc8', - '%C8': '\xc8', '%c9': '\xc9', '%C9': '\xc9', '%ca': '\xca', '%Ca': '\xca', - '%cA': '\xca', '%CA': '\xca', '%cb': '\xcb', '%Cb': '\xcb', '%cB': '\xcb', - '%CB': '\xcb', '%cc': '\xcc', '%Cc': '\xcc', '%cC': '\xcc', '%CC': '\xcc', - '%cd': '\xcd', '%Cd': '\xcd', '%cD': '\xcd', '%CD': '\xcd', '%ce': '\xce', - '%Ce': '\xce', '%cE': '\xce', '%CE': '\xce', '%cf': '\xcf', '%Cf': '\xcf', - '%cF': '\xcf', '%CF': '\xcf', '%d0': '\xd0', '%D0': '\xd0', '%d1': '\xd1', - '%D1': '\xd1', '%d2': '\xd2', '%D2': '\xd2', '%d3': '\xd3', '%D3': '\xd3', - '%d4': '\xd4', '%D4': '\xd4', '%d5': '\xd5', '%D5': '\xd5', '%d6': '\xd6', - '%D6': '\xd6', '%d7': '\xd7', '%D7': '\xd7', '%d8': '\xd8', '%D8': '\xd8', - '%d9': '\xd9', '%D9': '\xd9', '%da': '\xda', '%Da': '\xda', '%dA': '\xda', - '%DA': '\xda', '%db': '\xdb', '%Db': '\xdb', '%dB': '\xdb', '%DB': '\xdb', - '%dc': '\xdc', '%Dc': '\xdc', '%dC': '\xdc', '%DC': '\xdc', '%dd': '\xdd', - '%Dd': '\xdd', '%dD': '\xdd', '%DD': '\xdd', '%de': '\xde', '%De': '\xde', - '%dE': '\xde', '%DE': '\xde', '%df': '\xdf', '%Df': '\xdf', '%dF': '\xdf', - '%DF': '\xdf', '%e0': '\xe0', '%E0': '\xe0', '%e1': '\xe1', '%E1': '\xe1', - '%e2': '\xe2', '%E2': '\xe2', '%e3': '\xe3', '%E3': '\xe3', '%e4': '\xe4', - '%E4': '\xe4', '%e5': '\xe5', '%E5': '\xe5', '%e6': '\xe6', '%E6': '\xe6', - '%e7': '\xe7', '%E7': '\xe7', '%e8': '\xe8', '%E8': '\xe8', '%e9': '\xe9', - '%E9': '\xe9', '%ea': '\xea', '%Ea': '\xea', '%eA': '\xea', '%EA': '\xea', - '%eb': '\xeb', '%Eb': '\xeb', '%eB': '\xeb', '%EB': '\xeb', '%ec': '\xec', - '%Ec': '\xec', '%eC': '\xec', '%EC': '\xec', '%ed': '\xed', '%Ed': '\xed', - '%eD': '\xed', '%ED': '\xed', '%ee': '\xee', '%Ee': '\xee', '%eE': '\xee', - '%EE': '\xee', '%ef': '\xef', '%Ef': '\xef', '%eF': '\xef', '%EF': '\xef', - '%f0': '\xf0', '%F0': '\xf0', '%f1': '\xf1', '%F1': '\xf1', '%f2': '\xf2', - '%F2': '\xf2', '%f3': '\xf3', '%F3': '\xf3', '%f4': '\xf4', '%F4': '\xf4', - '%f5': '\xf5', '%F5': '\xf5', '%f6': '\xf6', '%F6': '\xf6', '%f7': '\xf7', - '%F7': '\xf7', '%f8': '\xf8', '%F8': '\xf8', '%f9': '\xf9', '%F9': '\xf9', - '%fa': '\xfa', '%Fa': '\xfa', '%fA': '\xfa', '%FA': '\xfa', '%fb': '\xfb', - '%Fb': '\xfb', '%fB': '\xfb', '%FB': '\xfb', '%fc': '\xfc', '%Fc': '\xfc', - '%fC': '\xfc', '%FC': '\xfc', '%fd': '\xfd', '%Fd': '\xfd', '%fD': '\xfd', - '%FD': '\xfd', '%fe': '\xfe', '%Fe': '\xfe', '%fE': '\xfe', '%FE': '\xfe', - '%ff': '\xff', '%Ff': '\xff', '%fF': '\xff', '%FF': '\xff' -} - -function encodedReplacer (match) { - return EncodedLookup[match] -} - -const STATE_KEY = 0 -const STATE_VALUE = 1 -const STATE_CHARSET = 2 -const STATE_LANG = 3 - -function parseParams (str) { - const res = [] - let state = STATE_KEY - let charset = '' - let inquote = false - let escaping = false - let p = 0 - let tmp = '' - const len = str.length - - for (var i = 0; i < len; ++i) { // eslint-disable-line no-var - const char = str[i] - if (char === '\\' && inquote) { - if (escaping) { escaping = false } else { - escaping = true - continue - } - } else if (char === '"') { - if (!escaping) { - if (inquote) { - inquote = false - state = STATE_KEY - } else { inquote = true } - continue - } else { escaping = false } - } else { - if (escaping && inquote) { tmp += '\\' } - escaping = false - if ((state === STATE_CHARSET || state === STATE_LANG) && char === "'") { - if (state === STATE_CHARSET) { - state = STATE_LANG - charset = tmp.substring(1) - } else { state = STATE_VALUE } - tmp = '' - continue - } else if (state === STATE_KEY && - (char === '*' || char === '=') && - res.length) { - state = char === '*' - ? STATE_CHARSET - : STATE_VALUE - res[p] = [tmp, undefined] - tmp = '' - continue - } else if (!inquote && char === ';') { - state = STATE_KEY - if (charset) { - if (tmp.length) { - tmp = decodeText(tmp.replace(RE_ENCODED, encodedReplacer), - 'binary', - charset) - } - charset = '' - } else if (tmp.length) { - tmp = decodeText(tmp, 'binary', 'utf8') - } - if (res[p] === undefined) { res[p] = tmp } else { res[p][1] = tmp } - tmp = '' - ++p - continue - } else if (!inquote && (char === ' ' || char === '\t')) { continue } - } - tmp += char - } - if (charset && tmp.length) { - tmp = decodeText(tmp.replace(RE_ENCODED, encodedReplacer), - 'binary', - charset) - } else if (tmp) { - tmp = decodeText(tmp, 'binary', 'utf8') - } - - if (res[p] === undefined) { - if (tmp) { res[p] = tmp } - } else { res[p][1] = tmp } - - return res -} - -module.exports = parseParams - - -/***/ }) - -/******/ }); -/************************************************************************/ -/******/ // The module cache -/******/ var __webpack_module_cache__ = {}; -/******/ -/******/ // The require function -/******/ function __nccwpck_require__(moduleId) { -/******/ // Check if module is in cache -/******/ var cachedModule = __webpack_module_cache__[moduleId]; -/******/ if (cachedModule !== undefined) { -/******/ return cachedModule.exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = __webpack_module_cache__[moduleId] = { -/******/ // no module.id needed -/******/ // no module.loaded needed -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ var threw = true; -/******/ try { -/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __nccwpck_require__); -/******/ threw = false; -/******/ } finally { -/******/ if(threw) delete __webpack_module_cache__[moduleId]; -/******/ } -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/************************************************************************/ -/******/ /* webpack/runtime/compat */ -/******/ -/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/"; -/******/ -/************************************************************************/ -var __webpack_exports__ = {}; -// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. -(() => { -const aarch64 = 'aarch64'; -const x86_64 = 'x86_64'; - -const archList = [{ - arch: x86_64, - runner: 'ubuntu-latest', - docker_tag: 'manylinux2014_x86_64-plugins-deps', -}, { - arch: aarch64, - runner: 'linux-arm64', - docker_tag: 'manylinux2014_aarch64-plugins-deps', -}]; - -const pluginList = [{ - name: 'wasi_nn', - bin: 'libwasmedgePluginWasiNN.so', - testBin: 'wasiNNTests', - features: [{ - name: 'tensorflowlite', - options: '-DWASMEDGE_PLUGIN_WASI_NN_BACKEND=TensorFlowLite', - archList: [aarch64, x86_64], - }, { - name: 'wasi_nn-ggml', - options: '-DWASMEDGE_PLUGIN_WASI_NN_BACKEND=GGML -DWASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_BLAS=OFF', - archList: [aarch64, x86_64], - }, { - name: 'wasi_nn-pytorch', - options: '-DWASMEDGE_PLUGIN_WASI_NN_BACKEND=PyTorch', - archList: [x86_64], - }], -}]; - -let expandVariables = () => { - let ret = archList.map((arch) => { - arch.plugins = pluginList.flatMap((plugin) => { - if (plugin.hasOwnProperty('features')) - return plugin.features - .filter((ft) => ft.archList.includes(arch.arch)) - .map((ft) => ({ - plugin: [plugin.name, ft.name].join('-'), - bin: plugin.bin, - dir: plugin.name, - testBin: plugin.testBin, - options: ft.options, - })); - if (plugin.archList.includes(arch.arch)) - return { - plugin: plugin.name, - bin: plugin.bin, - dir: plugin.name, - testBin: plugin.testBin, - options: plugin.options, - }; - return []; - }) - return arch; - }); - return ret; -}; - -const core = __nccwpck_require__(2619); - -try { - output = JSON.stringify(expandVariables()); - core.setOutput('matrix', output); - console.log(`matrix: ${output}`); -} catch (err) { - core.setFailed(err.message); -} - -})(); - -module.exports = __webpack_exports__; -/******/ })() -; \ No newline at end of file diff --git a/.github/actions/expand-variables/dist/license.txt b/.github/actions/expand-variables/dist/license.txt deleted file mode 100644 index a8fa3a86f90f..000000000000 --- a/.github/actions/expand-variables/dist/license.txt +++ /dev/null @@ -1,120 +0,0 @@ -@actions/core -MIT -The MIT License (MIT) - -Copyright 2019 GitHub - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -@actions/http-client -MIT -Actions Http Client for Node.js - -Copyright (c) GitHub, Inc. - -All rights reserved. - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -@fastify/busboy -MIT -Copyright Brian White. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. - -tunnel -MIT -The MIT License (MIT) - -Copyright (c) 2012 Koichi Kobayashi - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - - -undici -MIT -MIT License - -Copyright (c) Matteo Collina and Undici contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - -uuid -MIT -The MIT License (MIT) - -Copyright (c) 2010-2020 Robert Kieffer and other contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/.github/actions/expand-variables/main.js b/.github/actions/expand-variables/main.js deleted file mode 100644 index 5a393dedb59b..000000000000 --- a/.github/actions/expand-variables/main.js +++ /dev/null @@ -1,69 +0,0 @@ -const aarch64 = 'aarch64'; -const x86_64 = 'x86_64'; - -const archList = [{ - arch: x86_64, - runner: 'ubuntu-latest', - docker_tag: 'manylinux2014_x86_64-plugins-deps', -}, { - arch: aarch64, - runner: 'linux-arm64', - docker_tag: 'manylinux2014_aarch64-plugins-deps', -}]; - -const pluginList = [{ - name: 'wasi_nn', - bin: 'libwasmedgePluginWasiNN.so', - testBin: 'wasiNNTests', - features: [{ - name: 'tensorflowlite', - options: '-DWASMEDGE_PLUGIN_WASI_NN_BACKEND=TensorFlowLite', - archList: [aarch64, x86_64], - }, { - name: 'wasi_nn-ggml', - options: '-DWASMEDGE_PLUGIN_WASI_NN_BACKEND=GGML -DWASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_BLAS=OFF', - archList: [aarch64, x86_64], - }, { - name: 'wasi_nn-pytorch', - options: '-DWASMEDGE_PLUGIN_WASI_NN_BACKEND=PyTorch', - archList: [x86_64], - }], -}]; - -let expandVariables = () => { - let ret = archList.map((arch) => { - arch.plugins = pluginList.flatMap((plugin) => { - if (plugin.hasOwnProperty('features')) - return plugin.features - .filter((ft) => ft.archList.includes(arch.arch)) - .map((ft) => ({ - plugin: [plugin.name, ft.name].join('-'), - bin: plugin.bin, - dir: plugin.name, - testBin: plugin.testBin, - options: ft.options, - })); - if (plugin.archList.includes(arch.arch)) - return { - plugin: plugin.name, - bin: plugin.bin, - dir: plugin.name, - testBin: plugin.testBin, - options: plugin.options, - }; - return []; - }) - return arch; - }); - return ret; -}; - -const core = require('@actions/core'); - -try { - output = JSON.stringify(expandVariables()); - core.setOutput('matrix', output); - console.log(`matrix: ${output}`); -} catch (err) { - core.setFailed(err.message); -} diff --git a/.github/actions/expand-variables/package-lock.json b/.github/actions/expand-variables/package-lock.json deleted file mode 100644 index 0ce55136525c..000000000000 --- a/.github/actions/expand-variables/package-lock.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "name": "expand-variables", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "expand-variables", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@actions/core": "^1.10.1" - } - }, - "node_modules/@actions/core": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz", - "integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==", - "dependencies": { - "@actions/http-client": "^2.0.1", - "uuid": "^8.3.2" - } - }, - "node_modules/@actions/http-client": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.0.tgz", - "integrity": "sha512-q+epW0trjVUUHboliPb4UF9g2msf+w61b32tAkFEwL/IwP0DQWgbCMM0Hbe3e3WXSKz5VcUXbzJQgy8Hkra/Lg==", - "dependencies": { - "tunnel": "^0.0.6", - "undici": "^5.25.4" - } - }, - "node_modules/@fastify/busboy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", - "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", - "engines": { - "node": ">=14" - } - }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, - "node_modules/undici": { - "version": "5.27.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", - "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - } - } -} diff --git a/.github/actions/expand-variables/package.json b/.github/actions/expand-variables/package.json deleted file mode 100644 index 5391a153491d..000000000000 --- a/.github/actions/expand-variables/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "expand-variables", - "version": "1.0.0", - "description": "", - "main": "main.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [], - "author": "", - "license": "ISC", - "dependencies": { - "@actions/core": "^1.10.1" - } -} diff --git a/.github/extensions.paths-filter.yml b/.github/extensions.paths-filter.yml new file mode 100644 index 000000000000..6592f2c8fbf2 --- /dev/null +++ b/.github/extensions.paths-filter.yml @@ -0,0 +1,52 @@ +all: + - '.github/**' + - 'plugins/CMakeLists.txt' + - 'test/plugins/CMakeLists.txt' +wasi_crypto: + - 'plugins/wasi_crypto/**' + - 'test/plugins/wasi_crypto/**' +wasi_nn-ggml: + - 'plugins/wasi_nn/**' + - 'test/plugins/wasi_nn/**' +wasi_nn-pytorch: + - 'plugins/wasi_nn/**' + - 'test/plugins/wasi_nn/**' +wasi_nn-tensorflowlite: + - 'plugins/wasi_nn/**' + - 'test/plugins/wasi_nn/**' +wasi_nn-whisper: + - 'plugins/wasi_nn/**' + - 'test/plugins/wasi_nn/**' +wasi_nn-piper: + - 'plugins/wasi_nn/**' + - 'test/plugins/wasi_nn/**' +wasm_bpf: + - 'plugins/wasm_bpf/**' + - 'test/plugins/wasm_bpf/**' +wasmedge_ffmpeg: + - 'plugins/wasmedge_ffmpeg/**' + - 'test/plugins/wasmedge_ffmpeg/**' +wasmedge_image: + - 'plugins/wasmedge_image/**' + - 'test/plugins/wasmedge_image/**' +wasmedge_llmc: + - 'plugins/wasmedge_llmc/**' + - 'test/plugins/wasmedge_llmc/**' +wasmedge_opencvmini: + - 'plugins/wasmedge_opencvmini/**' + - 'test/plugins/wasmedge_opencvmini/**' +wasmedge_process: + - 'plugins/wasmedge_process/**' + - 'test/plugins/wasmedge_process/**' +wasmedge_stablediffusion: + - 'plugins/wasmedge_stablediffusion/**' + - 'test/plugins/wasmedge_stablediffusion/**' +wasmedge_tensorflow: + - 'plugins/wasmedge_tensorflow/**' + - 'test/plugins/wasmedge_tensorflow/**' +wasmedge_tensorflowlite: + - 'plugins/wasmedge_tensorflowlite/**' + - 'test/plugins/wasmedge_tensorflowlite/**' +wasmedge_zlib: + - 'plugins/wasmedge_zlib/**' + - 'test/plugins/wasmedge_zlib/**' diff --git a/.github/labeler.yml b/.github/labeler.yml index b6f7f2ea0244..8c2dc04cff8b 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -85,7 +85,7 @@ 'test/**/*' ] -'c-WASI': +'WASI': - changed-files: - any-glob-to-any-file: [ 'include/host/wasi/**', @@ -94,7 +94,7 @@ 'lib/host/wasi/**/*' ] -'c-WASI-NN': +'WASI-NN': - changed-files: - any-glob-to-any-file: [ 'plugins/wasi_nn/**', diff --git a/.github/workflows/IWYU_scan.yml b/.github/workflows/IWYU_scan.yml index b026b0b514a6..82f4d2b06039 100644 --- a/.github/workflows/IWYU_scan.yml +++ b/.github/workflows/IWYU_scan.yml @@ -40,7 +40,7 @@ jobs: outputs: version: ${{ steps.prep.outputs.version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory @@ -68,15 +68,12 @@ jobs: run: | dnf update -y dnf install -y cmake ninja-build llvm llvm-devel lld-devel clang git file rpm-build dpkg-dev clang-devel spdlog-devel - curl -L -O https://github.com/include-what-you-use/include-what-you-use/archive/refs/tags/0.20.zip - unzip 0.20.zip - mkdir build && cd build - cmake -G "Unix Makefiles" ../include-what-you-use-0.20 - make -j - make install - cd .. + curl -L -O https://github.com/include-what-you-use/include-what-you-use/archive/refs/tags/0.22.zip + unzip 0.22.zip + cmake -Bbuild-iwyu -GNinja -DCMAKE_BUILD_TYPE=Release include-what-you-use-0.22 + cmake --build build-iwyu --target install - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory @@ -102,7 +99,7 @@ jobs: needs: get_version steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory @@ -115,24 +112,40 @@ jobs: # Unlink python@3.11 to fix brew link 2to3 conflict. brew unlink python@3.11 brew install llvm ninja cmake - export LLVM_DIR="/usr/local/opt/llvm/lib/cmake" - export Clang_DIR="/usr/local/opt/llvm/lib/cmake/clang" + export LLVM_DIR="$(brew --prefix)/opt/llvm/lib/cmake" + export Clang_DIR="$(brew --prefix)/opt/llvm/lib/cmake/clang" + export IWYU_PREFIX="$(brew --prefix)/opt/iwyu" export CC=clang export CXX=clang++ cd ../../ - curl -L -O https://github.com/include-what-you-use/include-what-you-use/archive/refs/tags/0.20.zip - unzip 0.20.zip - mkdir build && cd build - cmake -G "Unix Makefiles" ../include-what-you-use-0.20 - make -j install - cd ../WasmEdge/WasmEdge - - cmake -Bbuild -GNinja -DWASMEDGE_BUILD_TESTS=ON -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE=include-what-you-use -DWASMEDGE_BUILD_PACKAGE="TGZ" . - cmake --build build > iwyu_macos.log + curl -L -O https://github.com/include-what-you-use/include-what-you-use/archive/refs/tags/0.22.zip + unzip 0.22.zip + patch -p1 -d include-what-you-use-0.22 <<EOF + diff --git a/iwyu.cc b/iwyu.cc + --- a/iwyu.cc + +++ b/iwyu.cc + @@ -3476,6 +3476,12 @@ class InstantiatedTemplateVisitor + if (ReplayClassMemberUsesFromPrecomputedList(type)) + return true; + + + // Sometimes, an implicit specialization occurs to be not instantiated. + + // TODO(bolshakov): don't report them at all as full uses or figure out + + // how to scan them. + + if (!class_decl->hasDefinition()) + + return true; + + + // Make sure all the types we report in the recursive TraverseDecl + // calls, below, end up in the cache for class_decl. + EOF + cmake -Bbuild-iwyu -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$IWYU_PREFIX" include-what-you-use-0.22 + cmake --build build-iwyu --target install + cd WasmEdge/WasmEdge + + cmake -Bbuild -GNinja -DWASMEDGE_BUILD_TESTS=ON -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="xcrun;$IWYU_PREFIX/bin/include-what-you-use" -DWASMEDGE_BUILD_PACKAGE="TGZ" . + cmake --build build > iwyu_macOS.log - uses: actions/upload-artifact@v3 with: name: iwyu_macOS.log path: iwyu_macOS.log - diff --git a/.github/workflows/README.md b/.github/workflows/README.md index e3be092b39da..9e6eab0c331c 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -2,7 +2,8 @@ This document has not yet covered all workflows. -## build.yml +## Workflow for `build.yml` + ```mermaid flowchart LR %% _ is the starting point of everything @@ -10,27 +11,29 @@ flowchart LR lint-->|pass|build(build) lint-->|fail|reject(unable to merge) build-.->source(create source tarball) - build-.->oss("<ul> - <li>build on macOS</li> - <li>build on manylinux</li> - <li>build on Windows</li> - <li>build on Android</li> - <li>build on Fedora</li> - </ul>") + build-.->oss("build on all OS") + build-.->ext("build plugins on all OS") ``` ### macOS + ```json [ { "name": "MacOS 12 (x86_64)", "runner": "macos-12", "darwin_version": 21 + }, + { + "name": "MacOS 14 (arm64)", + "runner": "macos-14", + "darwin_version": 23 } ] ``` ### manylinux + ```json [ { @@ -38,8 +41,55 @@ flowchart LR "docker_tag": "manylinux2014_x86_64" }, { - "runner": "linux-arm64", + "runner": "linux-arm64-v2", "docker_tag": "manylinux2014_aarch64" + }, + { + "runner": "ubuntu-latest", + "docker_tag": "manylinux_2_28_x86_64" + }, + { + "runner": "linux-arm64-v2", + "docker_tag": "manylinux_2_28_aarch64" } ] ``` + +## Calling Structure for Reusable Workflows + +```mermaid +flowchart LR + subgraph "build-extensions.yml" + b_("build-extensions.yml")-->|reusable-call-linter.yml|l0(("lint pass")) + l0-->b_ext("reusable-build-extensions.yml") + b_ext-->b_ext_m("reusable-build-extensions-on-manylinux.yml") + end + b("build.yml")-->|reusable-call-linter.yml|l1(("lint pass")) + l1-->oss("<ul> + <li>reusable-build-on-alpine-static.yml</li> + <li>reusable-build-on-android.yml</li> + <li>reusable-build-on-debian-static.yml</li> + <li>reusable-build-on-macos.yml</li> + <li>reusable-build-on-manylinux.yml</li> + <li>reusable-build-on-ubuntu.yml</li> + <li>reusable-build-on-windows.yml</li> + <li>reusable-build-on-windows-msvc.yml</li> + </ul>") + subgraph "release.yml" + rel("release.yml")-->|reusable-call-linter.yml|l2(("lint pass")) + l2-->oss + l2-->b_ext + l2-->src + end + l1-->oss_extra("<ul> + <li>reusable-build-on-debian.yml</li> + <li>reusable-build-on-fedora.yml</li> + </ul>") + l1-->src("reusable-create-source-tarball.yml") + classDef nostroke stroke:none; + class l0,l1,l2 nostroke + classDef relcls stroke:olive; + class rel,oss,src,b_ext relcls + classDef bcls stroke:orange; + class b,oss_extra bcls +``` diff --git a/.github/workflows/bindings-java.yml b/.github/workflows/bindings-java.yml index b6ec7648351d..43cc52326ab6 100644 --- a/.github/workflows/bindings-java.yml +++ b/.github/workflows/bindings-java.yml @@ -23,10 +23,12 @@ on: - "lib/api/**" permissions: - contents: write + contents: read jobs: build_ubuntu: + permissions: + contents: write name: Ubuntu 22.04 runs-on: ${{ matrix.os }} strategy: @@ -36,7 +38,7 @@ jobs: image: wasmedge/wasmedge:ubuntu-build-clang steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Ensure git safe directory run: | @@ -83,6 +85,8 @@ jobs: bindings/java/wasmedge-java/build/libs/wasmedge-java-*.jar build_macos: + permissions: + contents: write name: MacOS runs-on: ${{ matrix.os }} strategy: @@ -91,7 +95,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -145,6 +149,8 @@ jobs: bindings/java/wasmedge-java/build/libs/wasmedge-java-*.jar build_windows: + permissions: + contents: write name: Windows runs-on: windows-2022 env: @@ -153,7 +159,7 @@ jobs: WASMEDGE_PLUGIN_PATH: ${{ github.workspace }}\build\wasmedge\plugins\wasmedge_process LD_LIBRARY_PATH: ${{ github.workspace }}\build\lib\api steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -162,7 +168,7 @@ jobs: with: args: install cmake ninja vswhere - - uses: GuillaumeFalourd/setup-windows10-sdk-action@v1 + - uses: GuillaumeFalourd/setup-windows10-sdk-action@v2 with: sdk-version: 19041 @@ -178,10 +184,10 @@ jobs: $vsPath = (vswhere -latest -property installationPath) Import-Module (Join-Path $vsPath "Common7\Tools\Microsoft.VisualStudio.DevShell.dll") Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64 -winsdk=10.0.19041.0" - $llvm = "LLVM-16.0.6-win64-MultiThreadedDLL.zip" - curl -sLO https://github.com/WasmEdge/llvm-windows/releases/download/llvmorg-16.0.6/LLVM-16.0.6-win64-MultiThreadedDLL.zip -o $llvm + $llvm = "LLVM-17.0.6-win64-MultiThreadedDLL.zip" + curl -sLO https://github.com/WasmEdge/llvm-windows/releases/download/llvmorg-17.0.6/LLVM-17.0.6-win64-MultiThreadedDLL.zip -o $llvm Expand-Archive -Path $llvm - $llvm_dir = "$pwd\\LLVM-16.0.6-win64-MultiThreadedDLL\\LLVM-16.0.6-win64\\lib\\cmake\\llvm" + $llvm_dir = "$pwd\\LLVM-17.0.6-win64-MultiThreadedDLL\\LLVM-17.0.6-win64\\lib\\cmake\\llvm" $Env:CC = "clang-cl" $Env:CXX = "clang-cl" $cmake_sys_version = "10.0.19041.0" @@ -206,10 +212,10 @@ jobs: $vsPath = (vswhere -latest -property installationPath) Import-Module (Join-Path $vsPath "Common7\Tools\Microsoft.VisualStudio.DevShell.dll") Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64 -winsdk=10.0.19041.0" - $llvm = "LLVM-16.0.6-win64-MultiThreadedDLL.zip" - curl -sLO https://github.com/WasmEdge/llvm-windows/releases/download/llvmorg-16.0.6/LLVM-16.0.6-win64-MultiThreadedDLL.zip -o $llvm + $llvm = "LLVM-17.0.6-win64-MultiThreadedDLL.zip" + curl -sLO https://github.com/WasmEdge/llvm-windows/releases/download/llvmorg-17.0.6/LLVM-17.0.6-win64-MultiThreadedDLL.zip -o $llvm Expand-Archive -Path $llvm - $llvm_dir = "$pwd\\LLVM-16.0.6-win64-MultiThreadedDLL\\LLVM-16.0.6-win64\\lib\\cmake\\llvm" + $llvm_dir = "$pwd\\LLVM-17.0.6-win64-MultiThreadedDLL\\LLVM-17.0.6-win64\\lib\\cmake\\llvm" $Env:CC = "clang-cl" $Env:CXX = "clang-cl" $cmake_sys_version = "10.0.19041.0" diff --git a/.github/workflows/build-extensions.yml b/.github/workflows/build-extensions.yml index 060c8b60db9e..dc387045d5d3 100644 --- a/.github/workflows/build-extensions.yml +++ b/.github/workflows/build-extensions.yml @@ -9,8 +9,9 @@ on: branches: - master paths: + - ".github/extensions.paths-filter.yml" - ".github/workflows/build-extensions.yml" - - ".github/actions/expand-variables/**" + - ".github/workflows/matrix-extensions.json" - ".github/workflows/reusable-build-extensions**" - ".github/workflows/reusable-call-linter.yml" - "plugins/**" @@ -19,15 +20,16 @@ on: - "tools/**" - "CMakeLists.txt" - "cmake/**" + - "utils/ffmpeg/**" - "utils/wasi-nn/**" - - "utils/wasi-crypto/**" pull_request: branches: - master - "proposal/**" paths: + - ".github/extensions.paths-filter.yml" - ".github/workflows/build-extensions.yml" - - ".github/actions/expand-variables/**" + - ".github/workflows/matrix-extensions.json" - ".github/workflows/reusable-build-extensions**" - ".github/workflows/reusable-call-linter.yml" - "plugins/**" @@ -36,30 +38,26 @@ on: - "tools/**" - "CMakeLists.txt" - "cmake/**" + - "utils/ffmpeg/**" - "utils/wasi-nn/**" - - "utils/wasi-crypto/**" permissions: - contents: write + contents: read jobs: # TODO: Refactor `lint` with `on.workflow_run` # https://docs.github.com/en/actions/using-workflows/triggering-a-workflow lint: - permissions: - contents: read uses: ./.github/workflows/reusable-call-linter.yml get_version: - permissions: - contents: read name: Retrieve version information needs: lint runs-on: ubuntu-latest outputs: version: ${{ steps.prep.outputs.version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory @@ -75,6 +73,8 @@ jobs: # Due to the dependencies and exclusions of WASI-NN, build them saperately. build_ubuntu_wasi_nn: + permissions: + contents: write strategy: matrix: include: @@ -91,19 +91,19 @@ jobs: env: output_dir: build/plugins/wasi_nn test_dir: build/test/plugins/wasi_nn - build_options: -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=PyTorch -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=OpenVINO -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=TensorFlowLite -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=GGML - tar_names: wasi_nn-pytorch wasi_nn-openvino wasi_nn-tensorflowlite wasi_nn-ggml + build_options: -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=PyTorch -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=OpenVINO -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=TensorFlowLite -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=GGML -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=Piper -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=Whisper + tar_names: wasi_nn-pytorch wasi_nn-openvino wasi_nn-tensorflowlite wasi_nn-ggml wasi_nn-piper wasi_nn-whisper test_bin: wasiNNTests output_bin: libwasmedgePluginWasiNN.so - OPENVINO_VERSION: "2023.0.2" - OPENVINO_YEAR: "2023" + OPENVINO_VERSION: "2024.2.0" + OPENVINO_YEAR: "2024" PYTORCH_VERSION: "1.8.2" PYTORCH_INSTALL_TO: "." - needs: [get_version] + needs: [ get_version ] container: image: wasmedge/wasmedge:${{ matrix.docker_tag }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory @@ -116,6 +116,7 @@ jobs: apt install -y unzip libopenblas-dev pkg-config protobuf-compiler-grpc libgrpc-dev libgrpc++-dev bash utils/wasi-nn/install-openvino.sh bash utils/wasi-nn/install-pytorch.sh + bash utils/wasi-nn/install-onnxruntime.sh - name: Build and test WASI-NN using ${{ matrix.compiler }} with ${{ matrix.build_type }} mode shell: bash run: | @@ -123,7 +124,7 @@ jobs: ldconfig plugin_array=(${tar_names}) option_array=(${build_options}) - cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DWASMEDGE_BUILD_TESTS=ON -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DWASMEDGE_BUILD_TOOLS=OFF + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DWASMEDGE_BUILD_TESTS=ON -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_TOOLS=OFF for (( i=0; i<${#plugin_array[@]}; i++ )); do echo "Building ${plugin_array[$i]} backend:" @@ -143,17 +144,35 @@ jobs: shell: bash run: | set -eux - # wasi_nn_rpcserver is built in a clean "build2" dir - cmake -Bbuild2 -GNinja - cmake --build build2 + # wasi_nn_rpcserver is built in a clean "build_rpc" dir + export nnrpc_test_dir=build_rpc/test/plugins/wasi_nn + cmake -Bbuild_rpc -GNinja \ + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ + -DWASMEDGE_BUILD_TESTS=ON \ + -DWASMEDGE_USE_LLVM=OFF \ + -DWASMEDGE_BUILD_TOOLS=ON \ + -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=GGML \ + -DWASMEDGE_BUILD_WASI_NN_RPC=ON + cmake --build build_rpc export WASI_NN_RPC_TEST_URI=unix:///tmp/wasi_nn_rpc.sock - WASMEDGE_PLUGIN_PATH=build/plugins/wasi_nn build2/tools/wasmedge/wasi_nn_rpcserver \ - --nn-rpc-uri=$WASI_NN_RPC_TEST_URI \ - --nn-preload=default:GGML:AUTO:build/test/plugins/wasi_nn/wasinn_ggml_fixtures/orca_mini.gguf & + export WASMEDGE_PLUGIN_PATH=build_rpc/plugins/wasi_nn + build_rpc/tools/wasmedge/wasi_nn_rpcserver \ + --nn-rpc-uri $WASI_NN_RPC_TEST_URI \ + --nn-preload default:GGML:AUTO:build_rpc/test/plugins/wasi_nn/wasinn_ggml_fixtures/orca_mini.gguf & + RPC_SERVER_PID=$! sleep 3 - cd ${test_dir} # The test binary consumes $WASI_NN_RPC_TEST_URI - ./${test_bin} --gtest_filter=WasiNNTest.GGMLBackendWithRPC + (cd ${nnrpc_test_dir} && ./${test_bin} --gtest_filter=WasiNNTest.GGMLBackendWithRPC) + kill -9 "$RPC_SERVER_PID" + + # Restart the server for the compute single test + build_rpc/tools/wasmedge/wasi_nn_rpcserver \ + --nn-rpc-uri $WASI_NN_RPC_TEST_URI \ + --nn-preload default:GGML:AUTO:build_rpc/test/plugins/wasi_nn/wasinn_ggml_fixtures/orca_mini.gguf & + RPC_SERVER_PID=$! + sleep 3 + (cd ${nnrpc_test_dir} && ./${test_bin} --gtest_filter=WasiNNTest.GGMLBackendComputeSingleWithRPC) + kill -9 "$RPC_SERVER_PID" - name: Upload artifact - wasi_nn-pytorch uses: actions/upload-artifact@v3 with: @@ -174,8 +193,151 @@ jobs: with: name: WasmEdge-plugin-wasi_nn-ggml-${{ needs.get_version.outputs.version }}-ubuntu22.04-${{ matrix.compiler }}.tar.gz path: plugin_wasi_nn-ggml.tar.gz + - name: Upload artifact - wasi_nn-piper + uses: actions/upload-artifact@v3 + with: + name: WasmEdge-plugin-wasi_nn-piper-${{ needs.get_version.outputs.version }}-ubuntu22.04-${{ matrix.compiler }}.tar.gz + path: plugin_wasi_nn-piper.tar.gz + - name: Upload artifact - wasi_nn-whisper + uses: actions/upload-artifact@v3 + with: + name: WasmEdge-plugin-wasi_nn-whisper-${{ needs.get_version.outputs.version }}-ubuntu22.04-${{ matrix.compiler }}.tar.gz + path: plugin_wasi_nn-whisper.tar.gz + + build_macos_wasi_nn: + permissions: + contents: write + strategy: + matrix: + include: + - system: MacOS 12 (x86_64) + host_runner: macos-12 + darwin_version: darwin_21 + build_type: Release + arch: x86_64 + - system: MacOS 14 (arm64) + host_runner: macos-14 + darwin_version: darwin_23 + build_type: Release + arch: arm64 + name: WASI-NN (${{ matrix.system }}, clang++, ${{ matrix.build_type }}) + runs-on: ${{ matrix.host_runner }} + env: + output_dir: build/plugins/wasi_nn + test_dir: build/test/plugins/wasi_nn + build_options: -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=TensorFlowLite -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=Whisper + tar_names: wasi_nn-tensorflowlite wasi_nn-whisper + test_bin: wasiNNTests + output_bin: libwasmedgePluginWasiNN.dylib + needs: [ get_version ] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Build and install dependencies + run: | + eval $(/opt/homebrew/bin/brew shellenv) + brew install llvm@16 ninja cmake + - name: Build and test WASI-NN using clang++ with ${{ matrix.build_type }} mode + shell: bash + run: | + eval $(/opt/homebrew/bin/brew shellenv) + export LLVM_DIR="$(brew --prefix)/opt/llvm@16/lib/cmake" + export CC=clang + export CXX=clang++ + plugin_array=(${tar_names}) + option_array=(${build_options}) + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DWASMEDGE_BUILD_TESTS=ON -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_TOOLS=OFF + for (( i=0; i<${#plugin_array[@]}; i++ )); + do + echo "Building ${plugin_array[$i]} backend:" + cmake -Bbuild -GNinja ${option_array[$i]} + cmake --build build --target ${test_bin} + + echo "Testing ${plugin_array[$i]} backend:" + cd ${test_dir} + ./${test_bin} + cd - + + echo "Copying ${plugin_array[$i]} backend:" + cp -f ${output_dir}/${output_bin} ${output_bin} + tar -zcvf plugin_${plugin_array[$i]}.tar.gz ${output_bin} + done + - name: Upload artifact - wasi_nn-tensorflowlite + uses: actions/upload-artifact@v3 + with: + name: WasmEdge-plugin-wasi_nn-tensorflowlite-${{ needs.get_version.outputs.version }}-${{ matrix.darwin_version }}_${{ matrix.arch }}.tar.gz + path: plugin_wasi_nn-tensorflowlite.tar.gz + - name: Upload artifact - wasi_nn-whisper + uses: actions/upload-artifact@v3 + with: + name: WasmEdge-plugin-wasi_nn-whisper-${{ needs.get_version.outputs.version }}-${{ matrix.darwin_version }}_${{ matrix.arch }}.tar.gz + path: plugin_wasi_nn-whisper.tar.gz + + + build_windows_wasi_nn: + permissions: + contents: write + name: WASI-NN (Windows Server 2022) + runs-on: windows-2022 + env: + output_dir: build/plugins/wasi_nn + test_dir: build/test/plugins/wasi_nn + build_options: -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=GGML + tar_names: wasi_nn-ggml + test_bin: wasiNNTests + output_bin: wasmedgePluginWasiNN.dll + needs: [ get_version ] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Ensure git safe directory + run: | + git config --global --add safe.directory $(pwd) + - name: Install dependency + uses: crazy-max/ghaction-chocolatey@v3 + with: + args: install cmake ninja vswhere + - uses: GuillaumeFalourd/setup-windows10-sdk-action@v2 + with: + sdk-version: 22621 + - name: Build WasmEdge + run: | + $vsPath = (vswhere -latest -property installationPath) + Import-Module (Join-Path $vsPath "Common7\Tools\Microsoft.VisualStudio.DevShell.dll") + Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64 -winsdk=10.0.22621.0" + $llvm = "LLVM-17.0.6-win64-MultiThreadedDLL.zip" + curl -sLO https://github.com/WasmEdge/llvm-windows/releases/download/llvmorg-17.0.6/LLVM-17.0.6-win64-MultiThreadedDLL.zip -o $llvm + Expand-Archive -Path $llvm + $llvm_dir = "$pwd\\LLVM-17.0.6-win64-MultiThreadedDLL\\LLVM-17.0.6-win64\\lib\\cmake\\llvm" + $cmake_sys_version = "10.0.22621.0" + cmake -Bbuild -GNinja "-DCMAKE_SYSTEM_VERSION=$cmake_sys_version" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL "-DLLVM_DIR=$llvm_dir" -DWASMEDGE_BUILD_TESTS=ON -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_TOOLS=OFF + + Write-Output "Building $Env:tar_names backend:" + cmake -Bbuild -GNinja "$Env:build_options" + cmake --build build --target "$Env:test_bin" + + $Env:PATH += ";$pwd\\build\\lib\\api" + Write-Output "Testing $Env:tar_names backend:" + cmake -E chdir "$Env:test_dir" "$Env:test_bin" + + Write-Output "Copying $Env:tar_names backend:" + Copy-Item "$Env:output_dir/$Env:output_bin" -Destination "./$Env:output_bin" + + Write-Output "Compress-Archive -Path $Env:output_bin -DestinationPath plugin_${Env:tar_names}.zip -CompressionLevel Optimal" + Compress-Archive -Path "$Env:output_bin" -DestinationPath "plugin_${Env:tar_names}.zip" -CompressionLevel Optimal + ls "plugin_${Env:tar_names}.zip" + - name: Upload artifact - wasi_nn-ggml + uses: actions/upload-artifact@v3 + with: + name: WasmEdge-plugin-wasi_nn-ggml-${{ needs.get_version.outputs.version }}-windows.zip + path: plugin_wasi_nn-ggml.zip + build_ubuntu: + permissions: + contents: write strategy: matrix: include: @@ -192,34 +354,39 @@ jobs: env: output_prefix: build/plugins test_prefix: build/test/plugins - build_options: -DWASMEDGE_PLUGIN_WASI_CRYPTO=ON -DWASMEDGE_PLUGIN_WASI_LOGGING=ON -DWASMEDGE_PLUGIN_PROCESS=ON -DWASMEDGE_PLUGIN_TENSORFLOW=ON -DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON -DWASMEDGE_PLUGIN_IMAGE=ON -DWASMEDGE_PLUGIN_WASM_BPF=ON -DWASMEDGE_PLUGIN_OPENCVMINI=ON -DWASMEDGE_PLUGIN_ZLIB=ON - tar_names: wasi_crypto wasi_logging wasmedge_process wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasm_bpf wasmedge_opencvmini wasmedge_zlib - test_bins: wasiCryptoTests wasiLoggingTests wasmedgeProcessTests wasmedgeTensorflowTests wasmedgeTensorflowLiteTests wasmedgeImageTests wasmBpfTests wasmedgeOpencvminiTests wasmedgeZlibTests - output_bins: libwasmedgePluginWasiCrypto.so libwasmedgePluginWasiLogging.so libwasmedgePluginWasmEdgeProcess.so libwasmedgePluginWasmEdgeTensorflow.so libwasmedgePluginWasmEdgeTensorflowLite.so libwasmedgePluginWasmEdgeImage.so libwasmedgePluginWasmBpf.so libwasmedgePluginWasmEdgeOpenCVMini.so libwasmedgePluginWasmEdgeZlib.so - needs: [get_version] + build_options: -DWASMEDGE_PLUGIN_WASI_CRYPTO=ON -DWASMEDGE_PLUGIN_PROCESS=ON -DWASMEDGE_PLUGIN_TENSORFLOW=ON -DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON -DWASMEDGE_PLUGIN_IMAGE=ON -DWASMEDGE_PLUGIN_WASM_BPF=ON -DWASMEDGE_PLUGIN_OPENCVMINI=ON -DWASMEDGE_PLUGIN_ZLIB=ON -DWASMEDGE_PLUGIN_FFMPEG=ON -DWASMEDGE_PLUGIN_STABLEDIFFUSION=ON -DWASMEDGE_PLUGIN_LLMC=ON + tar_names: wasi_crypto wasmedge_process wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasm_bpf wasmedge_opencvmini wasmedge_zlib wasmedge_ffmpeg wasmedge_stablediffusion wasmedge_llmc + test_bins: wasiCryptoTests wasmedgeProcessTests wasmedgeTensorflowTests wasmedgeTensorflowLiteTests wasmedgeImageTests wasmBpfTests wasmedgeOpencvminiTests wasmedgeZlibTests wasmedgeFFmpegTests wasmedgeStableDiffusionTests wasmedgeLLMCTests + output_bins: libwasmedgePluginWasiCrypto.so libwasmedgePluginWasmEdgeProcess.so libwasmedgePluginWasmEdgeTensorflow.so libwasmedgePluginWasmEdgeTensorflowLite.so libwasmedgePluginWasmEdgeImage.so libwasmedgePluginWasmBpf.so libwasmedgePluginWasmEdgeOpenCVMini.so libwasmedgePluginWasmEdgeZlib.so libwasmedgePluginWasmEdgeFFmpeg.so libwasmedgePluginWasmEdgeStableDiffusion.so libwasmedgePluginWasmEdgeLLMC.so + needs: [ get_version ] container: image: wasmedge/wasmedge:${{ matrix.docker_tag }} # Required for mounting debugfs # Tests of wasm_bpf also require privileges options: --privileged steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install dependencies run: | apt update apt install -y libssl-dev - apt install -y libelf-dev zlib1g-dev pkg-config - apt install -y clang llvm + apt install -y libelf-dev zlib1g-dev pkg-config libomp-dev + apt install -y clang-15 apt install -y cargo + apt install -y yasm # Running tests of wasm_bpf requires proper ebpf running environment mount -t debugfs none /sys/kernel/debug + bash utils/ffmpeg/install-ffmpeg-v6.0.sh - name: Build plugins using ${{ matrix.compiler }} with ${{ matrix.build_type }} mode shell: bash run: | + update-alternatives --install /usr/bin/clang clang /usr/bin/clang-15 100 + update-alternatives --install /usr/bin/llvm-strip llvm-strip /usr/bin/llvm-strip-15 100 testbin_array=(${test_bins}) - cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DWASMEDGE_BUILD_TESTS=ON -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DWASMEDGE_BUILD_TOOLS=OFF ${build_options} + export PKG_CONFIG_PATH=$(pwd)/FFmpeg-n6.0/output/lib/pkgconfig + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DWASMEDGE_BUILD_TESTS=ON -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_TOOLS=OFF ${build_options} for (( i=0; i<${#testbin_array[@]}; i++ )); do echo "Building ${testbin_array[$i]} :" @@ -228,6 +395,7 @@ jobs: - name: Test plugins shell: bash run: | + export LD_LIBRARY_PATH=$(pwd)/FFmpeg-n6.0/output/lib:$LD_LIBRARY_PATH plugin_array=(${tar_names}) testbin_array=(${test_bins}) for (( i=0; i<${#plugin_array[@]}; i++ )); @@ -253,11 +421,6 @@ jobs: with: name: WasmEdge-plugin-wasi_crypto-${{ needs.get_version.outputs.version }}-ubuntu22.04-${{ matrix.compiler }}.tar.gz path: plugin_wasi_crypto.tar.gz - - name: Upload artifact - wasi_logging - uses: actions/upload-artifact@v3 - with: - name: WasmEdge-plugin-wasi_logging-${{ needs.get_version.outputs.version }}-ubuntu22.04-${{ matrix.compiler }}.tar.gz - path: plugin_wasi_logging.tar.gz - name: Upload artifact - wasmedge_process uses: actions/upload-artifact@v3 with: @@ -293,186 +456,147 @@ jobs: with: name: WasmEdge-plugin-wasmedge_zlib-${{ needs.get_version.outputs.version }}-ubuntu22.04-${{ matrix.compiler }}.tar.gz path: plugin_wasmedge_zlib.tar.gz + - name: Upload artifact - wasmedge_ffmpeg + uses: actions/upload-artifact@v3 + with: + name: WasmEdge-plugin-wasmedge_ffmpeg-${{ needs.get_version.outputs.version }}-ubuntu22.04-${{ matrix.compiler }}.tar.gz + path: plugin_wasmedge_ffmpeg.tar.gz + - name: Upload artifact - wasmedge_stablediffusion + uses: actions/upload-artifact@v3 + with: + name: WasmEdge-plugin-wasmedge_stablediffusion-${{ needs.get_version.outputs.version }}-ubuntu22.04-${{ matrix.compiler }}.tar.gz + path: plugin_wasmedge_stablediffusion.tar.gz + - name: Upload artifact - wasmedge_llmc + uses: actions/upload-artifact@v3 + with: + name: WasmEdge-plugin-wasmedge_llmc-${{ needs.get_version.outputs.version }}-ubuntu22.04-${{ matrix.compiler }}.tar.gz + path: plugin_wasmedge_llmc.tar.gz - # Due to the dependencies and exclusions of WASI-NN, build them saperately. - build_wasinn_manylinux: - name: WASI-NN (manylinux, g++, Release) - needs: get_version - uses: ./.github/workflows/reusable-build-extensions.yml - with: - version: ${{ needs.get_version.outputs.version }} - - build_manylinux: + # Build CUDA related plugins, only on Ubuntu 20.04 currently. + build_ubuntu_cuda: + permissions: + contents: write strategy: matrix: include: - - name: Plugins_x86_64 - host_runner: ubuntu-latest - docker_tag: manylinux2014_x86_64-plugins-deps - build_type: Release - - name: Plugins_aarch64 - host_runner: linux-arm64 - docker_tag: manylinux2014_aarch64-plugins-deps - build_type: Release - name: Plugins (${{ matrix.docker_tag }}, g++, ${{ matrix.build_type }}) - runs-on: ${{ matrix.host_runner }} + - cuda_version: '11.3' + - cuda_version: '12.0' + name: Plugins (CUDA ${{ matrix.cuda_version }}) + runs-on: ubuntu-latest + needs: [ get_version ] + container: wasmedge/wasmedge:ubuntu-20.04-build-gcc env: + CUDA_VER: ${{ matrix.cuda_version }} + CUDAARCHS: "60;61;70" output_prefix: build/plugins test_prefix: build/test/plugins - build_options_all_platforms: -DWASMEDGE_PLUGIN_WASI_CRYPTO=ON -DWASMEDGE_PLUGIN_WASI_LOGGING=ON -DWASMEDGE_PLUGIN_PROCESS=ON -DWASMEDGE_PLUGIN_TENSORFLOW=ON -DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON -DWASMEDGE_PLUGIN_IMAGE=ON -DWASMEDGE_PLUGIN_OPENCVMINI=ON -DWASMEDGE_PLUGIN_ZLIB=ON - build_options_manylinux2014_x86_64: -DWASMEDGE_PLUGIN_WASM_BPF=ON -DWASMEDGE_PLUGIN_WASM_BPF_BUILD_LIBBPF_WITH_PKG_CONF=OFF - build_options_manylinux2014_aarch64: - tar_names_all_platforms: wasi_crypto wasi_logging wasmedge_process wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasmedge_opencvmini wasmedge_zlib - tar_names_manylinux2014_x86_64: wasm_bpf - tar_names_manylinux2014_aarch64: - test_bins_all_platforms: wasiCryptoTests wasiLoggingTests wasmedgeProcessTests wasmedgeTensorflowTests wasmedgeTensorflowLiteTests wasmedgeImageTests wasmedgeOpencvminiTests wasmedgeZlibTests - test_bins_manylinux2014_x86_64: wasmBpfTests - test_bins_manylinux2014_aarch64: - output_bins_all_platforms: libwasmedgePluginWasiCrypto.so libwasmedgePluginWasiLogging.so libwasmedgePluginWasmEdgeProcess.so libwasmedgePluginWasmEdgeTensorflow.so libwasmedgePluginWasmEdgeTensorflowLite.so libwasmedgePluginWasmEdgeImage.so libwasmedgePluginWasmEdgeOpenCVMini.so libwasmedgePluginWasmEdgeZlib.so - output_bins_manylinux2014_x86_64: libwasmedgePluginWasmBpf.so - output_bins_manylinux2014_aarch64: - needs: [get_version] - container: - image: wasmedge/wasmedge:${{ matrix.docker_tag }} - # Required for mounting debugfs - # Tests of wasm_bpf also require privileges - options: --privileged + build_options: -DWASMEDGE_PLUGIN_STABLEDIFFUSION=ON -DWASMEDGE_PLUGIN_STABLEDIFFUSION_CUBLAS=ON + tar_names: wasmedge_stablediffusion + test_bins: wasmedgeStableDiffusionTests + output_bins: libwasmedgePluginWasmEdgeStableDiffusion.so steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Build and install dependencies + - name: Install dependencies + shell: bash run: | - yum update -y - yum install -y zlib-devel zlib-static cmake curl - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y - bash ./utils/wasi-crypto/build-openssl.sh - # Running tests of wasm_bpf requires proper ebpf running environment - mount -t debugfs none /sys/kernel/debug - - name: Build and test plugins using g++ with ${{ matrix.build_type }} mode + CUDA_KEYRING=cuda-keyring_1.1-1_all.deb + NVCC_VER=${CUDA_VER//./-} + wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/${CUDA_KEYRING} + dpkg -i ${CUDA_KEYRING} + rm -f ${CUDA_KEYRING} + wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null + apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" + apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 6AF7F09730B3F0A4 + export DEBIAN_FRONTEND=noninteractive + apt-get update + apt-get remove -y --purge --auto-remove cmake + apt-get upgrade -y + apt-get install -y cmake cuda-nvcc-${NVCC_VER} libcublas-dev-${NVCC_VER} lsb-release pkg-config software-properties-common unzip + - name: Build plugins with CUDA (skip testing as there is no GPU on the CI runner) shell: bash run: | - source "$HOME/.cargo/env" - testbin_array=(${test_bins_all_platforms} ${test_bins_${{ matrix.docker_tag }}}) - cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DWASMEDGE_BUILD_TESTS=ON -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DWASMEDGE_BUILD_TOOLS=OFF ${build_options_all_platforms} ${build_options_${{ matrix.docker_tag }}} -DOPENSSL_ROOT_DIR=$(pwd)/openssl-1.1.1n/openssl + export CXXFLAGS="-Wno-error" + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_TESTS=ON -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DWASMEDGE_BUILD_TOOLS=OFF -DCMAKE_CUDA_ARCHITECTURES="${CUDAARCHS}" -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc -DWASMEDGE_USE_LLVM=OFF ${build_options} + plugin_array=(${tar_names}) + testbin_array=(${test_bins}) for (( i=0; i<${#testbin_array[@]}; i++ )); do echo "Building ${testbin_array[$i]} :" cmake --build build --target ${testbin_array[$i]} + echo "Testing ${plugin_array[$i]} (skipped)" done - - name: Test plugins - shell: bash - run: | - plugin_array=(${tar_names_all_platforms} ${tar_names_${{ matrix.docker_tag }}}) - testbin_array=(${test_bins_all_platforms} ${test_bins_${{ matrix.docker_tag }}}) - for (( i=0; i<${#plugin_array[@]}; i++ )); - do - echo "Testing ${plugin_array[$i]} :" - cd ${test_prefix}/${plugin_array[$i]} - ./${testbin_array[$i]} - cd - - done - - name: Prepare the WasmEdge plugins tar.gz package + - name: Prepare the plugins tar.gz package shell: bash run: | - plugin_array=(${tar_names_all_platforms} ${tar_names_${{ matrix.docker_tag }}}) - outbin_array=(${output_bins_all_platforms} ${output_bins_${{ matrix.docker_tag }}}) + plugin_array=(${tar_names}) + outbin_array=(${output_bins}) for (( i=0; i<${#plugin_array[@]}; i++ )); do echo "Copying ${plugin_array[$i]} :" cp ${output_prefix}/${plugin_array[$i]}/${outbin_array[$i]} ${outbin_array[$i]} tar -zcvf plugin_${plugin_array[$i]}.tar.gz ${outbin_array[$i]} done - - name: Upload artifact - wasi_crypto - uses: actions/upload-artifact@v3 - with: - name: WasmEdge-plugin-wasi_crypto-${{ needs.get_version.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - path: plugin_wasi_crypto.tar.gz - - name: Upload artifact - wasi_logging - uses: actions/upload-artifact@v3 - with: - name: WasmEdge-plugin-wasi_logging-${{ needs.get_version.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - path: plugin_wasi_logging.tar.gz - - name: Upload artifact - wasmedge_process - uses: actions/upload-artifact@v3 - with: - name: WasmEdge-plugin-wasmedge_process-${{ needs.get_version.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - path: plugin_wasmedge_process.tar.gz - - name: Upload artifact - wasmedge_tensorflow - uses: actions/upload-artifact@v3 - with: - name: WasmEdge-plugin-wasmedge_tensorflow-${{ needs.get_version.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - path: plugin_wasmedge_tensorflow.tar.gz - - name: Upload artifact - wasmedge_tensorflowlite - uses: actions/upload-artifact@v3 - with: - name: WasmEdge-plugin-wasmedge_tensorflowlite-${{ needs.get_version.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - path: plugin_wasmedge_tensorflowlite.tar.gz - - name: Upload artifact - wasmedge_image - uses: actions/upload-artifact@v3 - with: - name: WasmEdge-plugin-wasmedge_image-${{ needs.get_version.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - path: plugin_wasmedge_image.tar.gz - - name: Upload artifact - wasm_bpf - if: contains(matrix.docker_tag, 'manylinux2014_x86_64') - uses: actions/upload-artifact@v3 - with: - name: WasmEdge-plugin-wasm_bpf-${{ needs.get_version.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - path: plugin_wasm_bpf.tar.gz - - name: Upload artifact - wasmedge_opencvmini - uses: actions/upload-artifact@v3 - with: - name: WasmEdge-plugin-wasmedge_opencvmini-${{ needs.get_version.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - path: plugin_wasmedge_opencvmini.tar.gz - - name: Upload artifact - wasmedge_zlib + - name: Upload artifact - wasmedge_stablediffusion uses: actions/upload-artifact@v3 with: - name: WasmEdge-plugin-wasmedge_zlib-${{ needs.get_version.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - path: plugin_wasmedge_zlib.tar.gz + name: WasmEdge-plugin-wasmedge_stablediffusion-cuda-${{ matrix.cuda_version }}-${{ needs.get_version.outputs.version }}-ubuntu20.04_x86_64.tar.gz + path: plugin_wasmedge_stablediffusion.tar.gz + + build_manylinux: + permissions: + contents: write + name: manylinux, g++, Release + needs: get_version + uses: ./.github/workflows/reusable-build-extensions.yml + with: + version: ${{ needs.get_version.outputs.version }} build_macos: + permissions: + contents: write strategy: matrix: include: - - name: Plugins_MacOS_12 - system: MacOS 12 + - system: MacOS 12 (x86_64) host_runner: macos-12 darwin_version: darwin_21 build_type: Release arch: x86_64 - - name: Plugins_MacOS_arm64 - system: MacOS 13 (arm64) + - system: MacOS 14 (arm64) host_runner: macos-14 - darwin_version: darwin_22 + darwin_version: darwin_23 build_type: Release arch: arm64 - name: Plugins (${{ matrix.system }}, clang++, ${{ matrix.build_type }}) + name: Plugins (${{ matrix.system }}, clang++, ${{ matrix.build_type }}) runs-on: ${{ matrix.host_runner }} env: output_prefix: build/plugins test_prefix: build/test/plugins - build_options: -DWASMEDGE_PLUGIN_WASI_CRYPTO=ON -DWASMEDGE_PLUGIN_WASI_LOGGING=ON -DWASMEDGE_PLUGIN_TENSORFLOW=ON -DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON -DWASMEDGE_PLUGIN_IMAGE=ON -DWASMEDGE_PLUGIN_OPENCVMINI=ON - tar_names: wasi_crypto wasi_logging wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasmedge_opencvmini - test_bins: wasiCryptoTests wasiLoggingTests wasmedgeTensorflowTests wasmedgeTensorflowLiteTests wasmedgeImageTests wasmedgeOpencvminiTests - output_bins: libwasmedgePluginWasiCrypto.dylib libwasmedgePluginWasiLogging.dylib libwasmedgePluginWasmEdgeTensorflow.dylib libwasmedgePluginWasmEdgeTensorflowLite.dylib libwasmedgePluginWasmEdgeImage.dylib libwasmedgePluginWasmEdgeOpenCVMini.dylib - needs: [get_version] + build_options: -DWASMEDGE_PLUGIN_WASI_CRYPTO=ON -DWASMEDGE_PLUGIN_TENSORFLOW=ON -DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON -DWASMEDGE_PLUGIN_IMAGE=ON -DWASMEDGE_PLUGIN_OPENCVMINI=ON -DWASMEDGE_PLUGIN_FFMPEG=ON -DWASMEDGE_PLUGIN_STABLEDIFFUSION=ON -DWASMEDGE_PLUGIN_LLMC=ON + tar_names: wasi_crypto wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasmedge_opencvmini wasmedge_ffmpeg wasmedge_stablediffusion wasmedge_llmc + test_bins: wasiCryptoTests wasmedgeTensorflowTests wasmedgeTensorflowLiteTests wasmedgeImageTests wasmedgeOpencvminiTests wasmedgeFFmpegTests wasmedgeStableDiffusionTests wasmedgeLLMCTests + output_bins: libwasmedgePluginWasiCrypto.dylib libwasmedgePluginWasmEdgeTensorflow.dylib libwasmedgePluginWasmEdgeTensorflowLite.dylib libwasmedgePluginWasmEdgeImage.dylib libwasmedgePluginWasmEdgeOpenCVMini.dylib libwasmedgePluginWasmEdgeFFmpeg.dylib libwasmedgePluginWasmEdgeStableDiffusion.dylib libwasmedgePluginWasmEdgeLLMC.dylib + needs: [ get_version ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Build and install dependencies run: | eval $(/opt/homebrew/bin/brew shellenv) - brew install llvm@16 ninja cmake openssl opencv rust + brew install llvm@16 ninja cmake openssl opencv rust ffmpeg@6 - name: Build WasmEdge plugins using clang++ with ${{ matrix.build_type }} mode shell: bash run: | eval $(/opt/homebrew/bin/brew shellenv) testbin_array=(${test_bins}) + export PKG_CONFIG_PATH="$(brew --prefix)/opt/ffmpeg@6/lib/pkgconfig:$PKG_CONFIG_PATH" export LLVM_DIR="$(brew --prefix)/opt/llvm@16/lib/cmake" export CC=clang export CXX=clang++ - cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DWASMEDGE_BUILD_TESTS=ON -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DWASMEDGE_BUILD_TOOLS=OFF ${build_options} -DOPENSSL_ROOT_DIR=$(brew --prefix)/opt/openssl + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DWASMEDGE_BUILD_TESTS=ON -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_TOOLS=OFF ${build_options} -DOPENSSL_ROOT_DIR=$(brew --prefix)/opt/openssl for (( i=0; i<${#testbin_array[@]}; i++ )); do echo "Building ${testbin_array[$i]} :" @@ -512,11 +636,6 @@ jobs: with: name: WasmEdge-plugin-wasi_crypto-${{ needs.get_version.outputs.version }}-${{ matrix.darwin_version }}_${{ matrix.arch }}.tar.gz path: plugin_wasi_crypto.tar.gz - - name: Upload artifact - wasi_logging - uses: actions/upload-artifact@v3 - with: - name: WasmEdge-plugin-wasi_logging-${{ needs.get_version.outputs.version }}-${{ matrix.darwin_version }}_${{ matrix.arch }}.tar.gz - path: plugin_wasi_logging.tar.gz - name: Upload artifact - wasmedge_tensorflow uses: actions/upload-artifact@v3 with: @@ -537,3 +656,87 @@ jobs: with: name: WasmEdge-plugin-wasmedge_opencvmini-${{ needs.get_version.outputs.version }}-${{ matrix.darwin_version }}_${{ matrix.arch }}.tar.gz path: plugin_wasmedge_opencvmini.tar.gz + - name: Upload artifact - wasmedge_ffmpeg + uses: actions/upload-artifact@v3 + with: + name: WasmEdge-plugin-wasmedge_ffmpeg-${{ needs.get_version.outputs.version }}-${{ matrix.darwin_version }}_${{ matrix.arch }}.tar.gz + path: plugin_wasmedge_ffmpeg.tar.gz + - name: Upload artifact - wasmedge_stablediffusion + if: ${{ matrix.arch != 'arm64' }} + uses: actions/upload-artifact@v3 + with: + name: WasmEdge-plugin-wasmedge_stablediffusion-${{ needs.get_version.outputs.version }}-${{ matrix.darwin_version }}_${{ matrix.arch }}.tar.gz + path: plugin_wasmedge_stablediffusion.tar.gz + - name: Upload artifact - wasmedge_llmc + uses: actions/upload-artifact@v3 + with: + name: WasmEdge-plugin-wasmedge_llmc-${{ needs.get_version.outputs.version }}-${{ matrix.darwin_version }}_${{ matrix.arch }}.tar.gz + path: plugin_wasmedge_llmc.tar.gz + + build_macos_metal: + permissions: + contents: write + strategy: + matrix: + include: + - system: MacOS 14 (arm64) + host_runner: macos-14 + darwin_version: darwin_23 + build_type: Release + arch: arm64 + name: Plugins (Metal, ${{ matrix.system }}, clang++, ${{ matrix.build_type }}) + runs-on: ${{ matrix.host_runner }} + env: + output_prefix: build/plugins + test_prefix: build/test/plugins + build_options: -DWASMEDGE_PLUGIN_STABLEDIFFUSION=ON -DWASMEDGE_PLUGIN_STABLEDIFFUSION_METAL=ON + tar_names: wasmedge_stablediffusion + test_bins: wasmedgeStableDiffusionTests + output_bins: libwasmedgePluginWasmEdgeStableDiffusion.dylib + needs: [ get_version ] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Build and install dependencies + run: | + eval $(/opt/homebrew/bin/brew shellenv) + brew install llvm@16 ninja cmake + - name: Build WasmEdge plugins using clang++ with ${{ matrix.build_type }} mode + shell: bash + run: | + eval $(/opt/homebrew/bin/brew shellenv) + testbin_array=(${test_bins}) + export LLVM_DIR="$(brew --prefix)/opt/llvm@16/lib/cmake" + export CC=clang + export CXX=clang++ + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DWASMEDGE_BUILD_TESTS=ON -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_TOOLS=OFF ${build_options} -DOPENSSL_ROOT_DIR=$(brew --prefix)/opt/openssl + for (( i=0; i<${#testbin_array[@]}; i++ )); + do + echo "Building ${testbin_array[$i]} :" + cmake --build build --target ${testbin_array[$i]} + done + - name: Test WasmEdge plugins (skipped) + shell: bash + run: | + echo 'The GitHub Actions runner does not support some instructions for Metal GPU testing.' + - name: Prepare the WasmEdge plugins tar.gz package (with metal files) + shell: bash + run: | + eval $(/opt/homebrew/bin/brew shellenv) + plugin_array=(${tar_names}) + outbin_array=(${output_bins}) + for (( i=0; i<${#plugin_array[@]}; i++ )); + do + echo "Copying ${plugin_array[$i]} :" + for plugin_files in "${outbin_array[$i]}" "ggml-metal.metal" "ggml-common.h" + do + cp ${output_prefix}/${plugin_array[$i]}/$plugin_files . + done + tar -zcvf plugin_${plugin_array[$i]}.tar.gz "${outbin_array[$i]}" "ggml-metal.metal" "ggml-common.h" + done + - name: Upload artifact - wasmedge_stablediffusion + uses: actions/upload-artifact@v3 + with: + name: WasmEdge-plugin-wasmedge_stablediffusion-${{ needs.get_version.outputs.version }}-${{ matrix.darwin_version }}_${{ matrix.arch }}.tar.gz + path: plugin_wasmedge_stablediffusion.tar.gz diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index abb87318214f..a728a3a1c98c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,8 +15,8 @@ on: - ".github/workflows/reusable-create-source-tarball.yml" - "include/**" - "lib/**" - - "plugins/**" - "test/**" + - "!test/plugins/**" - "thirdparty/**" - "tools/**" - "CMakeLists.txt" @@ -32,34 +32,30 @@ on: - ".github/workflows/reusable-create-source-tarball.yml" - "include/**" - "lib/**" - - "plugins/**" - "test/**" + - "!test/plugins/**" - "thirdparty/**" - "tools/**" - "CMakeLists.txt" - "cmake/**" permissions: - contents: write + contents: read jobs: # TODO: Refactor `lint` with `on.workflow_run` # https://docs.github.com/en/actions/using-workflows/triggering-a-workflow lint: - permissions: - contents: read uses: ./.github/workflows/reusable-call-linter.yml get_version: - permissions: - contents: read needs: lint name: Retrieve version information runs-on: ubuntu-latest outputs: version: ${{ steps.prep.outputs.version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory @@ -74,6 +70,8 @@ jobs: echo "version=$(git describe --match '[0-9].[0-9]*' --tag)" >> $GITHUB_OUTPUT create_source_tarball: + permissions: + contents: write needs: [get_version, lint] name: Source Tarball uses: ./.github/workflows/reusable-create-source-tarball.yml @@ -81,24 +79,41 @@ jobs: version: ${{ needs.get_version.outputs.version }} build_on_macos: + permissions: + contents: write needs: [get_version, lint] name: macOS uses: ./.github/workflows/reusable-build-on-macos.yml with: version: ${{ needs.get_version.outputs.version }} matrix: "[{'name':'MacOS 12 (x86_64)','runner':'macos-12','darwin_version':21,'arch':'x86_64'}, - {'name':'MacOS 13 (arm64)','runner':'macos-14','darwin_version':22,'arch':'arm64'}]" + {'name':'MacOS 14 (arm64)','runner':'macos-14','darwin_version':23,'arch':'arm64'}]" + + build_on_manylinux2014: + permissions: + contents: write + needs: [get_version, lint] + name: Manylinux2014 (deprecated) + uses: ./.github/workflows/reusable-build-on-manylinux.yml + with: + version: ${{ needs.get_version.outputs.version }} + matrix: "[{'name':'manylinux2014 x86_64','runner':'ubuntu-latest','docker_tag':'manylinux2014_x86_64-plugins-deps','asset_tag':'manylinux2014_x86_64'}, + {'name':'manylinux2014 aarch64','runner':'linux-arm64-v2','docker_tag':'manylinux2014_aarch64-plugins-deps','asset_tag':'manylinux2014_aarch64'}]" - build_on_manylinux_2014: + build_on_manylinux_2_28: + permissions: + contents: write needs: [get_version, lint] - name: Manylinux2014 + name: Manylinux_2_28 uses: ./.github/workflows/reusable-build-on-manylinux.yml with: version: ${{ needs.get_version.outputs.version }} - matrix: "[{'name':'manylinux 2014 x86_64','runner':'ubuntu-latest','docker_tag':'manylinux2014_x86_64'}, - {'name':'manylinux 2014 aarch64','runner':'linux-arm64','docker_tag':'manylinux2014_aarch64'}]" + matrix: "[{'name':'manylinux_2_28 x86_64','runner':'ubuntu-latest','docker_tag':'manylinux_2_28_x86_64','asset_tag':'manylinux_2_28_x86_64'}, + {'name':'manylinux_2_28 aarch64','runner':'linux-arm64-v2','docker_tag':'manylinux_2_28_aarch64','asset_tag':'manylinux_2_28_x86_64'}]" build_on_debian_static: + permissions: + contents: write needs: [get_version, lint] name: Debian (static) uses: ./.github/workflows/reusable-build-on-debian-static.yml @@ -106,6 +121,8 @@ jobs: version: ${{ needs.get_version.outputs.version }} build_on_alpine_static: + permissions: + contents: write needs: [get_version, lint] name: Alpine (static) uses: ./.github/workflows/reusable-build-on-alpine-static.yml @@ -113,19 +130,25 @@ jobs: version: ${{ needs.get_version.outputs.version }} build_on_ubuntu_22_04: + permissions: + contents: write needs: [get_version, lint] name: Ubuntu uses: ./.github/workflows/reusable-build-on-ubuntu.yml + secrets: inherit with: version: ${{ needs.get_version.outputs.version }} - matrix: "[{'name':'ubuntu-22.04','compiler':'g++','build_type':'Debug','docker_tag':'ubuntu-build-gcc','tests':true}, - {'name':'ubuntu-22.04','compiler':'g++','build_type':'Release','docker_tag':'ubuntu-build-gcc','tests':true}, - {'name':'ubuntu-22.04','compiler':'clang++','build_type':'Debug','docker_tag':'ubuntu-build-clang','tests':true}, - {'name':'ubuntu-22.04','compiler':'clang++','build_type':'Release','docker_tag':'ubuntu-build-clang','tests':true}, - {'name':'linux-static','compiler':'clang++','build_type':'Release','docker_tag':'ubuntu-build-clang','options':'-DWASMEDGE_BUILD_SHARED_LIB=Off -DWASMEDGE_BUILD_STATIC_LIB=On -DWASMEDGE_LINK_TOOLS_STATIC=On -DWASMEDGE_BUILD_PLUGINS=Off'}, - {'name':'ubuntu-22.04-coverage','compiler':'g++','build_type':'Debug','docker_tag':'ubuntu-build-gcc','coverage':true,'tests':true}]" + matrix: "[{'name':'ubuntu-22.04','arch':'x86_64','runner':'ubuntu-latest','compiler':'g++','build_type':'Debug','docker_tag':'ubuntu-build-gcc','tests':true}, + {'name':'ubuntu-22.04','arch':'x86_64','runner':'ubuntu-latest','compiler':'g++','build_type':'Release','docker_tag':'ubuntu-build-gcc','tests':true}, + {'name':'ubuntu-22.04','arch':'x86_64','runner':'ubuntu-latest','compiler':'clang++','build_type':'Debug','docker_tag':'ubuntu-build-clang','tests':true}, + {'name':'ubuntu-22.04','arch':'x86_64','runner':'ubuntu-latest','compiler':'clang++','build_type':'Release','docker_tag':'ubuntu-build-clang','tests':true}, + {'name':'ubuntu-20.04','arch':'aarch64','runner':'linux-arm64-v2','compiler':'clang++','build_type':'Release','docker_tag':'ubuntu-20.04-build-clang-aarch64','tests':true}, + {'name':'linux-static','arch':'x86_64','runner':'ubuntu-latest','compiler':'clang++','build_type':'Release','docker_tag':'ubuntu-build-clang','options':'-DWASMEDGE_BUILD_SHARED_LIB=Off -DWASMEDGE_BUILD_STATIC_LIB=On -DWASMEDGE_LINK_TOOLS_STATIC=On -DWASMEDGE_BUILD_PLUGINS=Off'}, + {'name':'ubuntu-22.04-coverage','arch':'x86_64','runner':'ubuntu-latest','compiler':'g++','build_type':'Debug','docker_tag':'ubuntu-build-gcc','coverage':true,'tests':true}]" build_on_windows: + permissions: + contents: write needs: [get_version, lint] name: Windows uses: ./.github/workflows/reusable-build-on-windows.yml @@ -133,6 +156,8 @@ jobs: version: ${{ needs.get_version.outputs.version }} build_on_windows_msvc: + permissions: + contents: write needs: [get_version, lint] name: Windows-MSVC uses: ./.github/workflows/reusable-build-on-windows-msvc.yml @@ -140,6 +165,8 @@ jobs: version: ${{ needs.get_version.outputs.version }} build_on_android: + permissions: + contents: write needs: [get_version, lint] name: Android uses: ./.github/workflows/reusable-build-on-android.yml @@ -147,8 +174,19 @@ jobs: version: ${{ needs.get_version.outputs.version }} build_on_fedora: + permissions: + contents: write needs: [get_version, lint] name: Fedora uses: ./.github/workflows/reusable-build-on-fedora.yml with: version: ${{ needs.get_version.outputs.version }} + + build_on_debian: + permissions: + contents: write + needs: [get_version, lint] + name: Debian + uses: ./.github/workflows/reusable-build-on-debian.yml + with: + version: ${{ needs.get_version.outputs.version }} diff --git a/.github/workflows/build_for_nix.yml b/.github/workflows/build_for_nix.yml new file mode 100644 index 000000000000..cf4c72e7c33d --- /dev/null +++ b/.github/workflows/build_for_nix.yml @@ -0,0 +1,41 @@ +name: Build WasmEdge on Nix + +on: + push: + branches: + - master + paths: + - "flake.nix" + - "flake.lock" + - ".github/workflows/build_for_nix.yml" + - "include/**" + - "lib/**" + - "thirdparty/**" + - "tools/**" + - "CMakeLists.txt" + - "cmake/**" + pull_request: + branches: + - master + - "proposal/**" + paths: + - "flake.nix" + - "flake.lock" + - ".github/workflows/build_for_nix.yml" + - "include/**" + - "lib/**" + - "thirdparty/**" + - "tools/**" + - "CMakeLists.txt" + - "cmake/**" + +jobs: + build_nix: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v27 + with: + nix_path: nixpkgs=channel:nixos-24.05 + - run: nix build + - run: nix flake check diff --git a/.github/workflows/build_for_openwrt.yml b/.github/workflows/build_for_openwrt.yml index 832f06d753f3..ab280f64498f 100644 --- a/.github/workflows/build_for_openwrt.yml +++ b/.github/workflows/build_for_openwrt.yml @@ -44,7 +44,7 @@ jobs: needs: lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory @@ -143,4 +143,3 @@ jobs: docker build -t openwrt . docker run --name openwrt -d --privileged openwrt:latest /sbin/init docker exec openwrt wasmedge -v - diff --git a/.github/workflows/build_for_riscv.yml b/.github/workflows/build_for_riscv.yml index ab069318ce1d..c9e45077e8be 100644 --- a/.github/workflows/build_for_riscv.yml +++ b/.github/workflows/build_for_riscv.yml @@ -12,8 +12,8 @@ on: - ".github/workflows/build_for_riscv.yml" - "include/**" - "lib/**" - - "plugins/**" - "test/**" + - "!test/plugins/**" - "thirdparty/**" - "tools/**" - "CMakeLists.txt" @@ -26,8 +26,8 @@ on: - ".github/workflows/build_for_riscv.yml" - "include/**" - "lib/**" - - "plugins/**" - "test/**" + - "!test/plugins/**" - "thirdparty/**" - "tools/**" - "CMakeLists.txt" @@ -47,7 +47,7 @@ jobs: runs-on: ubuntu-latest needs: lint steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory @@ -56,7 +56,8 @@ jobs: - uses: uraimo/run-on-arch-action@v2 name: Build WasmEdge with: - base_image: riscv64/ubuntu + arch: riscv64 + distro: ubuntu22.04 githubToken: ${{ github.token }} dockerRunArgs: | --volume "${PWD}:/workplace" @@ -65,7 +66,7 @@ jobs: apt-get update -q -y apt-get install -q -y git cmake g++ dpkg apt-get install -q -y software-properties-common - apt-get install -q -y llvm-12-dev liblld-12-dev + apt-get install -q -y llvm-15-dev liblld-15-dev zlib1g-dev apt-get install -q -y wabt # For generating wasm run: | mkdir -p build && cd build diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8c3f00a91b96..3e23b8ef0f52 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -69,7 +69,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Ensure git safe directory run: | git config --global --add safe.directory $(pwd) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 53b76eee23c7..b571eae56ccb 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -6,17 +6,23 @@ concurrency: on: push: - tags: - - '*.*.*' branches: - master paths: - - 'utils/docker/**' - '.github/workflows/docker.yml' + - 'utils/docker/**' + - 'utils/ffmpeg/**' + - 'utils/opencvmini/**' + - 'utils/wasi-crypto/**' + - 'utils/wasi-nn/**' pull_request: paths: - - 'utils/docker/**' - '.github/workflows/docker.yml' + - 'utils/docker/**' + - 'utils/ffmpeg/**' + - 'utils/opencvmini/**' + - 'utils/wasi-crypto/**' + - 'utils/wasi-nn/**' schedule: - cron: "0 0 */7 * *" @@ -50,16 +56,54 @@ jobs: echo "docker_image=$DOCKER_IMAGE" >> $GITHUB_OUTPUT echo "created=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT - build-docker-images: - name: build-docker-images - needs: [prep] + paths-filter: + name: Run paths-filter + runs-on: ubuntu-latest + + permissions: + pull-requests: read + + outputs: # Set outputs to true if not pull_request + ci-image-base: ${{ github.event_name == 'pull_request' && steps.filter.outputs.ci-image-base || 'true' }} + manylinux: ${{ github.event_name == 'pull_request' && steps.filter.outputs.manylinux || 'true' }} + ubuntu: ${{ github.event_name == 'pull_request' && steps.filter.outputs.ubuntu || 'true' }} + + steps: + - if: ${{ github.event_name == 'pull_request' }} + id: filter + uses: dorny/paths-filter@v3 + with: + filters: | + ci-image-base: + - '.github/workflows/docker.yml' + - 'utils/docker/docker-bake.ci-image-base.hcl' + - 'utils/docker/Dockerfile.ci-image-base' + manylinux: + - '.github/workflows/docker.yml' + - 'utils/docker/docker-bake.manylinux.hcl' + - 'utils/docker/Dockerfile.manylinux**' + - 'utils/ffmpeg/**' + - 'utils/opencvmini/**' + - 'utils/wasi-crypto/**' + - 'utils/wasi-nn/**' + ubuntu: + - '.github/workflows/docker.yml' + - 'utils/docker/docker-bake.ubuntu.hcl' + - 'utils/docker/Dockerfile.ubuntu-**' + - 'utils/ffmpeg/**' + - 'utils/opencvmini/**' + + bake-base-images: + needs: + - prep + - paths-filter + + name: CI image base runs-on: ubuntu-latest - container: - image: wasmedge/wasmedge:ci-image-base steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -71,140 +115,36 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - name: "Rebuild wasmedge/wasmedge:ci-image-base" - uses: docker/build-push-action@v5 - with: - context: ./utils/docker - file: utils/docker/Dockerfile.ci-image-base - platforms: linux/amd64 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ needs.prep.outputs.docker_image }}:ci-image-base - labels: | - org.opencontainers.image.title=${{ github.event.repository.name }} - org.opencontainers.image.description=${{ github.event.repository.description }} - org.opencontainers.image.url=${{ github.event.repository.html_url }} - org.opencontainers.image.source=${{ github.event.repository.clone_url }} - org.opencontainers.image.version=${{ needs.prep.outputs.version }} - org.opencontainers.image.created=${{ needs.prep.outputs.created }} - org.opencontainers.image.revision=${{ github.sha }} - - - name: "Rebuild wasmedge/wasmedge:ubuntu-base" - uses: docker/build-push-action@v5 - with: - context: ./utils/docker - file: utils/docker/Dockerfile.base - platforms: linux/amd64 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ needs.prep.outputs.docker_image }}:ubuntu-base - labels: | - org.opencontainers.image.title=${{ github.event.repository.name }} - org.opencontainers.image.description=${{ github.event.repository.description }} - org.opencontainers.image.url=${{ github.event.repository.html_url }} - org.opencontainers.image.source=${{ github.event.repository.clone_url }} - org.opencontainers.image.version=${{ needs.prep.outputs.version }} - org.opencontainers.image.created=${{ needs.prep.outputs.created }} - org.opencontainers.image.revision=${{ github.sha }} - - - name: "Rebuild wasmedge/wasmedge:ubuntu-build-clang" - uses: docker/build-push-action@v5 - with: - build-args: BASE=wasmedge/wasmedge:ubuntu-base - context: ./utils/docker - file: ./utils/docker/Dockerfile.build-clang - platforms: linux/amd64 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ needs.prep.outputs.docker_image }}:ubuntu-build-clang - labels: | - org.opencontainers.image.title=${{ github.event.repository.name }} - org.opencontainers.image.description=${{ github.event.repository.description }} - org.opencontainers.image.url=${{ github.event.repository.html_url }} - org.opencontainers.image.source=${{ github.event.repository.clone_url }} - org.opencontainers.image.version=${{ needs.prep.outputs.version }} - org.opencontainers.image.created=${{ needs.prep.outputs.created }} - org.opencontainers.image.revision=${{ github.sha }} - - - name: "Rebuild wasmedge/wasmedge:ubuntu-build-gcc" - uses: docker/build-push-action@v5 - with: - build-args: BASE=wasmedge/wasmedge:ubuntu-base - context: ./utils/docker - file: utils/docker/Dockerfile.build-gcc - platforms: linux/amd64 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ needs.prep.outputs.docker_image }}:ubuntu-build-gcc - labels: | - org.opencontainers.image.title=${{ github.event.repository.name }} - org.opencontainers.image.description=${{ github.event.repository.description }} - org.opencontainers.image.url=${{ github.event.repository.html_url }} - org.opencontainers.image.source=${{ github.event.repository.clone_url }} - org.opencontainers.image.version=${{ needs.prep.outputs.version }} - org.opencontainers.image.created=${{ needs.prep.outputs.created }} - org.opencontainers.image.revision=${{ github.sha }} - - - name: "Rebuild wasmedge/wasmedge:ubuntu-build-clang-plugins-deps" - uses: docker/build-push-action@v5 + # DO NOT skip the whole job to prevent descending jobs to be skipped + - if: ${{ needs.paths-filter.outputs.ci-image-base == 'true' }} + name: Bake and Push + uses: docker/bake-action@v5 with: - build-args: BASE=wasmedge/wasmedge:ubuntu-build-clang - context: ./utils/docker - file: ./utils/docker/Dockerfile.build-plugins-deps - platforms: linux/amd64 + files: utils/docker/docker-bake.ci-image-base.hcl push: ${{ github.event_name != 'pull_request' }} - tags: ${{ needs.prep.outputs.docker_image }}:ubuntu-build-clang-plugins-deps - labels: | - org.opencontainers.image.title=${{ github.event.repository.name }} - org.opencontainers.image.description=${{ github.event.repository.description }} - org.opencontainers.image.url=${{ github.event.repository.html_url }} - org.opencontainers.image.source=${{ github.event.repository.clone_url }} - org.opencontainers.image.version=${{ needs.prep.outputs.version }} - org.opencontainers.image.created=${{ needs.prep.outputs.created }} - org.opencontainers.image.revision=${{ github.sha }} - - - name: "Rebuild wasmedge/wasmedge:ubuntu-build-gcc-plugins-deps" - uses: docker/build-push-action@v5 - with: - build-args: BASE=wasmedge/wasmedge:ubuntu-build-gcc - context: ./utils/docker - file: ./utils/docker/Dockerfile.build-plugins-deps - platforms: linux/amd64 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ needs.prep.outputs.docker_image }}:ubuntu-build-gcc-plugins-deps - labels: | - org.opencontainers.image.title=${{ github.event.repository.name }} - org.opencontainers.image.description=${{ github.event.repository.description }} - org.opencontainers.image.url=${{ github.event.repository.html_url }} - org.opencontainers.image.source=${{ github.event.repository.clone_url }} - org.opencontainers.image.version=${{ needs.prep.outputs.version }} - org.opencontainers.image.created=${{ needs.prep.outputs.created }} - org.opencontainers.image.revision=${{ github.sha }} - - - name: "Rebuild wasmedge/wasmedge:latest" - uses: docker/build-push-action@v5 - with: - build-args: BASE=wasmedge/wasmedge:ubuntu-base - context: ./utils/docker - file: utils/docker/Dockerfile.build-clang - platforms: linux/amd64 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ needs.prep.outputs.docker_image }}:latest - labels: | - org.opencontainers.image.title=${{ github.event.repository.name }} - org.opencontainers.image.description=${{ github.event.repository.description }} - org.opencontainers.image.url=${{ github.event.repository.html_url }} - org.opencontainers.image.source=${{ github.event.repository.clone_url }} - org.opencontainers.image.version=${{ needs.prep.outputs.version }} - org.opencontainers.image.created=${{ needs.prep.outputs.created }} - org.opencontainers.image.revision=${{ github.sha }} - - build-manylinux2014_x86_64: - name: build-manylinux2014_x86_64 + + build-ubuntu-images: + needs: + - prep + - paths-filter + - bake-base-images + if: ${{ needs.paths-filter.outputs.ubuntu == 'true' }} + + strategy: + fail-fast: false + matrix: + targets: + - default + - base-2004-clang-aarch64 + + name: Ubuntu runs-on: ubuntu-latest - needs: [prep] container: image: wasmedge/wasmedge:ci-image-base steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -216,38 +156,73 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - name: "Rebuild wasmedge/wasmedge:manylinux2014_x86_64" - uses: docker/build-push-action@v5 + - name: Bake and Push + uses: docker/bake-action@v5 with: - build-args: BASE=quay.io/pypa/manylinux2014_x86_64 - context: ./utils/docker - file: utils/docker/Dockerfile.manylinux2014_x86_64 - platforms: linux/amd64 + files: utils/docker/docker-bake.ubuntu.hcl + targets: ${{ matrix.targets }} push: ${{ github.event_name != 'pull_request' }} - tags: ${{ needs.prep.outputs.docker_image }}:manylinux2014_x86_64 - labels: | - org.opencontainers.image.title=${{ github.event.repository.name }} - org.opencontainers.image.description=${{ github.event.repository.description }} - org.opencontainers.image.url=${{ github.event.repository.html_url }} - org.opencontainers.image.source=${{ github.event.repository.clone_url }} - org.opencontainers.image.version=${{ needs.prep.outputs.version }} - org.opencontainers.image.created=${{ needs.prep.outputs.created }} - org.opencontainers.image.revision=${{ github.sha }} - - - name: "Rebuild wasmedge/wasmedge:manylinux2014_x86_64-plugins-deps" - uses: docker/build-push-action@v5 + set: | + *.labels.org.opencontainers.image.title=${{ github.event.repository.name }} + *.labels.org.opencontainers.image.description=${{ github.event.repository.description }} + *.labels.org.opencontainers.image.url=${{ github.event.repository.html_url }} + *.labels.org.opencontainers.image.source=${{ github.event.repository.clone_url }} + *.labels.org.opencontainers.image.revision=${{ github.sha }} + *.labels.org.opencontainers.image.version=${{ needs.prep.outputs.version }} + *.labels.org.opencontainers.image.created=${{ needs.prep.outputs.created }} + + build-manylinux-images: + needs: + - prep + - paths-filter + - bake-base-images + if: ${{ needs.paths-filter.outputs.manylinux == 'true' }} + + strategy: + fail-fast: false + matrix: + include: + - name: manylinux_2_28 x86_64 + docker_tag: manylinux_2_28_x86_64 + targets: x86_64,x86_64-plugins + host_runner: ubuntu-latest + host_container: wasmedge/wasmedge:ci-image-base + - name: manylinux_2_28 aarch64 + docker_tag: manylinux_2_28_aarch64 + targets: aarch64,aarch64-plugins + host_runner: linux-arm64-v2 + host_container: wasmedge/wasmedge:ci-image-base_aarch64 + + name: ${{ matrix.name }} + runs-on: ${{ matrix.host_runner }} + container: + image: ${{ matrix.host_container }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_ACCESS_TOKEN }} + + - name: Bake and Push + uses: docker/bake-action@v5 with: - build-args: BASE=wasmedge/wasmedge:manylinux2014_x86_64 - context: ./utils/docker - file: utils/docker/Dockerfile.manylinux2014-build-plugins-deps - platforms: linux/amd64 + files: utils/docker/docker-bake.manylinux.hcl + targets: ${{ matrix.targets }} push: ${{ github.event_name != 'pull_request' }} - tags: ${{ needs.prep.outputs.docker_image }}:manylinux2014_x86_64-plugins-deps - labels: | - org.opencontainers.image.title=${{ github.event.repository.name }} - org.opencontainers.image.description=${{ github.event.repository.description }} - org.opencontainers.image.url=${{ github.event.repository.html_url }} - org.opencontainers.image.source=${{ github.event.repository.clone_url }} - org.opencontainers.image.version=${{ needs.prep.outputs.version }} - org.opencontainers.image.created=${{ needs.prep.outputs.created }} - org.opencontainers.image.revision=${{ github.sha }} + set: | + *.labels.org.opencontainers.image.title=${{ github.event.repository.name }} + *.labels.org.opencontainers.image.description=${{ github.event.repository.description }} + *.labels.org.opencontainers.image.url=${{ github.event.repository.html_url }} + *.labels.org.opencontainers.image.source=${{ github.event.repository.clone_url }} + *.labels.org.opencontainers.image.revision=${{ github.sha }} + *.labels.org.opencontainers.image.version=${{ needs.prep.outputs.version }} + *.labels.org.opencontainers.image.created=${{ needs.prep.outputs.created }} diff --git a/.github/workflows/ignore_words b/.github/workflows/ignore_words index 3e6db4519ce6..d637d3540913 100644 --- a/.github/workflows/ignore_words +++ b/.github/workflows/ignore_words @@ -17,3 +17,7 @@ unexpect cript wit createor +inout +anull +thirdparty +totalin diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index ba464c418003..e7a01df7f2cb 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -7,6 +7,8 @@ on: - reopened - closed +permissions: + contents: read jobs: labeler: permissions: diff --git a/.github/workflows/matrix-extensions.json b/.github/workflows/matrix-extensions.json new file mode 100644 index 000000000000..517b7803d5e5 --- /dev/null +++ b/.github/workflows/matrix-extensions.json @@ -0,0 +1,204 @@ +{ + "plugins": [ + { + "plugin": "wasi_crypto", + "bin": "libwasmedgePluginWasiCrypto.so", + "dir": "wasi_crypto", + "testBin": "wasiCryptoTests", + "options": "-DWASMEDGE_PLUGIN_WASI_CRYPTO=ON", + "platforms": [ + "manylinux2014_x86_64", + "manylinux2014_aarch64", + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + }, + { + "plugin": "wasi_nn-ggml", + "bin": "libwasmedgePluginWasiNN.so", + "dir": "wasi_nn", + "testBin": "wasiNNTests", + "options": "-DWASMEDGE_PLUGIN_WASI_NN_BACKEND=GGML", + "platforms": [ + "manylinux2014_x86_64", + "manylinux2014_aarch64", + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + }, + { + "plugin": "wasi_nn-pytorch", + "bin": "libwasmedgePluginWasiNN.so", + "dir": "wasi_nn", + "testBin": "wasiNNTests", + "options": "-DWASMEDGE_PLUGIN_WASI_NN_BACKEND=PyTorch", + "platforms": [ + "manylinux2014_x86_64", + "manylinux_2_28_x86_64" + ] + }, + { + "plugin": "wasi_nn-tensorflowlite", + "bin": "libwasmedgePluginWasiNN.so", + "dir": "wasi_nn", + "testBin": "wasiNNTests", + "options": "-DWASMEDGE_PLUGIN_WASI_NN_BACKEND=TensorFlowLite", + "platforms": [ + "manylinux2014_x86_64", + "manylinux2014_aarch64", + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + }, + { + "plugin": "wasi_nn-whisper", + "bin": "libwasmedgePluginWasiNN.so", + "dir": "wasi_nn", + "testBin": "wasiNNTests", + "options": "-DWASMEDGE_PLUGIN_WASI_NN_BACKEND=Whisper", + "platforms": [ + "manylinux2014_x86_64", + "manylinux2014_aarch64", + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + }, + { + "plugin": "wasi_nn-piper", + "bin": "libwasmedgePluginWasiNN.so", + "dir": "wasi_nn", + "testBin": "wasiNNTests", + "options": "-DWASMEDGE_PLUGIN_WASI_NN_BACKEND=Piper", + "platforms": [ + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + }, + { + "plugin": "wasm_bpf", + "bin": "libwasmedgePluginWasmBpf.so", + "dir": "wasm_bpf", + "testBin": "wasmBpfTests", + "options": "-DWASMEDGE_PLUGIN_WASM_BPF=ON -DWASMEDGE_PLUGIN_WASM_BPF_BUILD_LIBBPF_WITH_PKG_CONF=OFF", + "platforms": [ + "manylinux2014_x86_64", + "manylinux_2_28_x86_64" + ] + }, + { + "plugin": "wasmedge_ffmpeg", + "bin": "libwasmedgePluginWasmEdgeFFmpeg.so", + "dir": "wasmedge_ffmpeg", + "testBin": "wasmedgeFFmpegTests", + "options": "-DWASMEDGE_PLUGIN_FFMPEG=ON", + "platforms": [ + "manylinux2014_x86_64", + "manylinux2014_aarch64", + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + }, + { + "plugin": "wasmedge_image", + "bin": "libwasmedgePluginWasmEdgeImage.so", + "dir": "wasmedge_image", + "testBin": "wasmedgeImageTests", + "options": "-DWASMEDGE_PLUGIN_IMAGE=ON", + "platforms": [ + "manylinux2014_x86_64", + "manylinux2014_aarch64", + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + }, + { + "plugin": "wasmedge_llmc", + "bin": "libwasmedgePluginWasmEdgeLLMC.so", + "dir": "wasmedge_llmc", + "testBin": "wasmedgeLLMCTests", + "options": "-DWASMEDGE_PLUGIN_LLMC=ON", + "platforms": [ + "manylinux2014_x86_64", + "manylinux2014_aarch64", + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + }, + { + "plugin": "wasmedge_opencvmini", + "bin": "libwasmedgePluginWasmEdgeOpenCVMini.so", + "dir": "wasmedge_opencvmini", + "testBin": "wasmedgeOpencvminiTests", + "options": "-DWASMEDGE_PLUGIN_OPENCVMINI=ON", + "platforms": [ + "manylinux2014_x86_64", + "manylinux2014_aarch64", + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + }, + { + "plugin": "wasmedge_process", + "bin": "libwasmedgePluginWasmEdgeProcess.so", + "dir": "wasmedge_process", + "testBin": "wasmedgeProcessTests", + "options": "-DWASMEDGE_PLUGIN_PROCESS=ON", + "platforms": [ + "manylinux2014_x86_64", + "manylinux2014_aarch64", + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + }, + { + "plugin": "wasmedge_stablediffusion", + "bin": "libwasmedgePluginWasmEdgeStableDiffusion.so", + "dir": "wasmedge_stablediffusion", + "testBin": "wasmedgeStableDiffusionTests", + "options": "-DWASMEDGE_PLUGIN_STABLEDIFFUSION=ON", + "platforms": [ + "manylinux2014_x86_64", + "manylinux2014_aarch64", + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + }, + { + "plugin": "wasmedge_tensorflow", + "bin": "libwasmedgePluginWasmEdgeTensorflow.so", + "dir": "wasmedge_tensorflow", + "testBin": "wasmedgeTensorflowTests", + "options": "-DWASMEDGE_PLUGIN_TENSORFLOW=ON", + "platforms": [ + "manylinux2014_x86_64", + "manylinux2014_aarch64", + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + }, + { + "plugin": "wasmedge_tensorflowlite", + "bin": "libwasmedgePluginWasmEdgeTensorflowLite.so", + "dir": "wasmedge_tensorflowlite", + "testBin": "wasmedgeTensorflowLiteTests", + "options": "-DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON", + "platforms": [ + "manylinux2014_x86_64", + "manylinux2014_aarch64", + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + }, + { + "plugin": "wasmedge_zlib", + "bin": "libwasmedgePluginWasmEdgeZlib.so", + "dir": "wasmedge_zlib", + "testBin": "wasmedgeZlibTests", + "options": "-DWASMEDGE_PLUGIN_ZLIB=ON", + "platforms": [ + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64" + ] + } + ] +} diff --git a/.github/workflows/mdbook.yml b/.github/workflows/mdbook.yml deleted file mode 100644 index 990541d0ed8c..000000000000 --- a/.github/workflows/mdbook.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: MDBOOK - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} - cancel-in-progress: true - -on: - workflow_dispatch: - inputs: - logLevel: - description: 'Log level' - required: true - default: 'info' - push: - branches: [ master ] - paths: - - 'docs/**' - pull_request: - branches: [ master ] - paths: - - 'docs/**' - -jobs: - lint-markdown: - if: ${{ github.event_name != 'push' }} - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Ensure git safe directory - run: | - git config --global --add safe.directory $(pwd) - - - name: Lint markdown format - uses: github/super-linter/slim@v5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DEFAULT_BRANCH: master - FILTER_REGEX_INCLUDE: .*docs/.*md$ - VALIDATE_ALL_CODEBASE: false - VALIDATE_MARKDOWN: true - - build-mdbook: - needs: lint-markdown - if: | - always() - && (needs.lint-markdown.result == 'success' || needs.lint-markdown.result == 'skipped') - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Ensure git safe directory - run: | - git config --global --add safe.directory $(pwd) - - - name: Setup mdBook - uses: peaceiris/actions-mdbook@v1 - with: - mdbook-version: 'latest' - - - name: Install mdBook preprocessors - run: | - cargo install mdbook-variables --locked - - - name: Create work dir - run: | - cd docs/book/ - mkdir target - - - name: Build English version - run: | - cd docs/book/en - mdbook build - cp -r book ../target/en - - - name: Publish EN version - if: ${{ github.event_name == 'push' }} - uses: cpina/github-action-push-to-another-repository@main - env: - API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB_WWW }} - with: - source-directory: 'docs/book/target' - destination-github-username: 'WasmEdge' - destination-repository-name: 'www' - target-directory: 'book' - user-email: michael@secondstate.io - target-branch: main diff --git a/.github/workflows/misc-linters.yml b/.github/workflows/misc-linters.yml index ff8dcf6e4623..8c07c3276b8a 100644 --- a/.github/workflows/misc-linters.yml +++ b/.github/workflows/misc-linters.yml @@ -6,6 +6,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: misc: permissions: @@ -14,7 +17,7 @@ jobs: name: misc linters runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Ensure git safe directory run: | git config --global --add safe.directory $(pwd) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9a4a24313159..b02ab938682a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: upload_url: ${{ steps.create_release.outputs.upload_url }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Ensure git safe directory run: | git config --global --add safe.directory $(pwd) @@ -54,7 +54,7 @@ jobs: version: ${{ needs.create_release.outputs.version }} matrix: "[{'name':'MacOS 12 (x86_64)','runner':'macos-12','darwin_version':21,'arch':'x86_64'}, - {'name':'MacOS 13 (arm64)','runner':'macos-14','darwin_version':22,'arch':'arm64'}]" + {'name':'MacOS 14 (arm64)','runner':'macos-14','darwin_version':23,'arch':'arm64'}]" release: true secrets: inherit @@ -63,7 +63,8 @@ jobs: uses: ./.github/workflows/reusable-build-on-ubuntu.yml with: version: ${{ needs.create_release.outputs.version }} - matrix: "[{'name':'ubuntu-20.04','compiler':'clang++','build_type':'Release','docker_tag':'ubuntu-20.04-build-clang'}]" + matrix: "[{'name':'ubuntu-20.04','arch':'x86_64','runner':'ubuntu-latest','compiler':'clang++','build_type':'Release','docker_tag':'ubuntu-20.04-build-clang'}, + {'name':'ubuntu-20.04','arch':'aarch64','runner':'linux-arm64-v2','compiler':'clang++','build_type':'Release','docker_tag':'ubuntu-20.04-build-clang-aarch64'}]" release: true secrets: inherit @@ -73,8 +74,19 @@ jobs: with: version: ${{ needs.create_release.outputs.version }} matrix: - "[{'name':'manylinux 2014 x86_64','runner':'ubuntu-latest','docker_tag':'manylinux2014_x86_64'}, - {'name':'manylinux 2014 aarch64','runner':'linux-arm64','docker_tag':'manylinux2014_aarch64'}]" + "[{'name':'manylinux2014 x86_64','runner':'ubuntu-latest','docker_tag':'manylinux2014_x86_64-plugins-deps','asset_tag':'manylinux2014_x86_64'}, + {'name':'manylinux2014 aarch64','runner':'linux-arm64-v2','docker_tag':'manylinux2014_aarch64-plugins-deps','asset_tag':'manylinux2014_aarch64'}]" + release: true + secrets: inherit + + build_on_manylinux_2_28: + needs: create_release + uses: ./.github/workflows/reusable-build-on-manylinux.yml + with: + version: ${{ needs.create_release.outputs.version }} + matrix: + "[{'name':'manylinux_2_28 x86_64','runner':'ubuntu-latest','docker_tag':'manylinux_2_28_x86_64','asset_tag':'manylinux_2_28_x86_64'}, + {'name':'manylinux_2_28 aarch64','runner':'linux-arm64-v2','docker_tag':'manylinux_2_28_aarch64','asset_tag':'manylinux_2_28_aarch64'}]" release: true secrets: inherit @@ -123,11 +135,11 @@ jobs: runs-on: ubuntu-latest env: output_dir: build/plugins/wasi_nn - build_options: -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=PyTorch -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=OpenVINO -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=TensorFlowLite -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=GGML - tar_names: wasi_nn-pytorch wasi_nn-openvino wasi_nn-tensorflowlite wasi_nn-ggml + build_options: -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=PyTorch -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=OpenVINO -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=TensorFlowLite -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=GGML -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=Whisper -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=Piper + tar_names: wasi_nn-pytorch wasi_nn-openvino wasi_nn-tensorflowlite wasi_nn-ggml wasi_nn-whisper wasi_nn-piper output_bin: libwasmedgePluginWasiNN.so - OPENVINO_VERSION: "2023.0.2" - OPENVINO_YEAR: "2023" + OPENVINO_VERSION: "2024.2.0" + OPENVINO_YEAR: "2024" PYTORCH_VERSION: "1.8.2" PYTORCH_INSTALL_TO: "." needs: create_release @@ -135,7 +147,7 @@ jobs: image: wasmedge/wasmedge:ubuntu-20.04-build-clang steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Grant the safe directory for git @@ -145,9 +157,10 @@ jobs: shell: bash run: | apt update - apt install -y unzip libopenblas-dev pkg-config protobuf-compiler-grpc libgrpc-dev libgrpc++-dev + apt install -y unzip libopenblas-dev pkg-config python3-dev bash utils/wasi-nn/install-openvino.sh bash utils/wasi-nn/install-pytorch.sh + bash utils/wasi-nn/install-onnxruntime.sh - name: Build WASI-NN plugin shell: bash run: | @@ -157,7 +170,7 @@ jobs: option_array=(${build_options}) outtarget=${output_bin%.*} outtarget=${outtarget#lib} - cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DWASMEDGE_BUILD_TOOLS=OFF + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_TOOLS=OFF for (( i=0; i<${#plugin_array[@]}; i++ )); do echo "Building ${plugin_array[$i]} backend:" @@ -200,21 +213,96 @@ jobs: run: | mv plugin_wasi_nn-ggml.tar.gz WasmEdge-plugin-wasi_nn-ggml-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasi_nn-ggml-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz --clobber + - name: Upload wasi_nn-whisper plugin tar.gz package + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mv plugin_wasi_nn-whisper.tar.gz WasmEdge-plugin-wasi_nn-whisper-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz + gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasi_nn-whisper-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz --clobber + - name: Upload wasi_nn-piper plugin tar.gz package + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mv plugin_wasi_nn-piper.tar.gz WasmEdge-plugin-wasi_nn-piper-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz + gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasi_nn-piper-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz --clobber + + build_and_upload_wasinn_burnrs_ubuntu: + name: Build and upload WASI-NN burn.rs backend on Ubuntu 20.04 + runs-on: ubuntu-latest + env: + output_dir: build/plugins/wasi_nn_burnrs + build_options: -DWASMEDGE_PLUGIN_WASI_NN_BURNRS_MODEL=squeezenet -DWASMEDGE_PLUGIN_WASI_NN_BURNRS_MODEL=whisper + tar_names: wasi_nn_burnrs-squeezenet wasi_nn_burnrs-whisper + output_bin: libwasmedgePluginWasiNN.so + needs: create_release + container: + image: wasmedge/wasmedge:ubuntu-20.04-build-clang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Grant the safe directory for git + run: | + git config --global --add safe.directory $(pwd) + - uses: dtolnay/rust-toolchain@stable + - name: Install dependencies + shell: bash + run: | + apt update + apt install -y pkg-config libssl-dev + - name: Build WASI-NN plugin + shell: bash + run: | + plugin_array=(${tar_names}) + option_array=(${build_options}) + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_TOOLS=OFF + for (( i=0; i<${#plugin_array[@]}; i++ )); + do + echo "Building ${plugin_array[$i]} backend:" + cmake -Bbuild -GNinja ${option_array[$i]} + cmake --build build --target wasmedgePluginWasiNNBurnRS + + echo "Copying ${plugin_array[$i]} backend:" + cp -f ${output_dir}/${output_bin} ${output_bin} + tar -zcvf plugin_${plugin_array[$i]}.tar.gz ${output_bin} + done + - name: Install gh + run: | + type -p curl >/dev/null || (apt update && apt install curl -y) + curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \ + && chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ + && apt update \ + && apt install gh -y + - name: Upload wasi_nn_burnrs-squeezenet plugin tar.gz package + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mv plugin_wasi_nn_burnrs-squeezenet.tar.gz WasmEdge-plugin-wasi_nn_burnrs-squeezenet-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz + gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasi_nn_burnrs-squeezenet-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz --clobber + - name: Upload wasi_nn_burnrs-whisper plugin tar.gz package + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mv plugin_wasi_nn_burnrs-whisper.tar.gz WasmEdge-plugin-wasi_nn_burnrs-whisper-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz + gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasi_nn_burnrs-whisper-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz --clobber build_and_upload_plugin_ubuntu: name: Build and upload plugins on Ubuntu 20.04 runs-on: ubuntu-latest env: output_prefix: build/plugins - build_options: -DWASMEDGE_PLUGIN_WASI_CRYPTO=ON -DWASMEDGE_PLUGIN_WASI_LOGGING=ON -DWASMEDGE_PLUGIN_PROCESS=ON -DWASMEDGE_PLUGIN_TENSORFLOW=ON -DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON -DWASMEDGE_PLUGIN_IMAGE=ON -DWASMEDGE_PLUGIN_WASM_BPF=ON -DWASMEDGE_PLUGIN_OPENCVMINI=ON -DWASMEDGE_PLUGIN_ZLIB=ON - tar_names: wasi_crypto wasi_logging wasmedge_process wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasm_bpf wasmedge_opencvmini wasmedge_zlib - output_bins: libwasmedgePluginWasiCrypto.so libwasmedgePluginWasiLogging.so libwasmedgePluginWasmEdgeProcess.so libwasmedgePluginWasmEdgeTensorflow.so libwasmedgePluginWasmEdgeTensorflowLite.so libwasmedgePluginWasmEdgeImage.so libwasmedgePluginWasmBpf.so libwasmedgePluginWasmEdgeOpenCVMini.so libwasmedgePluginWasmEdgeZlib.so + build_options: -DWASMEDGE_PLUGIN_WASI_CRYPTO=ON -DWASMEDGE_PLUGIN_PROCESS=ON -DWASMEDGE_PLUGIN_TENSORFLOW=ON -DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON -DWASMEDGE_PLUGIN_IMAGE=ON -DWASMEDGE_PLUGIN_WASM_BPF=ON -DWASMEDGE_PLUGIN_OPENCVMINI=ON -DWASMEDGE_PLUGIN_ZLIB=ON -DWASMEDGE_PLUGIN_FFMPEG=ON -DWASMEDGE_PLUGIN_STABLEDIFFUSION=ON + tar_names: wasi_crypto wasmedge_process wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasm_bpf wasmedge_opencvmini wasmedge_zlib wasmedge_ffmpeg wasmedge_stablediffusion + output_bins: libwasmedgePluginWasiCrypto.so libwasmedgePluginWasmEdgeProcess.so libwasmedgePluginWasmEdgeTensorflow.so libwasmedgePluginWasmEdgeTensorflowLite.so libwasmedgePluginWasmEdgeImage.so libwasmedgePluginWasmBpf.so libwasmedgePluginWasmEdgeOpenCVMini.so libwasmedgePluginWasmEdgeZlib.so libwasmedgePluginWasmEdgeFFmpeg.so libwasmedgePluginWasmEdgeStableDiffusion.so + OPENCV_VERSION: "4.8.0" needs: create_release container: - image: wasmedge/wasmedge:ubuntu-build-clang-plugins-deps + image: wasmedge/wasmedge:ubuntu-20.04-build-clang steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Grant the safe directory for git @@ -226,11 +314,15 @@ jobs: apt install -y libssl-dev cmake g++ wget unzip apt install -y libelf-dev zlib1g-dev pkg-config apt install -y cargo + apt install -y yasm + bash utils/ffmpeg/install-ffmpeg-v6.0.sh + bash utils/opencvmini/install-opencvmini.sh - name: Build plugins shell: bash run: | outbin_array=(${output_bins}) - cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DWASMEDGE_BUILD_TOOLS=OFF ${build_options} + export PKG_CONFIG_PATH=$(pwd)/FFmpeg-n6.0/output/lib/pkgconfig + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_TOOLS=OFF ${build_options} for (( i=0; i<${#outbin_array[@]}; i++ )); do echo "Building ${outbin_array[$i]} :" @@ -242,6 +334,7 @@ jobs: - name: Prepare the plugins tar.gz package shell: bash run: | + export LD_LIBRARY_PATH=$(pwd)/FFmpeg-n6.0/output/lib:$LD_LIBRARY_PATH plugin_array=(${tar_names}) outbin_array=(${output_bins}) for (( i=0; i<${#plugin_array[@]}; i++ )); @@ -264,12 +357,6 @@ jobs: run: | mv plugin_wasi_crypto.tar.gz WasmEdge-plugin-wasi_crypto-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasi_crypto-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz --clobber - - name: Upload wasi_logging plugin tar.gz package - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - mv plugin_wasi_logging.tar.gz WasmEdge-plugin-wasi_logging-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz - gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasi_logging-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz --clobber - name: Upload wasmedge_process plugin tar.gz package env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -312,63 +399,66 @@ jobs: run: | mv plugin_wasmedge_zlib.tar.gz WasmEdge-plugin-wasmedge_zlib-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_zlib-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz --clobber + - name: Upload wasmedge_ffmpeg plugin tar.gz package + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mv plugin_wasmedge_ffmpeg.tar.gz WasmEdge-plugin-wasmedge_ffmpeg-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz + gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_ffmpeg-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz --clobber + - name: Upload wasmedge_stablediffusion plugin tar.gz package + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mv plugin_wasmedge_stablediffusion.tar.gz WasmEdge-plugin-wasmedge_stablediffusion-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz + gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_stablediffusion-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz --clobber - build_and_upload_wasinn_manylinux: - name: Build and upload WASI-NN on manylinux - needs: create_release - uses: ./.github/workflows/reusable-build-extensions.yml - with: - version: ${{ needs.create_release.outputs.version }} - release: true - secrets: inherit - - build_and_upload_plugin_manylinux: + build_and_upload_plugin_ubuntu_cuda: strategy: matrix: include: - - name: Plugins_x86_64 - host_runner: ubuntu-latest - docker_tag: manylinux2014_x86_64-plugins-deps - - name: Plugins_aarch64 - host_runner: linux-arm64 - docker_tag: manylinux2014_aarch64-plugins-deps - name: Build and upload plugins on ${{ matrix.docker_tag }} - runs-on: ${{ matrix.host_runner }} + - cuda_version: '11.3' + - cuda_version: '12.0' + name: Build and upload plugins on Ubuntu 20.04 with CUDA ${{ matrix.cuda_version }} + runs-on: ubuntu-latest + container: wasmedge/wasmedge:ubuntu-20.04-build-gcc + needs: create_release env: + CUDA_VER: ${{ matrix.cuda_version }} + CUDAARCHS: "60;61;70" output_prefix: build/plugins - build_options_all_platforms: -DWASMEDGE_PLUGIN_WASI_CRYPTO=ON -DWASMEDGE_PLUGIN_WASI_LOGGING=ON -DWASMEDGE_PLUGIN_PROCESS=ON -DWASMEDGE_PLUGIN_TENSORFLOW=ON -DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON -DWASMEDGE_PLUGIN_IMAGE=ON -DWASMEDGE_PLUGIN_OPENCVMINI=ON -DWASMEDGE_PLUGIN_ZLIB=ON - build_options_manylinux2014_x86_64: -DWASMEDGE_PLUGIN_WASM_BPF=ON -DWASMEDGE_PLUGIN_WASM_BPF_BUILD_LIBBPF_WITH_PKG_CONF=OFF - build_options_manylinux2014_aarch64: - tar_names_all_platforms: wasi_crypto wasi_logging wasmedge_process wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasmedge_opencvmini wasmedge_zlib - tar_names_manylinux2014_x86_64: wasm_bpf - tar_names_manylinux2014_aarch64: - output_bins_all_platforms: libwasmedgePluginWasiCrypto.so libwasmedgePluginWasiLogging.so libwasmedgePluginWasmEdgeProcess.so libwasmedgePluginWasmEdgeTensorflow.so libwasmedgePluginWasmEdgeTensorflowLite.so libwasmedgePluginWasmEdgeImage.so libwasmedgePluginWasmEdgeOpenCVMini.so libwasmedgePluginWasmEdgeZlib.so - output_bins_manylinux2014_x86_64: libwasmedgePluginWasmBpf.so - output_bins_manylinux2014_aarch64: - needs: create_release - container: - image: wasmedge/wasmedge:${{ matrix.docker_tag }} + build_options: -DWASMEDGE_PLUGIN_STABLEDIFFUSION=ON -DWASMEDGE_PLUGIN_STABLEDIFFUSION_CUBLAS=ON + tar_names: wasmedge_stablediffusion + output_bins: libwasmedgePluginWasmEdgeStableDiffusion.so steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Grant the safe directory for git run: | git config --global --add safe.directory $(pwd) - - name: Build and install dependencies + - name: Install dependencies + shell: bash run: | - yum update -y - yum install -y zlib-devel zlib-static cmake curl wget unzip - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y - source "$HOME/.cargo/env" - bash ./utils/wasi-crypto/build-openssl.sh - - name: Build plugins + CUDA_KEYRING=cuda-keyring_1.1-1_all.deb + NVCC_VER=${CUDA_VER//./-} + wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/${CUDA_KEYRING} + dpkg -i ${CUDA_KEYRING} + rm -f ${CUDA_KEYRING} + wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null + apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" + apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 6AF7F09730B3F0A4 + export DEBIAN_FRONTEND=noninteractive + apt-get update + apt-get remove -y --purge --auto-remove cmake + apt-get upgrade -y + apt-get install -y cmake cuda-nvcc-${NVCC_VER} libcublas-dev-${NVCC_VER} lsb-release pkg-config software-properties-common unzip + - name: Build plugins with CUDA shell: bash run: | - source "$HOME/.cargo/env" - outbin_array=(${output_bins_all_platforms} ${output_bins_${{ matrix.docker_tag }}}) - cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DWASMEDGE_BUILD_TOOLS=OFF -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DWASMEDGE_BUILD_TOOLS=OFF ${build_options_all_platforms} ${build_options_${{ matrix.docker_tag }}} -DOPENSSL_ROOT_DIR=$(pwd)/openssl-1.1.1n/openssl + export CXXFLAGS="-Wno-error" + outbin_array=(${output_bins}) + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_TESTS=OFF -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DWASMEDGE_BUILD_TOOLS=OFF -DCMAKE_CUDA_ARCHITECTURES="${CUDAARCHS}" -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc -DWASMEDGE_USE_LLVM=OFF ${build_options} for (( i=0; i<${#outbin_array[@]}; i++ )); do echo "Building ${outbin_array[$i]} :" @@ -380,100 +470,123 @@ jobs: - name: Prepare the plugins tar.gz package shell: bash run: | - plugin_array=(${tar_names_all_platforms} ${tar_names_${{ matrix.docker_tag }}}) - outbin_array=(${output_bins_all_platforms} ${output_bins_${{ matrix.docker_tag }}}) + plugin_array=(${tar_names}) + outbin_array=(${output_bins}) for (( i=0; i<${#plugin_array[@]}; i++ )); do echo "Copying ${plugin_array[$i]} :" cp ${output_prefix}/${plugin_array[$i]}/${outbin_array[$i]} ${outbin_array[$i]} tar -zcvf plugin_${plugin_array[$i]}.tar.gz ${outbin_array[$i]} done - - name: Install gh on manylinux - run: | - type -p yum-config-manager >/dev/null || sudo yum install yum-utils - yum-config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo - yum install -y gh - - name: Upload wasi_crypto plugin tar.gz package - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - mv plugin_wasi_crypto.tar.gz WasmEdge-plugin-wasi_crypto-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasi_crypto-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz --clobber - - name: Upload wasi_logging plugin tar.gz package - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - mv plugin_wasi_logging.tar.gz WasmEdge-plugin-wasi_logging-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasi_logging-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz --clobber - - name: Upload wasmedge_process plugin tar.gz package - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Install gh run: | - mv plugin_wasmedge_process.tar.gz WasmEdge-plugin-wasmedge_process-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_process-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz --clobber - - name: Upload wasmedge_tensorflow plugin tar.gz package + type -p curl >/dev/null || (apt update && apt install curl -y) + curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \ + && chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ + && apt update \ + && apt install gh -y + - name: Upload wasmedge_stablediffusion CUDA ${{ matrix.cuda_version }} plugin tar.gz package env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - mv plugin_wasmedge_tensorflow.tar.gz WasmEdge-plugin-wasmedge_tensorflow-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_tensorflow-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz --clobber - - name: Upload wasmedge_tensorflowlite plugin tar.gz package - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + mv plugin_wasmedge_stablediffusion.tar.gz WasmEdge-plugin-wasmedge_stablediffusion-cuda-${{ matrix.cuda_version }}-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz + gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_stablediffusion-cuda-${{ matrix.cuda_version }}-${{ needs.create_release.outputs.version }}-ubuntu20.04_x86_64.tar.gz --clobber + + build_and_upload_plugins_manylinux: + name: Build and upload plugins on manylinux + needs: create_release + uses: ./.github/workflows/reusable-build-extensions.yml + with: + version: ${{ needs.create_release.outputs.version }} + release: true + secrets: inherit + + build_and_upload_wasinn_macos: + strategy: + matrix: + include: + - system: MacOS 12 (x86_64) + host_runner: macos-12 + arch: x86_64 + - system: MacOS 14 (arm64) + host_runner: macos-14 + arch: arm64 + name: Build and upload WASI-NN on ${{ matrix.system }} + runs-on: ${{ matrix.host_runner }} + env: + output_dir: build/plugins/wasi_nn + build_options: -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=TensorFlowLite -DWASMEDGE_PLUGIN_WASI_NN_BACKEND=Whisper + tar_names: wasi_nn-tensorflowlite wasi_nn-whisper + output_bin: libwasmedgePluginWasiNN.dylib + needs: create_release + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Grant the safe directory for git run: | - mv plugin_wasmedge_tensorflowlite.tar.gz WasmEdge-plugin-wasmedge_tensorflowlite-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_tensorflowlite-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz --clobber - - name: Upload wasmedge_image plugin tar.gz package - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + git config --global --add safe.directory $(pwd) + - name: Install dependencies run: | - mv plugin_wasmedge_image.tar.gz WasmEdge-plugin-wasmedge_image-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_image-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz --clobber - - name: Upload wasm_bpf plugin tar.gz package - if: contains(matrix.docker_tag, 'manylinux2014_x86_64') - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + eval $(/opt/homebrew/bin/brew shellenv) + brew install llvm@16 ninja cmake gh + - name: Build WASI-NN plugin + shell: bash run: | - mv plugin_wasm_bpf.tar.gz WasmEdge-plugin-wasm_bpf-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasm_bpf-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz --clobber - - name: Upload wasmedge_opencvmini plugin tar.gz package + eval $(/opt/homebrew/bin/brew shellenv) + plugin_array=(${tar_names}) + option_array=(${build_options}) + outtarget=${output_bin%.*} + outtarget=${outtarget#lib} + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_TOOLS=OFF + for (( i=0; i<${#plugin_array[@]}; i++ )); + do + echo "Building ${plugin_array[$i]} backend:" + cmake -Bbuild -GNinja ${option_array[$i]} + cmake --build build --target ${outtarget} + + echo "Copying ${plugin_array[$i]} backend:" + cp -f ${output_dir}/${output_bin} ${output_bin} + tar -zcvf plugin_${plugin_array[$i]}.tar.gz ${output_bin} + done + - name: Upload wasi_nn-tensorflowlite plugin tar.gz package env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - mv plugin_wasmedge_opencvmini.tar.gz WasmEdge-plugin-wasmedge_opencvmini-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_opencvmini-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz --clobber - - name: Upload wasmedge_zlib plugin tar.gz package + eval $(/opt/homebrew/bin/brew shellenv) + mv plugin_wasi_nn-tensorflowlite.tar.gz WasmEdge-plugin-wasi_nn-tensorflowlite-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz + gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasi_nn-tensorflowlite-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz --clobber + - name: Upload wasi_nn-whisper plugin tar.gz package env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - mv plugin_wasmedge_zlib.tar.gz WasmEdge-plugin-wasmedge_zlib-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz - gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_zlib-${{ needs.create_release.outputs.version }}-${{ matrix.docker_tag }}.tar.gz --clobber + eval $(/opt/homebrew/bin/brew shellenv) + mv plugin_wasi_nn-whisper.tar.gz WasmEdge-plugin-wasi_nn-whisper-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz + gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasi_nn-whisper-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz --clobber build_and_upload_plugin_macos: strategy: matrix: include: - - name: Plugins_MacOS_12 - system: MacOS 12 + - system: MacOS 12 (x86_64) host_runner: macos-12 - darwin_version: darwin_21 arch: x86_64 - - name: Plugins_MacOS_arm64 - system: MacOS 13 (arm64) + - system: MacOS 14 (arm64) host_runner: macos-14 - darwin_version: darwin_22 arch: arm64 name: Build and upload plugins on ${{ matrix.system }} runs-on: ${{ matrix.host_runner }} env: output_prefix: build/plugins - build_options: -DWASMEDGE_PLUGIN_WASI_CRYPTO=ON -DWASMEDGE_PLUGIN_WASI_LOGGING=ON -DWASMEDGE_PLUGIN_TENSORFLOW=ON -DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON -DWASMEDGE_PLUGIN_IMAGE=ON -DWASMEDGE_PLUGIN_OPENCVMINI=ON -DWASMEDGE_PLUGIN_ZLIB=ON - tar_names: wasi_crypto wasi_logging wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasmedge_opencvmini wasmedge_zlib - output_bins: libwasmedgePluginWasiCrypto.dylib libwasmedgePluginWasiLogging.dylib libwasmedgePluginWasmEdgeTensorflow.dylib libwasmedgePluginWasmEdgeTensorflowLite.dylib libwasmedgePluginWasmEdgeImage.dylib libwasmedgePluginWasmEdgeOpenCVMini.dylib libwasmedgePluginWasmEdgeZlib.dylib + build_options: -DWASMEDGE_PLUGIN_WASI_CRYPTO=ON -DWASMEDGE_PLUGIN_TENSORFLOW=ON -DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON -DWASMEDGE_PLUGIN_IMAGE=ON -DWASMEDGE_PLUGIN_OPENCVMINI=ON -DWASMEDGE_PLUGIN_ZLIB=ON -DWASMEDGE_PLUGIN_FFMPEG=ON -DWASMEDGE_PLUGIN_STABLEDIFFUSION=ON + tar_names: wasi_crypto wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasmedge_opencvmini wasmedge_zlib wasmedge_ffmpeg wasmedge_stablediffusion + output_bins: libwasmedgePluginWasiCrypto.dylib libwasmedgePluginWasmEdgeTensorflow.dylib libwasmedgePluginWasmEdgeTensorflowLite.dylib libwasmedgePluginWasmEdgeImage.dylib libwasmedgePluginWasmEdgeOpenCVMini.dylib libwasmedgePluginWasmEdgeZlib.dylib libwasmedgePluginWasmEdgeFFmpeg.dylib libwasmedgePluginWasmEdgeStableDiffusion.dylib needs: create_release steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Grant the safe directory for git @@ -482,16 +595,17 @@ jobs: - name: Install dependencies run: | eval $(/opt/homebrew/bin/brew shellenv) - brew install llvm@16 ninja cmake openssl wabt opencv rust gh + brew install llvm@16 ninja cmake openssl opencv rust gh ffmpeg@6 - name: Build plugins shell: bash run: | eval $(/opt/homebrew/bin/brew shellenv) outbin_array=(${output_bins}) export LLVM_DIR="$(brew --prefix)/opt/llvm@16/lib/cmake" + export PKG_CONFIG_PATH="$(brew --prefix)/opt/ffmpeg@6/lib/pkgconfig:$PKG_CONFIG_PATH" export CC=clang export CXX=clang++ - cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DWASMEDGE_BUILD_TOOLS=OFF -DOPENSSL_ROOT_DIR=$(brew --prefix)/opt/openssl ${build_options} + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_TOOLS=OFF -DOPENSSL_ROOT_DIR=$(brew --prefix)/opt/openssl ${build_options} for (( i=0; i<${#outbin_array[@]}; i++ )); do echo "Building ${outbin_array[$i]} :" @@ -518,13 +632,6 @@ jobs: eval $(/opt/homebrew/bin/brew shellenv) mv plugin_wasi_crypto.tar.gz WasmEdge-plugin-wasi_crypto-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasi_crypto-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz --clobber - - name: Upload wasi_logging plugin tar.gz package - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - eval $(/opt/homebrew/bin/brew shellenv) - mv plugin_wasi_logging.tar.gz WasmEdge-plugin-wasi_logging-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz - gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasi_logging-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz --clobber - name: Upload wasmedge_tensorflow plugin tar.gz package env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -560,13 +667,92 @@ jobs: eval $(/opt/homebrew/bin/brew shellenv) mv plugin_wasmedge_zlib.tar.gz WasmEdge-plugin-wasmedge_zlib-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_zlib-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz --clobber + - name: Upload wasmedge_ffmpeg plugin tar.gz package + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mv plugin_wasmedge_ffmpeg.tar.gz WasmEdge-plugin-wasmedge_ffmpeg-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz + gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_ffmpeg-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz --clobber + - name: Upload wasmedge_stablediffusion plugin tar.gz package + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mv plugin_wasmedge_stablediffusion.tar.gz WasmEdge-plugin-wasmedge_stablediffusion-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz + gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_stablediffusion-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz --clobber + + build_and_upload_plugin_macos_metal: + strategy: + matrix: + include: + - system: MacOS 14 (arm64) + host_runner: macos-14 + arch: arm64 + name: Build and upload plugins on ${{ matrix.system }} with Metal + runs-on: ${{ matrix.host_runner }} + env: + output_prefix: build/plugins + build_options: -DWASMEDGE_PLUGIN_STABLEDIFFUSION=ON -DWASMEDGE_PLUGIN_STABLEDIFFUSION_METAL=ON + tar_names: wasmedge_stablediffusion + output_bins: libwasmedgePluginWasmEdgeStableDiffusion.dylib + needs: create_release + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Grant the safe directory for git + run: | + git config --global --add safe.directory $(pwd) + - name: Install dependencies + run: | + eval $(/opt/homebrew/bin/brew shellenv) + brew install llvm@16 ninja cmake gh + - name: Build plugins + shell: bash + run: | + eval $(/opt/homebrew/bin/brew shellenv) + outbin_array=(${output_bins}) + export LLVM_DIR="$(brew --prefix)/opt/llvm@16/lib/cmake" + export CC=clang + export CXX=clang++ + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_TOOLS=OFF -DOPENSSL_ROOT_DIR=$(brew --prefix)/opt/openssl ${build_options} + for (( i=0; i<${#outbin_array[@]}; i++ )); + do + echo "Building ${outbin_array[$i]} :" + outtarget=${outbin_array[$i]} + outtarget=${outtarget%.*} + outtarget=${outtarget#lib} + cmake --build build --target ${outtarget} + done + - name: Prepare the WasmEdge plugins tar.gz package (with metal files) + shell: bash + run: | + plugin_array=(${tar_names}) + outbin_array=(${output_bins}) + for (( i=0; i<${#plugin_array[@]}; i++ )); + do + echo "Copying ${plugin_array[$i]} :" + for plugin_files in "${outbin_array[$i]}" "ggml-metal.metal" "ggml-common.h" + do + cp ${output_prefix}/${plugin_array[$i]}/$plugin_files . + done + tar -zcvf plugin_${plugin_array[$i]}.tar.gz "${outbin_array[$i]}" "ggml-metal.metal" "ggml-common.h" + done + - name: Upload wasmedge_stablediffusion plugin tar.gz package + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mv plugin_wasmedge_stablediffusion.tar.gz WasmEdge-plugin-wasmedge_stablediffusion-metal-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz + gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-plugin-wasmedge_stablediffusion-metal-${{ needs.create_release.outputs.version }}-darwin_${{ matrix.arch }}.tar.gz --clobber build_manylinux2014_runtime_only: name: Build runtime only on manylinux2014 platform needs: create_release runs-on: ubuntu-latest container: - image: wasmedge/wasmedge:manylinux2014_x86_64 + image: wasmedge/wasmedge:manylinux2014_x86_64-plugins-deps + env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true steps: - name: Checkout code uses: actions/checkout@v3 @@ -575,17 +761,12 @@ jobs: git config --global --add safe.directory $(pwd) - name: Build runtime only manylinux2014 package run: | - bash utils/docker/build-manylinux.sh -DWASMEDGE_BUILD_AOT_RUNTIME=OFF + bash utils/docker/build-manylinux.sh -DWASMEDGE_USE_LLVM=OFF - name: Upload ${{ matrix.name }} tar.gz package to artifact uses: actions/upload-artifact@v3 with: name: build_manylinux2014_runtime_only path: build/WasmEdge-${{ needs.create_release.outputs.version }}-Linux.tar.gz - - name: Install gh on manylinux - run: | - type -p yum-config-manager >/dev/null || sudo yum install yum-utils - yum-config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo - yum install -y gh - name: Upload ${{ matrix.name }} tar.gz package env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -593,79 +774,13 @@ jobs: mv build/WasmEdge-${{ needs.create_release.outputs.version }}-Linux.tar.xz WasmEdge-runtime-only-${{ needs.create_release.outputs.version }}-manylinux2014_x86_64.tar.xz gh release upload ${{ needs.create_release.outputs.version }} WasmEdge-runtime-only-${{ needs.create_release.outputs.version }}-manylinux2014_x86_64.tar.xz --clobber - build_docker_slim_images: - strategy: - matrix: - include: - - name: wasmedge/slim:${{ needs.create_release.outputs.version }} - artifact_name: WasmEdge-${{ needs.create_release.outputs.version }}-manylinux2014_x86_64.tar.gz - include_bin: "--include-bin /usr/local/bin/wasmedge --include-bin /usr/local/bin/wasmedgec" - - name: wasmedge/slim-runtime:${{ needs.create_release.outputs.version }} - artifact_name: build_manylinux2014_runtime_only - include_bin: "--include-bin /usr/local/bin/wasmedge" - name: Build DockerSlim Images - needs: - [create_release, build_on_manylinux2014, build_manylinux2014_runtime_only] - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - name: Prepare tarball - uses: actions/download-artifact@v3 - with: - name: ${{ matrix.artifact_name }} - path: utils/docker - - name: Grant the safe directory for git - run: | - git config --global --add safe.directory $(pwd) - - name: Install requirements - run: | - curl -sL https://raw.githubusercontent.com/slimtoolkit/slim/master/scripts/install-slim.sh | sudo -E bash - - - name: Prepare docker env - id: docker_env - run: | - echo "docker_image=${{ matrix.name }}" >> $GITHUB_OUTPUT - echo "created=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Login to DockerHub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - name: Run slim - run: | - slim build \ - --dockerfile Dockerfile.release \ - --dockerfile-context utils/docker \ - --tag ${{ steps.docker_env.outputs.docker_image }} \ - --http-probe-off \ - --include-bin /usr/lib/x86_64-linux-gnu/libnss_compat.so.2 \ - --include-bin /usr/lib/x86_64-linux-gnu/libnss_dns.so.2 \ - --include-bin /usr/lib/x86_64-linux-gnu/libnss_files.so.2 \ - --include-bin /usr/lib/x86_64-linux-gnu/libresolv.so.2 \ - --include-path /etc/services \ - ${{ matrix.include_bin }} \ - --cbo-build-arg VERSION="${{ needs.create_release.outputs.version }}" \ - --cbo-label org.opencontainers.image.title="${{ github.event.repository.name }}" \ - --cbo-label org.opencontainers.image.description="${{ github.event.repository.description }}" \ - --cbo-label org.opencontainers.image.url="${{ github.event.repository.html_url }}" \ - --cbo-label org.opencontainers.image.source="${{ github.event.repository.clone_url }}" \ - --cbo-label org.opencontainers.image.version="${{ needs.create_release.outputs.version }}" \ - --cbo-label org.opencontainers.image.created="${{ steps.docker_env.outputs.created }}" \ - --cbo-label org.opencontainers.image.revision="${{ github.sha }}" \ - --cbo-label org.opencontainers.image.licenses="${{ github.event.repository.license.spdx_id }}" - - name: Push to DockerHub - run: | - docker push ${{ steps.docker_env.outputs.docker_image }} - generate_sbom: name: Generate SBOM runs-on: ubuntu-latest needs: create_release steps: - name: checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Grant the safe directory for git run: | diff --git a/.github/workflows/reusable-build-extensions-on-legacy-manylinux.yml b/.github/workflows/reusable-build-extensions-on-legacy-manylinux.yml new file mode 100644 index 000000000000..bf9254a4e66f --- /dev/null +++ b/.github/workflows/reusable-build-extensions-on-legacy-manylinux.yml @@ -0,0 +1,101 @@ +name: Build extensions on legacy manylinux + +on: + workflow_call: + inputs: + runner: + type: string + required: true + docker_tag: + type: string + required: true + asset_tag: + type: string + required: true + plugins: + description: 'JSON array of the plugins' + type: string + required: true + version: + type: string + required: true + release: + type: boolean + default: false + +env: + # https://github.blog/changelog/2024-03-07-github-actions-all-actions-will-run-on-node20-instead-of-node16-by-default/ + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + +jobs: + build: + if: ${{ startsWith(inputs.asset_tag, 'manylinux2014') }} + strategy: + fail-fast: false + matrix: + include: ${{ fromJSON(inputs.plugins) }} + name: ${{ matrix.plugin }} + runs-on: ${{ inputs.runner }} + container: + image: wasmedge/wasmedge:${{ inputs.docker_tag }} + # Required for mounting debugfs + # Tests of wasm_bpf also require privileges + options: --privileged + env: + bin_name: ${{ matrix.bin }} + target: ${{ matrix.testBin }} + test_dir: build/test/plugins/${{ matrix.dir }} + output_dir: build/plugins/${{ matrix.dir }} + steps: + - id: var + run: | + echo "artifact=WasmEdge-plugin-${{ matrix.plugin }}-${{ inputs.version }}-${{ inputs.asset_tag }}.tar.gz" >> $GITHUB_OUTPUT + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Ensure git safe directory + run: | + git config --global --add safe.directory $(pwd) + - if: ${{ inputs.release }} + name: Prepare target for release + run: | + target=${bin_name%.*} + echo "target=${target#lib}" >> $GITHUB_ENV + - name: Build ${{ matrix.plugin }} + shell: bash + run: | + cmake -Bbuild -GNinja \ + -DCMAKE_BUILD_TYPE=Release \ + -DWASMEDGE_BUILD_TESTS=${{ inputs.release && 'OFF' || 'ON' }} \ + -DWASMEDGE_BUILD_TOOLS=OFF \ + -DWASMEDGE_USE_LLVM=OFF \ + -DOPENSSL_ROOT_DIR=${OpenSSL_DIR} \ + ${{ matrix.options }} + cmake --build build --target ${target} + + cp -f ${output_dir}/${bin_name} ${bin_name} + tar -zcvf ${{ steps.var.outputs.artifact }} ${bin_name} + - if: ${{ !inputs.release && matrix.plugin == 'wasm_bpf' }} + name: Prepare test env + shell: bash + run: | + # Running tests of wasm_bpf requires proper ebpf running environment + mount -t debugfs none /sys/kernel/debug + - if: ${{ !inputs.release }} + name: Test ${{ matrix.plugin }} + run: | + cd ${test_dir} + ./${target} + cd - + - if: ${{ !inputs.release }} + name: Upload artifact ${{ matrix.plugin }} + uses: actions/upload-artifact@v3 + with: + name: ${{ steps.var.outputs.artifact }} + path: ${{ steps.var.outputs.artifact }} + - if: ${{ inputs.release }} + name: Upload ${{ steps.var.outputs.artifact }} + run: | + gh release upload ${{ inputs.version }} ${{ steps.var.outputs.artifact }} --clobber + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/reusable-build-extensions-on-manylinux.yml b/.github/workflows/reusable-build-extensions-on-manylinux.yml index 12cb57ed80f7..26b32a72b4db 100644 --- a/.github/workflows/reusable-build-extensions-on-manylinux.yml +++ b/.github/workflows/reusable-build-extensions-on-manylinux.yml @@ -3,16 +3,17 @@ name: Build extensions on manylinux on: workflow_call: inputs: - arch: - type: string - required: true runner: type: string required: true docker_tag: type: string required: true + asset_tag: + type: string + required: true plugins: + description: 'JSON array of the plugins' type: string required: true version: @@ -22,138 +23,80 @@ on: type: boolean default: false -env: - build_tests: ${{ inputs.release && 'Off' || 'On' }} - build_type: Release - OPENVINO_VERSION: "2023.0.2" - OPENVINO_YEAR: "2023" - PYTORCH_VERSION: "1.8.2" - PYTORCH_INSTALL_TO: "." - jobs: - prepare: - name: Prepare files (${{ inputs.docker_tag }}) + build: + if: ${{ startsWith(inputs.asset_tag, 'manylinux_2_28') }} + strategy: + fail-fast: false + matrix: + include: ${{ fromJSON(inputs.plugins) }} + name: ${{ matrix.plugin }} runs-on: ${{ inputs.runner }} container: image: wasmedge/wasmedge:${{ inputs.docker_tag }} # Required for mounting debugfs # Tests of wasm_bpf also require privileges options: --privileged - outputs: - cache_key1: ${{ steps.prep.outputs.cache_key1 }} - cache_path1: ${{ steps.prep.outputs.cache_path1 }} - cache_key2: ${{ steps.prep.outputs.cache_key2 }} - cache_path2: ${{ steps.prep.outputs.cache_path2 }} - steps: - - id: prep - run: | - echo "cache_key1=${{ github.workflow }}-${{ github.head_ref || github.ref }}-${{ inputs.docker_tag }}-1-${{ github.run_id }}" >> $GITHUB_OUTPUT - echo "cache_path1=${{ github.workspace }}" >> $GITHUB_OUTPUT - echo "cache_key2=${{ github.workflow }}-${{ github.head_ref || github.ref }}-${{ inputs.docker_tag }}-2-${{ github.run_id }}" >> $GITHUB_OUTPUT - echo "cache_path2=$HOME" >> $GITHUB_OUTPUT - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Ensure git safe directory - run: | - git config --global --add safe.directory $(pwd) - - name: Install dependencies - shell: bash - run: | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y - mkdir -p build - bash ./utils/wasi-nn/install-pytorch.sh --disable-cxx11-abi - source "$HOME/.cargo/env" - bash ./utils/wasi-crypto/build-openssl.sh - - name: Build ${{ matrix.plugin }} - shell: bash - run: | - source "$HOME/.cargo/env" - export Torch_DIR=$(pwd)/${PYTORCH_INSTALL_TO}/libtorch - if [[ ${build_tests} != "On" ]]; then - target=${bin_name%.*} - target=${target#lib} - fi - - cmake -Bbuild -GNinja -DWASMEDGE_BUILD_TESTS=${build_tests} -DCMAKE_BUILD_TYPE=${build_type} -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DWASMEDGE_BUILD_TOOLS=OFF -DOPENSSL_ROOT_DIR=$(pwd)/openssl-1.1.1n/openssl - - uses: actions/cache/save@v3 - with: - key: ${{ steps.prep.outputs.cache_key1 }} - path: ${{ steps.prep.outputs.cache_path1 }} - - uses: actions/cache/save@v3 - with: - key: ${{ steps.prep.outputs.cache_key2 }} - path: ${{ steps.prep.outputs.cache_path2 }} - - build_on_manylinux: - needs: [prepare] - strategy: - fail-fast: false - max-parallel: 1 - matrix: - include: ${{ fromJSON(inputs.plugins) }} - name: ${{ matrix.plugin }} (${{ inputs.docker_tag }}) - runs-on: ${{ inputs.runner }} - container: wasmedge/wasmedge:${{ inputs.docker_tag }} env: bin_name: ${{ matrix.bin }} - target: ${{ inputs.release && matrix.bin || matrix.testBin }} + target: ${{ matrix.testBin }} test_dir: build/test/plugins/${{ matrix.dir }} output_dir: build/plugins/${{ matrix.dir }} steps: - - id: prep + - id: var run: | - echo "artifact=WasmEdge-plugin-${{ matrix.plugin }}-${{ inputs.version }}-${{ inputs.docker_tag }}.tar.gz" >> $GITHUB_OUTPUT - echo "filename=plugin_${{ matrix.plugin }}.tar.gz" >> $GITHUB_OUTPUT - - uses: actions/cache/restore@v3 - with: - key: ${{ needs.prepare.outputs.cache_key1 }} - path: ${{ needs.prepare.outputs.cache_path1 }} - - uses: actions/cache/restore@v3 + echo "artifact=WasmEdge-plugin-${{ matrix.plugin }}-${{ inputs.version }}-${{ inputs.asset_tag }}.tar.gz" >> $GITHUB_OUTPUT + - uses: actions/checkout@v4 with: - key: ${{ needs.prepare.outputs.cache_key2 }} - path: ${{ needs.prepare.outputs.cache_path2 }} - - name: Install dependencies - shell: bash + fetch-depth: 0 + - name: Ensure git safe directory + run: | + git config --global --add safe.directory $(pwd) + - if: ${{ inputs.release }} + name: Prepare target for release run: | - mkdir -p build - bash ./utils/wasi-nn/install-pytorch.sh --disable-cxx11-abi + target=${bin_name%.*} + echo "target=${target#lib}" >> $GITHUB_ENV - name: Build ${{ matrix.plugin }} shell: bash run: | - export Torch_DIR=$(pwd)/${PYTORCH_INSTALL_TO}/libtorch - if [[ ${build_tests} != "On" ]]; then - target=${bin_name%.*} - target=${target#lib} - fi - - cmake -Bbuild -GNinja ${{ matrix.options }} + cmake -Bbuild -GNinja \ + -DCMAKE_BUILD_TYPE=Release \ + -DWASMEDGE_BUILD_TESTS=${{ inputs.release && 'OFF' || 'ON' }} \ + -DWASMEDGE_BUILD_TOOLS=OFF \ + -DWASMEDGE_USE_LLVM=OFF \ + -DOPENSSL_ROOT_DIR=${OpenSSL_DIR} \ + ${{ matrix.options }} cmake --build build --target ${target} cp -f ${output_dir}/${bin_name} ${bin_name} - tar -zcvf ${{ steps.prep.outputs.filename }} ${bin_name} - - name: Test ${{ matrix.plugin }} - if: ${{ !inputs.release }} + tar -zcvf ${{ steps.var.outputs.artifact }} ${bin_name} + - if: ${{ !inputs.release && matrix.plugin == 'wasm_bpf' }} + name: Prepare test env + shell: bash + run: | + # Running tests of wasm_bpf requires proper ebpf running environment + mount -t debugfs none /sys/kernel/debug + - if: ${{ !inputs.release }} + name: Test ${{ matrix.plugin }} run: | cd ${test_dir} ./${target} cd - - - name: Upload artifact ${{ matrix.plugin }} - if: ${{ !inputs.release }} - uses: actions/upload-artifact@v3 + - if: ${{ !inputs.release }} + name: Upload artifact ${{ matrix.plugin }} + uses: actions/upload-artifact@v4 with: - name: ${{ steps.prep.outputs.artifact }} - path: ${{ steps.prep.outputs.filename }} - - name: Install gh on manylinux - if: ${{ inputs.release }} + name: ${{ steps.var.outputs.artifact }} + path: ${{ steps.var.outputs.artifact }} + - if: ${{ inputs.release }} + name: Install gh run: | - type -p yum-config-manager >/dev/null || sudo yum install yum-utils - yum-config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo + yum check-update || true yum install -y gh - - name: Upload WasmEdge ${{ matrix.plugin }} plugin tar.gz package - if: ${{ inputs.release }} + - if: ${{ inputs.release }} + name: Upload ${{ steps.var.outputs.artifact }} + run: | + gh release upload ${{ inputs.version }} ${{ steps.var.outputs.artifact }} --clobber env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - mv ${{ steps.prep.outputs.filename }} ${{ steps.prep.outputs.artifact }} - gh release upload ${{ inputs.version }} ${{ steps.prep.outputs.artifact }} --clobber diff --git a/.github/workflows/reusable-build-extensions.yml b/.github/workflows/reusable-build-extensions.yml index 9da37f86e882..33c0cd2b4652 100644 --- a/.github/workflows/reusable-build-extensions.yml +++ b/.github/workflows/reusable-build-extensions.yml @@ -11,31 +11,118 @@ on: default: false jobs: + # ------------------------------------------------------------------# + # The list of build targets is in the file: + # .github/workflows/matrix-extensions.json + # ------------------------------------------------------------------# prepare: - name: Prepare matrix values + name: Prepare ${{ inputs.asset_tag }} runs-on: ubuntu-latest outputs: - matrix: ${{ steps.prep.outputs.matrix }} + manylinux_2_28_x86_64: ${{ steps.readfile.outputs.manylinux_2_28_x86_64 }} + manylinux_2_28_aarch64: ${{ steps.readfile.outputs.manylinux_2_28_aarch64 }} + manylinux2014_x86_64: ${{ steps.readfile.outputs.manylinux2014_x86_64 }} + manylinux2014_aarch64: ${{ steps.readfile.outputs.manylinux2014_aarch64 }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - id: prep - uses: ./.github/actions/expand-variables + - id: filter + uses: dorny/paths-filter@v3 + with: + filters: '.github/extensions.paths-filter.yml' + - id: readfile + uses: actions/github-script@v7 + with: + result-encoding: string + script: | + const fs = require("fs") + const s = fs.readFileSync(".github/workflows/matrix-extensions.json") + let plugins = JSON.parse(s).plugins + if (!${{ inputs.release || fromJSON(steps.filter.outputs.all) }}) { + plugins = plugins.filter( + (plugin) => !(process.env[plugin.plugin] != 'true') + ) + } + let asset_tags = [ + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64", + "manylinux2014_x86_64", + "manylinux2014_aarch64", + ] + for (const tag of asset_tags) { + core.setOutput(tag, plugins.filter( + (plugin) => plugin.platforms.includes(tag) + ).map((plugin) => { + let copy = { ...plugin } + delete copy.platforms + return copy + })) + } + env: + wasi_crypto: ${{ steps.filter.outputs.wasi_crypto }} + wasi_nn-ggml: ${{ steps.filter.outputs.wasi_nn-ggml }} + wasi_nn-pytorch: ${{ steps.filter.outputs.wasi_nn-pytorch }} + wasi_nn-tensorflowlite: ${{ steps.filter.outputs.wasi_nn-tensorflowlite }} + wasi_nn-whisper: ${{ steps.filter.outputs.wasi_nn-whisper }} + wasi_nn-piper: ${{ steps.filter.outputs.wasi_nn-piper }} + wasm_bpf: ${{ steps.filter.outputs.wasm_bpf }} + wasmedge_ffmpeg: ${{ steps.filter.outputs.wasmedge_ffmpeg }} + wasmedge_image: ${{ steps.filter.outputs.wasmedge_image }} + wasmedge_llmc: ${{ steps.filter.outputs.wasmedge_llmc }} + wasmedge_opencvmini: ${{ steps.filter.outputs.wasmedge_opencvmini }} + wasmedge_process: ${{ steps.filter.outputs.wasmedge_process }} + wasmedge_stablediffusion: ${{ steps.filter.outputs.wasmedge_stablediffusion }} + wasmedge_tensorflow: ${{ steps.filter.outputs.wasmedge_tensorflow }} + wasmedge_tensorflowlite: ${{ steps.filter.outputs.wasmedge_tensorflowlite }} + wasmedge_zlib: ${{ steps.filter.outputs.wasmedge_zlib }} - build_extensions_on_manylinux: - needs: [prepare] + build_on_manylinux: + needs: prepare strategy: fail-fast: false matrix: - include: ${{ fromJSON(needs.prepare.outputs.matrix) }} - name: Build all plugins on ${{ matrix.docker_tag }} + include: + - runner: 'ubuntu-latest' + docker_tag: 'manylinux_2_28_x86_64-plugins-deps' + asset_tag: 'manylinux_2_28_x86_64' + plugins: ${{ needs.prepare.outputs.manylinux_2_28_x86_64 }} + - runner: 'linux-arm64-v2' + docker_tag: 'manylinux_2_28_aarch64-plugins-deps' + asset_tag: 'manylinux_2_28_aarch64' + plugins: ${{ needs.prepare.outputs.manylinux_2_28_aarch64 }} + name: ${{ matrix.asset_tag }} uses: ./.github/workflows/reusable-build-extensions-on-manylinux.yml with: - arch: ${{ matrix.arch }} runner: ${{ matrix.runner }} docker_tag: ${{ matrix.docker_tag }} - plugins: ${{ toJSON(matrix.plugins) }} + asset_tag: ${{ matrix.asset_tag }} + plugins: ${{ matrix.plugins }} + version: ${{ inputs.version }} + release: ${{ inputs.release }} + secrets: inherit + + build_on_legacy_manylinux: + needs: prepare + strategy: + fail-fast: false + matrix: + include: + - runner: 'ubuntu-latest' + docker_tag: 'manylinux2014_x86_64-plugins-deps' + asset_tag: 'manylinux2014_x86_64' + plugins: ${{ needs.prepare.outputs.manylinux2014_x86_64 }} + - runner: 'linux-arm64-v2' + docker_tag: 'manylinux2014_aarch64-plugins-deps' + asset_tag: 'manylinux2014_aarch64' + plugins: ${{ needs.prepare.outputs.manylinux2014_aarch64 }} + name: ${{ matrix.asset_tag }} + uses: ./.github/workflows/reusable-build-extensions-on-legacy-manylinux.yml + with: + runner: ${{ matrix.runner }} + docker_tag: ${{ matrix.docker_tag }} + asset_tag: ${{ matrix.asset_tag }} + plugins: ${{ matrix.plugins }} version: ${{ inputs.version }} release: ${{ inputs.release }} secrets: inherit diff --git a/.github/workflows/reusable-build-on-alpine-static.yml b/.github/workflows/reusable-build-on-alpine-static.yml index a2d82e2224a9..7fea3131c889 100644 --- a/.github/workflows/reusable-build-on-alpine-static.yml +++ b/.github/workflows/reusable-build-on-alpine-static.yml @@ -8,7 +8,10 @@ on: required: true release: type: boolean - + +permissions: + contents: read + jobs: build_on_debian_static: permissions: @@ -17,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory @@ -26,7 +29,7 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build WasmEdge - uses: docker/bake-action@v4 + uses: docker/bake-action@v5 with: files: ./utils/docker/docker-bake.alpine-static.hcl - name: Upload artifact diff --git a/.github/workflows/reusable-build-on-android.yml b/.github/workflows/reusable-build-on-android.yml index dfb3b689d6f6..94d38950817b 100644 --- a/.github/workflows/reusable-build-on-android.yml +++ b/.github/workflows/reusable-build-on-android.yml @@ -10,7 +10,10 @@ on: type: boolean upload_asset_url: type: string - + +permissions: + contents: read + jobs: build_on_android: permissions: @@ -20,7 +23,7 @@ jobs: container: image: wasmedge/wasmedge:latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install dependency @@ -39,7 +42,7 @@ jobs: - name: Build WasmEdge run: | export ANDROID_NDK_HOME=$(pwd)/android-ndk-r23b/ - cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_PACKAGE="TGZ" -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=23 -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a -DCMAKE_ANDROID_NDK=$ANDROID_NDK_HOME -DCMAKE_ANDROID_STL_TYPE=c++_static + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_PACKAGE="TGZ" -DWASMEDGE_USE_LLVM=OFF -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=23 -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a -DCMAKE_ANDROID_NDK=$ANDROID_NDK_HOME -DCMAKE_ANDROID_STL_TYPE=c++_static cmake --build build cmake --build build --target package - name: Upload artifact diff --git a/.github/workflows/reusable-build-on-debian-static.yml b/.github/workflows/reusable-build-on-debian-static.yml index 88ce4b9e9230..9a0643fb5718 100644 --- a/.github/workflows/reusable-build-on-debian-static.yml +++ b/.github/workflows/reusable-build-on-debian-static.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory @@ -26,7 +26,7 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build WasmEdge - uses: docker/bake-action@v4 + uses: docker/bake-action@v5 with: files: ./utils/docker/docker-bake.debian-static.hcl - name: Upload artifact diff --git a/.github/workflows/reusable-build-on-debian.yml b/.github/workflows/reusable-build-on-debian.yml new file mode 100644 index 000000000000..956b825a1f83 --- /dev/null +++ b/.github/workflows/reusable-build-on-debian.yml @@ -0,0 +1,56 @@ +name: Build on Debian + +on: + workflow_call: + inputs: + version: + type: string + required: true + release: + type: boolean + upload_asset_url: + type: string + +permissions: + contents: read + +jobs: + build_debian: + permissions: + contents: write + name: Debian Testing + runs-on: ubuntu-latest + container: + image: debian:testing + steps: + - name: Install dependency + run: | + apt update && apt upgrade -y && apt install -y \ + software-properties-common wget cmake ninja-build curl \ + git dpkg-dev llvm-dev liblld-dev gcc rpm dpkg-dev g++ + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Grant the safe directory for git + run: | + git config --global --add safe.directory $(pwd) + - name: Build WasmEdge + run: | + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_TESTS=ON -DWASMEDGE_BUILD_PACKAGE="TGZ" . + cmake --build build + - name: Test WasmEdge + run: | + export LD_LIBRARY_PATH="$(pwd)/build/lib/api:$LD_LIBRARY_PATH" + cd build + ./tools/wasmedge/wasmedge -v + ctest + cd - + - name: Create package tarball + run: | + cmake --build build --target package + - name: Upload artifact + if: ${{ !inputs.release }} + uses: actions/upload-artifact@v3 + with: + name: WasmEdge-${{ inputs.version }}-debian.tar.gz + path: build/WasmEdge-${{ inputs.version }}-Linux.tar.gz diff --git a/.github/workflows/reusable-build-on-fedora.yml b/.github/workflows/reusable-build-on-fedora.yml index 13e87fc1e7eb..cf44492a476b 100644 --- a/.github/workflows/reusable-build-on-fedora.yml +++ b/.github/workflows/reusable-build-on-fedora.yml @@ -11,21 +11,35 @@ on: upload_asset_url: type: string +permissions: + contents: read + jobs: build_fedora: + strategy: + fail-fast: false + matrix: + include: + - name: Fedora Rawhide + image: fedora:rawhide + asset_postfix: fedora-rawhide + - name: Fedora Latest + image: fedora:latest + asset_postfix: fedora permissions: contents: write - name: Fedora latest + name: ${{ matrix.name }} runs-on: ubuntu-latest container: - image: fedora:latest + image: ${{ matrix.image }} + options: --privileged steps: - name: Install dependency run: | dnf update -y dnf install -y cmake ninja-build llvm llvm-devel lld-devel clang git file rpm-build dpkg-dev spdlog-devel \ pkgconf-pkg-config protobuf-c-compiler grpc-cpp grpc-plugins grpc-devel - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Grant the safe directory for git @@ -49,5 +63,5 @@ jobs: if: ${{ !inputs.release }} uses: actions/upload-artifact@v3 with: - name: WasmEdge-${{ inputs.version }}-fedora35.tar.gz + name: WasmEdge-${{ inputs.version }}-${{ matrix.asset_postfix }}.tar.gz path: build/WasmEdge-${{ inputs.version }}-Linux.tar.gz diff --git a/.github/workflows/reusable-build-on-macos.yml b/.github/workflows/reusable-build-on-macos.yml index 5f9d523de0d0..592bd61d3364 100644 --- a/.github/workflows/reusable-build-on-macos.yml +++ b/.github/workflows/reusable-build-on-macos.yml @@ -11,7 +11,10 @@ on: required: true release: type: boolean - + +permissions: + contents: read + jobs: build_on_macos: permissions: @@ -26,16 +29,22 @@ jobs: BUILD_TESTS: ON BUILD_TYPE: Debug steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory run: | git config --global --add safe.directory $(pwd) - - name: Setup build environment + - name: Setup build environment - non-release + if: ${{ !inputs.release }} + run: | + eval $(/opt/homebrew/bin/brew shellenv) + brew install llvm ninja cmake wabt grpc + - name: Setup build environment - release + if: ${{ inputs.release }} run: | eval $(/opt/homebrew/bin/brew shellenv) - brew install llvm@16 ninja cmake wabt grpc + brew install llvm ninja cmake wabt - name: Set environment variables for release if: ${{ inputs.release }} run: | @@ -44,7 +53,7 @@ jobs: - name: Build WasmEdge run: | eval $(/opt/homebrew/bin/brew shellenv) - export LLVM_DIR="$(brew --prefix)/opt/llvm@16/lib/cmake" + export LLVM_DIR="$(brew --prefix)/opt/llvm/lib/cmake" export CC=clang export CXX=clang++ rm -rf build output diff --git a/.github/workflows/reusable-build-on-manylinux.yml b/.github/workflows/reusable-build-on-manylinux.yml index f74a5086a0d3..5d34d0af4a33 100644 --- a/.github/workflows/reusable-build-on-manylinux.yml +++ b/.github/workflows/reusable-build-on-manylinux.yml @@ -12,6 +12,9 @@ on: release: type: boolean +permissions: + contents: read + jobs: build_on_manylinux: permissions: @@ -23,6 +26,8 @@ jobs: name: ${{ matrix.name }} runs-on: ${{ matrix.runner }} container: wasmedge/wasmedge:${{ matrix.docker_tag }} + env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true steps: - uses: actions/checkout@v3 with: @@ -30,7 +35,7 @@ jobs: - name: Ensure git safe directory run: | git config --global --add safe.directory $(pwd) - - name: Build ${{ matrix.docker_tag }} package + - name: Build ${{ matrix.asset_tag }} package run: | bash utils/docker/build-manylinux.sh ./build/tools/wasmedge/wasmedge -v @@ -38,11 +43,12 @@ jobs: uses: actions/upload-artifact@v3 with: path: build/WasmEdge-${{ inputs.version }}-Linux.tar.gz - name: WasmEdge-${{ inputs.version }}-${{ matrix.docker_tag }}.tar.gz - - name: Install gh on manylinux - if: ${{ inputs.release }} + name: WasmEdge-${{ inputs.version }}-${{ matrix.asset_tag }}.tar.gz + - name: Install gh except for manylinux2014 + if: ${{ inputs.release && (!contains(matrix.docker_tag, 'manylinux2014')) }} run: | - type -p yum-config-manager >/dev/null || sudo yum install yum-utils + echo "Detected docker tag: ${{ matrix.docker_tag }}" + type -p yum-config-manager >/dev/null || yum install -y yum-utils yum-config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo yum install -y gh - name: Upload rpm package @@ -50,19 +56,19 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - mv build/WasmEdge-${{ inputs.version }}-Linux.rpm WasmEdge-${{ inputs.version }}-${{ matrix.docker_tag }}.rpm - gh release upload ${{ inputs.version }} WasmEdge-${{ inputs.version }}-${{ matrix.docker_tag }}.rpm --clobber + mv build/WasmEdge-${{ inputs.version }}-Linux.rpm WasmEdge-${{ inputs.version }}-${{ matrix.asset_tag }}.rpm + gh release upload ${{ inputs.version }} WasmEdge-${{ inputs.version }}-${{ matrix.asset_tag }}.rpm --clobber - name: Upload tar.gz package if: ${{ inputs.release }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - mv build/WasmEdge-${{ inputs.version }}-Linux.tar.gz WasmEdge-${{ inputs.version }}-${{ matrix.docker_tag }}.tar.gz - gh release upload ${{ inputs.version }} WasmEdge-${{ inputs.version }}-${{ matrix.docker_tag }}.tar.gz --clobber + mv build/WasmEdge-${{ inputs.version }}-Linux.tar.gz WasmEdge-${{ inputs.version }}-${{ matrix.asset_tag }}.tar.gz + gh release upload ${{ inputs.version }} WasmEdge-${{ inputs.version }}-${{ matrix.asset_tag }}.tar.gz --clobber - name: Upload tar.xz package if: ${{ inputs.release }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - mv build/WasmEdge-${{ inputs.version }}-Linux.tar.xz WasmEdge-${{ inputs.version }}-${{ matrix.docker_tag }}.tar.xz - gh release upload ${{ inputs.version }} WasmEdge-${{ inputs.version }}-${{ matrix.docker_tag }}.tar.xz --clobber + mv build/WasmEdge-${{ inputs.version }}-Linux.tar.xz WasmEdge-${{ inputs.version }}-${{ matrix.asset_tag }}.tar.xz + gh release upload ${{ inputs.version }} WasmEdge-${{ inputs.version }}-${{ matrix.asset_tag }}.tar.xz --clobber diff --git a/.github/workflows/reusable-build-on-ubuntu.yml b/.github/workflows/reusable-build-on-ubuntu.yml index 4df645267a82..ec3233e02a1e 100644 --- a/.github/workflows/reusable-build-on-ubuntu.yml +++ b/.github/workflows/reusable-build-on-ubuntu.yml @@ -12,6 +12,9 @@ on: release: type: boolean +permissions: + contents: read + jobs: build_on_ubuntu: permissions: @@ -20,17 +23,23 @@ jobs: fail-fast: false matrix: include: ${{ fromJSON(inputs.matrix) }} - name: ${{ matrix.name }} (${{ matrix.compiler }}, ${{ matrix.build_type }}) - runs-on: ubuntu-latest + name: ${{ matrix.name }} ${{ matrix.arch }} (${{ matrix.compiler }}, ${{ matrix.build_type }}) + runs-on: ${{ matrix.runner }} env: BUILD_TESTS: OFF container: wasmedge/wasmedge:${{ matrix.docker_tag }} steps: - - name: Install dependencies + - name: Install dependencies - non-release + if: ${{ !inputs.release }} run: | apt-get update apt-get install -y pkg-config protobuf-compiler-grpc libgrpc-dev libgrpc++-dev - - uses: actions/checkout@v3 + - name: Install dependencies - release + if: ${{ inputs.release }} + run: | + apt-get update + apt-get install -y pkg-config + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory @@ -44,7 +53,7 @@ jobs: run: | git config --global --add safe.directory $(pwd) - name: Build (${{ matrix.compiler }}, ${{ matrix.build_type }}) - if: ${{ ! matrix.coverage }} + if: ${{ !matrix.coverage }} shell: bash env: CMAKE_BUILD_TYPE: ${{ matrix.build_type }} @@ -57,7 +66,7 @@ jobs: cmake --build build cmake --build build --target package - name: Test - if: ${{ !matrix.coverage && env.BUILD_TESTS }} + if: ${{ !matrix.coverage && matrix.tests }} run: | export LD_LIBRARY_PATH="$(pwd)/build/lib/api:$LD_LIBRARY_PATH" cd build @@ -89,13 +98,14 @@ jobs: && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ && apt update \ && apt install gh -y - mv build/WasmEdge-${{ inputs.version }}-Linux.tar.gz WasmEdge-${{ inputs.version }}-ubuntu20.04_x86_64.tar.gz - gh release upload ${{ inputs.version }} WasmEdge-${{ inputs.version }}-ubuntu20.04_x86_64.tar.gz --clobber + mv build/WasmEdge-${{ inputs.version }}-Linux.tar.gz WasmEdge-${{ inputs.version }}-ubuntu20.04_${{ matrix.arch }}.tar.gz + gh release upload ${{ inputs.version }} WasmEdge-${{ inputs.version }}-ubuntu20.04_${{ matrix.arch }}.tar.gz --clobber - name: Create and upload coverage report to Codecov if: ${{ matrix.coverage }} - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./build/codecov.xml name: codecov-wasmedge fail_ci_if_error: true + verbose: true diff --git a/.github/workflows/reusable-build-on-windows-msvc.yml b/.github/workflows/reusable-build-on-windows-msvc.yml index 2bed2e18429e..43dce8100332 100644 --- a/.github/workflows/reusable-build-on-windows-msvc.yml +++ b/.github/workflows/reusable-build-on-windows-msvc.yml @@ -9,6 +9,9 @@ on: release: type: boolean +permissions: + contents: read + jobs: build_on_windows: permissions: @@ -18,7 +21,7 @@ jobs: env: build_tests: ON steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory @@ -28,9 +31,10 @@ jobs: uses: crazy-max/ghaction-chocolatey@v3 with: args: install cmake ninja vswhere - - uses: GuillaumeFalourd/setup-windows10-sdk-action@v1.11 + - name: Install Windows SDK + uses: GuillaumeFalourd/setup-windows10-sdk-action@v2 with: - sdk-version: 19041 + sdk-version: 22621 - name: Set environment variables for release if: ${{ inputs.release }} run: | @@ -39,29 +43,30 @@ jobs: run: | $vsPath = (vswhere -latest -property installationPath) Import-Module (Join-Path $vsPath "Common7\Tools\Microsoft.VisualStudio.DevShell.dll") - Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64 -winsdk=10.0.19041.0" - $llvm = "LLVM-16.0.6-win64-MultiThreadedDLL.zip" - curl -sLO https://github.com/WasmEdge/llvm-windows/releases/download/llvmorg-16.0.6/LLVM-16.0.6-win64-MultiThreadedDLL.zip -o $llvm + Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64 -winsdk=10.0.22621.0" + $uri = "https://github.com/WasmEdge/llvm-windows/releases/download/llvmorg-17.0.6/LLVM-17.0.6-win64-MultiThreadedDLL.zip" + $llvm = "LLVM-17.0.6-win64-MultiThreadedDLL.zip" + Invoke-WebRequest -Uri "$uri" -HttpVersion 2.0 -OutFile "$llvm" Expand-Archive -Path $llvm - $llvm_dir = "$pwd\\LLVM-16.0.6-win64-MultiThreadedDLL\\LLVM-16.0.6-win64\\lib\\cmake\\llvm" - $cmake_sys_version = "10.0.19041.0" + $llvm_dir = "$pwd\\LLVM-17.0.6-win64-MultiThreadedDLL\\LLVM-17.0.6-win64\\lib\\cmake\\llvm" + $cmake_sys_version = "10.0.22621.0" cmake -Bbuild -GNinja "-DCMAKE_SYSTEM_VERSION=$cmake_sys_version" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL "-DLLVM_DIR=$llvm_dir" "-DWASMEDGE_BUILD_TESTS=$Env:build_tests" -DWASMEDGE_BUILD_PACKAGE="ZIP" . cmake --build build - name: Test WasmEdge run: | $vsPath = (vswhere -latest -property installationPath) Import-Module (Join-Path $vsPath "Common7\Tools\Microsoft.VisualStudio.DevShell.dll") - Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64 -winsdk=10.0.19041.0" + Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64 -winsdk=10.0.22621.0" $Env:PATH += ";$pwd\\build\\lib\\api" cd build tools\wasmedge\wasmedge -v - ctest + ctest --output-on-failure cd - - name: Create WasmEdge package run: | $vsPath = (vswhere -latest -property installationPath) Import-Module (Join-Path $vsPath "Common7\Tools\Microsoft.VisualStudio.DevShell.dll") - Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64 -winsdk=10.0.19041.0" + Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64 -winsdk=10.0.22621.0" cmake --build build --target package Get-ChildItem -Path "$pwd\\build" - name: Generate product version and package Windows installer diff --git a/.github/workflows/reusable-build-on-windows.yml b/.github/workflows/reusable-build-on-windows.yml index 295b5e9a5875..bd6cd23d91aa 100644 --- a/.github/workflows/reusable-build-on-windows.yml +++ b/.github/workflows/reusable-build-on-windows.yml @@ -18,7 +18,7 @@ jobs: env: build_tests: ON steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory @@ -27,43 +27,41 @@ jobs: - name: Install dependency uses: crazy-max/ghaction-chocolatey@v3 with: - args: install cmake ninja vswhere - - uses: GuillaumeFalourd/setup-windows10-sdk-action@v1.11 + args: install cmake ninja + - name: Upgrade dependency + uses: crazy-max/ghaction-chocolatey@v3 + with: + args: upgrade llvm + - name: Install Windows SDK + uses: GuillaumeFalourd/setup-windows10-sdk-action@v2 with: - sdk-version: 19041 + sdk-version: 22621 - name: Set environment variables for release if: ${{ inputs.release }} run: | echo "build_tests=OFF" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - name: Build WasmEdge run: | - $vsPath = (vswhere -latest -property installationPath) - Import-Module (Join-Path $vsPath "Common7\Tools\Microsoft.VisualStudio.DevShell.dll") - Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64 -winsdk=10.0.19041.0" - $llvm = "LLVM-16.0.6-win64-MultiThreadedDLL.zip" - curl -sLO https://github.com/WasmEdge/llvm-windows/releases/download/llvmorg-16.0.6/LLVM-16.0.6-win64-MultiThreadedDLL.zip -o $llvm + $uri = "https://github.com/WasmEdge/llvm-windows/releases/download/llvmorg-17.0.6/LLVM-17.0.6-win64-MultiThreadedDLL.zip" + $llvm = "LLVM-17.0.6-win64-MultiThreadedDLL.zip" + Invoke-WebRequest -Uri "$uri" -HttpVersion 2.0 -OutFile "$llvm" Expand-Archive -Path $llvm - $llvm_dir = "$pwd\\LLVM-16.0.6-win64-MultiThreadedDLL\\LLVM-16.0.6-win64\\lib\\cmake\\llvm" - $Env:CC = "clang-cl" - $Env:CXX = "clang-cl" - $cmake_sys_version = "10.0.19041.0" - cmake -Bbuild -GNinja "-DCMAKE_SYSTEM_VERSION=$cmake_sys_version" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL "-DLLVM_DIR=$llvm_dir" "-DWASMEDGE_BUILD_TESTS=$Env:build_tests" -DWASMEDGE_BUILD_PACKAGE="ZIP" . + $llvm_dir = "$pwd\\LLVM-17.0.6-win64-MultiThreadedDLL\\LLVM-17.0.6-win64\\lib\\cmake\\llvm" + $Env:CC = "$pwd\\LLVM-17.0.6-win64-MultiThreadedDLL\\LLVM-17.0.6-win64\\bin\\clang-cl.exe" + $Env:CXX = "$pwd\\LLVM-17.0.6-win64-MultiThreadedDLL\\LLVM-17.0.6-win64\\bin\\clang-cl.exe" + $llvm_mt = "$Env:ProgramFiles\\LLVM\\bin\\llvm-mt.exe" + $cmake_sys_version = "10.0.22621.0" + cmake -Bbuild -GNinja "-DCMAKE_SYSTEM_VERSION=$cmake_sys_version" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL -DCMAKE_MT="$llvm_mt" "-DLLVM_DIR=$llvm_dir" "-DWASMEDGE_BUILD_TESTS=$Env:build_tests" -DWASMEDGE_BUILD_PACKAGE="ZIP" . cmake --build build - name: Test WasmEdge run: | - $vsPath = (vswhere -latest -property installationPath) - Import-Module (Join-Path $vsPath "Common7\Tools\Microsoft.VisualStudio.DevShell.dll") - Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64 -winsdk=10.0.19041.0" $Env:PATH += ";$pwd\\build\\lib\\api" cd build tools\wasmedge\wasmedge -v - ctest + ctest --output-on-failure cd - - name: Create WasmEdge package run: | - $vsPath = (vswhere -latest -property installationPath) - Import-Module (Join-Path $vsPath "Common7\Tools\Microsoft.VisualStudio.DevShell.dll") - Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64 -winsdk=10.0.19041.0" cmake --build build --target package Get-ChildItem -Path "$pwd\\build" - name: Generate product version and package Windows installer diff --git a/.github/workflows/reusable-call-linter.yml b/.github/workflows/reusable-call-linter.yml index de94d8a288b2..02cb6c730169 100644 --- a/.github/workflows/reusable-call-linter.yml +++ b/.github/workflows/reusable-call-linter.yml @@ -2,14 +2,15 @@ name: Clang-Format on: workflow_call: - + +permissions: + contents: read + jobs: lint: - permissions: - contents: read runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory diff --git a/.github/workflows/reusable-create-source-tarball.yml b/.github/workflows/reusable-create-source-tarball.yml index d415ad412156..28e47546cd2f 100644 --- a/.github/workflows/reusable-create-source-tarball.yml +++ b/.github/workflows/reusable-create-source-tarball.yml @@ -9,6 +9,9 @@ on: release: type: boolean +permissions: + contents: read + jobs: create_source_tarball: permissions: @@ -16,7 +19,7 @@ jobs: name: Create source tarball runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Ensure git safe directory diff --git a/.github/workflows/static-code-analysis.yml b/.github/workflows/static-code-analysis.yml index 2ebfeecd9870..7772a2d90b66 100644 --- a/.github/workflows/static-code-analysis.yml +++ b/.github/workflows/static-code-analysis.yml @@ -39,6 +39,9 @@ on: - "CMakeLists.txt" - "cmake/**" +permissions: + contents: read + jobs: static_analysis: permissions: @@ -47,7 +50,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Ensure git safe directory run: | git config --global --add safe.directory $(pwd) diff --git a/.github/workflows/test-install-script.yml b/.github/workflows/test-install-script.yml index 3597adabb62b..0a7148bef368 100644 --- a/.github/workflows/test-install-script.yml +++ b/.github/workflows/test-install-script.yml @@ -31,14 +31,6 @@ jobs: fail-fast: false matrix: include: - - name: CentOS 8 Stream - host_runner: ubuntu-latest - package_manager: yum - docker_image: quay.io/centos/centos:stream8 - python_package: python3 python2 - python2_ex: python2 - python3_ex: python3 - extra_setup_command: yum install -y which - name: CentOS 7 host_runner: ubuntu-latest package_manager: yum @@ -47,6 +39,7 @@ jobs: python2_ex: python2 python3_ex: python3 extra_setup_command: yum install -y which + fix_mirror: "centos7" - name: Ubuntu 20.04 host_runner: ubuntu-latest package_manager: apt @@ -55,6 +48,7 @@ jobs: python2_ex: python2 python3_ex: python3 extra_setup_command: echo "No extra command" + fix_mirror: "" - name: Ubuntu 18.04 host_runner: ubuntu-latest package_manager: apt @@ -63,6 +57,7 @@ jobs: python2_ex: python2.7 python3_ex: python3 extra_setup_command: echo "No extra command" + fix_mirror: "" - name: Ubuntu 16.04 host_runner: ubuntu-latest package_manager: apt @@ -71,24 +66,45 @@ jobs: python2_ex: python2.7 python3_ex: python3.7 extra_setup_command: apt update -y && apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev wget && wget https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz && tar xzf Python-3.7.4.tgz && cd Python-3.7.4 && ./configure && make -j && make install && cd .. + fix_mirror: "" - name: manylinux2014 aarch64 - host_runner: linux-arm64 + host_runner: linux-arm64-v2 package_manager: yum docker_image: wasmedge/wasmedge:manylinux2014_aarch64 python_package: python2 python3 python2_ex: python2 python3_ex: python3 extra_setup_command: echo "No extra command" + fix_mirror: "centos7aarch64" name: ${{ matrix.name }} runs-on: ${{ matrix.host_runner }} container: image: ${{ matrix.docker_image }} + # For older OS like Ubuntu 16 & 18. + env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + steps: - uses: actions/checkout@v3 with: fetch-depth: 0 + - if: ${{ matrix.fix_mirror == 'centos7' }} + name: Fix mirrors on manylinux2014 + # Reference: https://github.com/pypa/manylinux/pull/1628 + run: | + sed -i 's/enabled=1/enabled=0/g' /etc/yum/pluginconf.d/fastestmirror.conf + sed -i 's/^mirrorlist/#mirrorlist/g' /etc/yum.repos.d/*.repo + sed -i 's;^.*baseurl=http://mirror;baseurl=https://vault;g' /etc/yum.repos.d/*.repo + - if: ${{ matrix.fix_mirror == 'centos7aarch64' }} + name: Fix mirrors on manylinux2014 for aarch64 + # Reference: https://github.com/pypa/manylinux/pull/1628 + run: | + sed -i 's/enabled=1/enabled=0/g' /etc/yum/pluginconf.d/fastestmirror.conf + sed -i 's/^mirrorlist/#mirrorlist/g' /etc/yum.repos.d/*.repo + sed -i 's;^.*baseurl=http://mirror;baseurl=https://vault;g' /etc/yum.repos.d/*.repo + sed -i 's;/centos/7/;/altarch/7/;g' /etc/yum.repos.d/*.repo - name: Install git and curl run: | ${{ matrix.extra_setup_command }} @@ -103,29 +119,6 @@ jobs: - name: Uninstall WasmEdge run: | bash utils/uninstall.sh -q -V - - name: Install WasmEdge latest release with all extensions - run: | - bash utils/install.sh -e all -D - - name: Uninstall WasmEdge with all extensions - run: | - bash utils/uninstall.sh -q -V - - name: Install deprecated WasmEdge specific release (0.10.0) - run: | - bash utils/install.sh -v 0.10.0 -D - - name: Uninstall WasmEdge - run: | - bash utils/uninstall.sh -q -V - - name: Install WasmEdge specific release (0.10.0) with all extensions - run: | - bash utils/install.sh -e all -v 0.10.0 -D - - name: Install WasmEdge and test for arm extension installation - run: | - bash utils/install.sh -e all --version=0.10.0-alpha.1 \ - --tf-version=0.10.0-alpha.1 --tf-deps-version=0.10.0-alpha.1 --tf-tools-version=0.10.0-alpha.1 \ - --image-version=0.10.0-alpha.1 - - name: Uninstall WasmEdge with all extensions - run: | - bash utils/uninstall.sh -q -V - name: Install WasmEdge and wasi_nn-ggml plugin (0.13.4) run: | bash utils/install.sh -v 0.13.4 --plugins wasi_nn-ggml -D @@ -133,31 +126,24 @@ jobs: - name: Uninstall WasmEdge with wasi_nn-ggml run: | bash utils/uninstall.sh -q -V - - name: Install versions multiple times + - name: Install WasmEdge and wasi_nn-ggml-noavx plugin (0.13.5) + if: ${{ matrix.docker_image == 'ubuntu:20.04' }} run: | - bash utils/install.sh -e all -D - bash utils/install.sh -e all -v 0.10.1 -D - bash utils/install.sh -e all -v 0.10.0 -D - - name: Uninstall WasmEdge + # Currently, we only support noavx build on ubuntu 20.04 + bash utils/install.sh -v 0.13.5 --plugins wasi_nn-ggml-noavx -D + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: WASI_NN-ggml Plugin found" || (echo "Fail: WASI_NN-ggml not found" && exit 1) + - name: Uninstall WasmEdge with wasi_nn-ggml-noavx + if: ${{ matrix.docker_image == 'ubuntu:20.04' }} run: | bash utils/uninstall.sh -q -V - - name: Tensorflow changes - libtensorflow_cc 2.6.0 will replace the old libtensorflow 2.6.0 - if: ${{ matrix.name != 'manylinux2014 aarch64' }} + - name: Install versions multiple times run: | - bash utils/install.sh -v 0.12.0-alpha.2 -e tensorflow --tf-version 0.12.0-alpha.2 --tf-deps-version 0.12.0-alpha.2 --tf-tools-version 0.12.0-alpha.2 - ls ~/.wasmedge/lib/ | grep libtensorflow_cc* && echo "Pass: libtensorflow_cc found" || (echo "Fail: libtensorflow_cc found not found" && exit 1) + bash utils/install.sh -D + bash utils/install.sh -v 0.13.1 -D + bash utils/install.sh -v 0.13.0 -D - name: Uninstall WasmEdge - if: ${{ matrix.name != 'manylinux2014 aarch64' }} run: | bash utils/uninstall.sh -q -V - - name: Plugins Install check - run: | - bash utils/install.sh -v 0.10.0-alpha.1 - ls ~/.wasmedge/plugin/ | grep .so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - bash utils/install.sh -v 0.10.0-alpha.1 -p ~/new_wasmedge - ls ~/new_wasmedge/plugin/ | grep .so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - bash utils/install.sh -v 0.10.0-alpha.1 -p /usr - ls /usr/lib/wasmedge/ | grep libwasmedgePluginWasmEdgeProcess.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - name: Latest Release Check run: | _res_git_=$(git ls-remote --refs --tags "https://github.com/WasmEdge/WasmEdge.git" | cut -d '/' -f 3 | awk '{ if ($1 ~ /-/) print; else print $0"_" ; }' | sort --version-sort | sed 's/_$//' | grep -e '^[0-9]\+.[0-9]\+.[0-9]\+$' | tail -1) @@ -166,24 +152,20 @@ jobs: (echo "Fail: Fetched version does not equal GitHub Ref\nFetched:$_res_git_\nCI:$_res_curl_" && exit 1) - macos: - strategy: - matrix: - include: - - name: MacOS-latest - host_runner: macos-latest - package_manager: brew - - name: MacOS-arm64 - host_runner: macos-14 - package_manager: brew - name: ${{ matrix.name }} - runs-on: ${{ matrix.host_runner }} + macos_amd64: + name: macos-amd64 + runs-on: macos-13 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Install zsh + run: | + eval $(/opt/homebrew/bin/brew shellenv) + brew install zsh + - name: Install WasmEdge latest release run: | bash utils/install.sh -D @@ -191,74 +173,75 @@ jobs: run: | bash utils/uninstall.sh -q -V - name: Check for bashrc generation - if: ${{ matrix.name != 'MacOS-arm64' }} run: | - rm ~/.bashrc + rm -f ~/.bashrc bash utils/install.sh -D if ls -a ~ | grep .bashrc; then echo "Fail: Bashrc found" && exit 1; else echo "Pass: Bashrc not found"; fi; - name: Check for bashrc generation if: ${{ matrix.name == 'MacOS-arm64' }} run: | - rm ~/.zshenv + rm -rf ~/.zshenv bash utils/install.sh -D if ls -a ~ | grep .zshenv; then echo echo "Pass: zshenv found"; else "Fail: zshenv not found" && exit 1; fi; - name: Uninstall WasmEdge run: | bash utils/uninstall.sh -q -V - - name: Install WasmEdge latest release with all extensions - if: ${{ matrix.name != 'MacOS-arm64' }} + - name: Plugins Install check MacOS-x86 run: | - bash utils/install.sh -e all -D - - name: Uninstall WasmEdge with all extensions - if: ${{ matrix.name != 'MacOS-arm64' }} + bash utils/install.sh -v 0.13.1 --plugins wasmedge_tensorflow + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflow.dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) + bash utils/install.sh -v 0.13.1 --plugins wasmedge_tensorflowlite + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflowLite.dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) + - name: Latest Release Check run: | - bash utils/uninstall.sh -q -V - - name: Install deprecated WasmEdge specific release (0.10.0) + _res_git_=$(git ls-remote --refs --tags "https://github.com/WasmEdge/WasmEdge.git" | cut -d '/' -f 3 | awk '{ if ($1 ~ /-/) print; else print $0"_" ; }' | sort --version-sort | sed 's/_$//' | grep -e '^[0-9]\+.[0-9]\+.[0-9]\+$' | tail -1) + _res_curl_=$(curl -w "%{url_effective}\n" -I -L -s -S https://github.com/WasmEdge/WasmEdge/releases/latest -o /dev/null | grep -Eo '[0-9]+.[0-9]+.[0-9]+') + [ "$_res_git_" = "$_res_curl_" ] && echo "Pass: Fetched version equals release" || + (echo "Fail: Fetched version does not equal GitHub Ref\nFetched:$_res_git_\nCI:$_res_curl_" && exit 1) + + macos-arm64: + name: macos-arm64 + runs-on: macos-14 + env: + SHELL: zsh + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Install WasmEdge latest release + shell: zsh {0} run: | - bash utils/install.sh -v 0.10.0 -D + bash utils/install.sh -D - name: Uninstall WasmEdge + shell: zsh {0} run: | bash utils/uninstall.sh -q -V - - name: Install WasmEdge specific release (0.10.0) with all extensions - if: ${{ matrix.name != 'MacOS-arm64' }} + - name: Check for bashrc generation + shell: zsh {0} run: | - bash utils/install.sh -e all -v 0.10.0 -D - - name: Uninstall WasmEdge with all extensions - if: ${{ matrix.name != 'MacOS-arm64' }} + rm -f ~/.zshenv + bash utils/install.sh -D + if ls -a ~ | grep .zshenv; then echo "Pass: zshenv found"; else echo "Fail: zshenv not found" && exit 1; fi; + - name: Uninstall WasmEdge + shell: zsh {0} run: | bash utils/uninstall.sh -q -V - - name: Plugins Install check MacOS-x86 - if: ${{ matrix.name != 'MacOS-arm64' }} - run: | - bash utils/install.sh -v 0.10.0-alpha.1 - ls ~/.wasmedge/plugin/ | grep .dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - bash utils/install.sh -v 0.13.1 --plugins wasmedge_tensorflow - ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflow.dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - bash utils/install.sh -v 0.13.1 --plugins wasmedge_tensorflowlite - ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflowLite.dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - bash utils/install.sh -v 0.10.0-alpha.1 -p ~/new_wasmedge - ls ~/new_wasmedge/plugin/ | grep .dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - # MacOS container does not have access for /usr directory - # bash utils/install.sh -v 0.10.0-alpha.1 -p /usr - # ls /usr/lib/wasmedge/ | grep libwasmedgePluginWasmEdgeProcess.dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - - name: Plugins Install check MacOS-arm64 - if: ${{ matrix.name == 'MacOS-arm64' }} + shell: zsh {0} run: | bash utils/install.sh -v 0.13.1 --plugins wasmedge_tensorflow ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflow.dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) bash utils/install.sh -v 0.13.1 --plugins wasmedge_tensorflowlite ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflowLite.dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - - name: Tensorflow changes - libtensorflow_cc 2.6.0 will replace the old libtensorflow 2.6.0 - if: ${{ matrix.name != 'MacOS-arm64' }} - run: | - bash utils/install.sh -v 0.12.0-alpha.2 -e tensorflow --tf-version 0.12.0-alpha.2 --tf-deps-version 0.12.0-alpha.2 --tf-tools-version 0.12.0-alpha.2 - ls ~/.wasmedge/lib/ | grep libtensorflow_cc* && echo "Pass: libtensorflow_cc found" || (echo "Fail: libtensorflow_cc found not found" && exit 1) - name: Uninstall WasmEdge + shell: zsh {0} run: | bash utils/uninstall.sh -q -V - name: Latest Release Check + shell: zsh {0} run: | _res_git_=$(git ls-remote --refs --tags "https://github.com/WasmEdge/WasmEdge.git" | cut -d '/' -f 3 | awk '{ if ($1 ~ /-/) print; else print $0"_" ; }' | sort --version-sort | sed 's/_$//' | grep -e '^[0-9]\+.[0-9]\+.[0-9]\+$' | tail -1) _res_curl_=$(curl -w "%{url_effective}\n" -I -L -s -S https://github.com/WasmEdge/WasmEdge/releases/latest -o /dev/null | grep -Eo '[0-9]+.[0-9]+.[0-9]+') diff --git a/.github/workflows/test-installer-v2.yml b/.github/workflows/test-installer-v2.yml new file mode 100644 index 000000000000..5dcdf0edbdfb --- /dev/null +++ b/.github/workflows/test-installer-v2.yml @@ -0,0 +1,123 @@ +name: test-installer-v2 + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +on: + push: + branches: + - master + paths: + - '.github/workflows/test-installer-v2.yml' + - 'utils/install_v2.sh' + - 'utils/uninstall.sh' + pull_request: + branches: + - master + paths: + - '.github/workflows/test-installer-v2.yml' + - 'utils/install_v2.sh' + - 'utils/uninstall.sh' + +jobs: + verify-installer-v2: + strategy: + fail-fast: false + matrix: + include: + - name: CentOS 9 Stream + host_runner: ubuntu-latest + docker_image: quay.io/centos/centos:stream9 + extra_setup_command: yum update -y && yum install -y which + - name: Ubuntu 20.04 + host_runner: ubuntu-latest + docker_image: ubuntu:20.04 + extra_setup_command: apt update -y && apt install -y curl + name: ${{ matrix.name }} + runs-on: ${{ matrix.host_runner }} + container: + image: ${{ matrix.docker_image }} + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup + run: | + ${{ matrix.extra_setup_command }} + - name: Run installer-v2 + run: | + # It will install WasmEdge and the GGML plugin + bash utils/install_v2.sh -V + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: WASI_NN-ggml Plugin found" || (echo "Fail: WASI_NN-ggml not found" && exit 1) + - name: Re-install installer-v2 + run: | + # It should uninstall the previous installation and install WasmEdge and the GGML plugin again + bash utils/install_v2.sh -V + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: WASI_NN-ggml Plugin found" || (echo "Fail: WASI_NN-ggml not found" && exit 1) + - name: Run installer-v2 with noavx option + if: ${{ matrix.docker_image == 'ubuntu:20.04' }} + run: | + # It will install WasmEdge and the noavx GGML plugin + bash utils/install_v2.sh -V --noavx + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: WASI_NN-ggml Plugin found" || (echo "Fail: WASI_NN-ggml not found" && exit 1) + - name: Run installer-v2 with ggml build number b2963 + run: | + # It will install WasmEdge and the b2963 GGML plugin + bash utils/install_v2.sh -V --ggmlbn=b2963 + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: WASI_NN-ggml Plugin found" || (echo "Fail: WASI_NN-ggml not found" && exit 1) + - name: Run installer-v2 with 0.14.1 rc.1 + run: | + bash utils/install_v2.sh -V --version=0.14.1-rc.1 + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiLogging.so && (echo "Fail: WASI_NN-logging Plugin found" && exit 1) || (echo "Pass: WASI_NN-logging not found" && exit 0) + - name: Uninstall WasmEdge + run: | + bash utils/uninstall.sh -q -V + + macos: + strategy: + fail-fast: false + matrix: + include: + - name: Mac M1 + host_runner: macos-14 + - name: Mac Intel + host_runner: macos-13 + name: ${{ matrix.name }} + runs-on: ${{ matrix.host_runner }} + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install zsh + run: | + eval $(/opt/homebrew/bin/brew shellenv) + brew install zsh + + - name: Run installer-v2 + run: | + # It will install WasmEdge and the GGML plugin + bash utils/install_v2.sh -V + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.dylib && echo "Pass: WASI_NN-ggml Plugin found" || (echo "Fail: WASI_NN-ggml not found" && exit 1) + - name: Re-install installer-v2 + run: | + # It should uninstall the previous installation and install WasmEdge and the GGML plugin again + bash utils/install_v2.sh -V + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.dylib && echo "Pass: WASI_NN-ggml Plugin found" || (echo "Fail: WASI_NN-ggml not found" && exit 1) + - name: Run installer-v2 with ggml build number b2963 + if: ${{ matrix.host_runner == 'macos-14' }} + run: | + # It will install WasmEdge and the b2963 GGML plugin + bash utils/install_v2.sh -V --ggmlbn=b2963 + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.dylib && echo "Pass: WASI_NN-ggml Plugin found" || (echo "Fail: WASI_NN-ggml not found" && exit 1) + - name: Run installer-v2 with 0.14.1 rc.1 + run: | + bash utils/install_v2.sh -V --version=0.14.1-rc.1 + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiLogging.dylib && (echo "Fail: WASI_NN-logging Plugin found" && exit 1) || (echo "Pass: WASI_NN-logging not found" && exit 0) + - name: Uninstall WasmEdge + run: | + bash utils/uninstall.sh -q -V diff --git a/.github/workflows/test-python-install-script.yml b/.github/workflows/test-python-install-script.yml index 38d84779fbde..3596dc463238 100644 --- a/.github/workflows/test-python-install-script.yml +++ b/.github/workflows/test-python-install-script.yml @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Setup Python env - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 - name: Install black run: pip install black @@ -45,14 +45,6 @@ jobs: fail-fast: false matrix: include: - - name: CentOS 8 Stream - host_runner: ubuntu-latest - package_manager: yum - docker_image: quay.io/centos/centos:stream8 - python_package: python3 python2 - python2_ex: python2 - python3_ex: python3 - extra_setup_command: yum install -y diffutils - name: CentOS 7 host_runner: ubuntu-latest package_manager: yum @@ -61,6 +53,7 @@ jobs: python2_ex: python2 python3_ex: python3 extra_setup_command: echo "No extra command" + fix_mirror: "centos7" - name: Ubuntu 20.04 host_runner: ubuntu-latest package_manager: apt @@ -69,6 +62,7 @@ jobs: python2_ex: python2 python3_ex: python3 extra_setup_command: apt update && apt install -y lsb-release + fix_mirror: "" - name: Ubuntu 18.04 host_runner: ubuntu-latest package_manager: apt @@ -77,6 +71,7 @@ jobs: python2_ex: python2.7 python3_ex: python3 extra_setup_command: echo "No extra command" + fix_mirror: "" - name: Ubuntu 16.04 host_runner: ubuntu-latest package_manager: apt @@ -85,24 +80,46 @@ jobs: python2_ex: python2.7 python3_ex: python3.7 extra_setup_command: apt update -y && apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev wget && wget https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz && tar xzf Python-3.7.4.tgz && cd Python-3.7.4 && ./configure && make -j && make install && cd .. + fix_mirror: "" - name: manylinux2014 aarch64 - host_runner: linux-arm64 + host_runner: linux-arm64-v2 package_manager: yum docker_image: wasmedge/wasmedge:manylinux2014_aarch64 python_package: python2 python3 python2_ex: python2 python3_ex: python3 extra_setup_command: echo "No extra command" + fix_mirror: "centos7aarch64" name: ${{ matrix.name }} runs-on: ${{ matrix.host_runner }} container: image: ${{ matrix.docker_image }} + # For older OS like Ubuntu 16 & 18. + env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + steps: - uses: actions/checkout@v3 with: fetch-depth: 0 + - if: ${{ matrix.fix_mirror == 'centos7' }} + name: Fix mirrors on manylinux2014 + # Reference: https://github.com/pypa/manylinux/pull/1628 + run: | + sed -i 's/enabled=1/enabled=0/g' /etc/yum/pluginconf.d/fastestmirror.conf + sed -i 's/^mirrorlist/#mirrorlist/g' /etc/yum.repos.d/*.repo + sed -i 's;^.*baseurl=http://mirror;baseurl=https://vault;g' /etc/yum.repos.d/*.repo + - if: ${{ matrix.fix_mirror == 'centos7aarch64' }} + name: Fix mirrors on manylinux2014 for aarch64 + # Reference: https://github.com/pypa/manylinux/pull/1628 + run: | + sed -i 's/enabled=1/enabled=0/g' /etc/yum/pluginconf.d/fastestmirror.conf + sed -i 's/^mirrorlist/#mirrorlist/g' /etc/yum.repos.d/*.repo + sed -i 's;^.*baseurl=http://mirror;baseurl=https://vault;g' /etc/yum.repos.d/*.repo + sed -i 's;/centos/7/;/altarch/7/;g' /etc/yum.repos.d/*.repo + - name: Install git and curl run: | ${{ matrix.extra_setup_command }} @@ -118,18 +135,11 @@ jobs: - name: Uninstall WasmEdge run: | bash utils/uninstall.sh -q -V - - name: Install WasmEdge latest release with all extensions - run: | - ${{ matrix.python2_ex }} utils/install.py -e all -D - ${{ matrix.python3_ex }} utils/install.py -e all -D - - name: Uninstall WasmEdge with all extensions - run: | - bash utils/uninstall.sh -q -V - - name: Install WasmEdge specific release (0.10.0) + - name: Install WasmEdge specific release (0.13.0) if: ${{ matrix.name != 'manylinux2014 aarch64' }} run: | - ${{ matrix.python2_ex }} utils/install.py -v 0.10.0 -D - ${{ matrix.python3_ex }} utils/install.py -v 0.10.0 -D + ${{ matrix.python2_ex }} utils/install.py -v 0.13.0 -D + ${{ matrix.python3_ex }} utils/install.py -v 0.13.0 -D - name: Uninstall WasmEdge if: ${{ matrix.name != 'manylinux2014 aarch64' }} run: | @@ -137,31 +147,11 @@ jobs: - name: Install WasmEdge deprecated release (0.9.0) - Fail purposefully if: ${{ matrix.name != 'manylinux2014 aarch64' }} run: | - ${{ matrix.python2_ex }} utils/install.py -v 0.9.0 -D 2>&1 | grep -q "Version not supported. Min Version: 0.10.0" && echo "Pass: Version not supported. Min Version: 0.10.0 found" \ - || (echo "Failed: Version not supported. Min Version: 0.10.0 not found" && exit 1) - ${{ matrix.python3_ex }} utils/install.py -v 0.9.0 -D 2>&1 | grep -q "Version not supported. Min Version: 0.10.0" && echo "Pass: Version not supported. Min Version: 0.10.0 found" \ - || (echo "Failed: Version not supported. Min Version: 0.10.0 not found" && exit 1) - - name: Install WasmEdge specific release (0.10.0) with all extensions - if: ${{ matrix.name != 'manylinux2014 aarch64' }} - run: | - ${{ matrix.python2_ex }} utils/install.py -e all -v 0.10.0 -D - ${{ matrix.python3_ex }} utils/install.py -e all -v 0.10.0 -D - - name: Install WasmEdge with all extensions compatible with min version for all platforms - run: | - ${{ matrix.python2_ex }} utils/install.py -e all --version=0.10.1-alpha.1 -D - ${{ matrix.python3_ex }} utils/install.py -e all --version=0.10.1-alpha.1 -D - - name: Uninstall WasmEdge with all extensions - run: | - bash utils/uninstall.sh -q -V - - name: Install versions multiple times - run: | - ${{ matrix.python2_ex }} utils/install.py -e all -D - ${{ matrix.python2_ex }} utils/install.py -e all -v 0.10.1-alpha.1 -D - ${{ matrix.python2_ex }} utils/install.py -e all -v 0.10.0 -D - ${{ matrix.python3_ex }} utils/install.py -e all -D - - name: Uninstall WasmEdge - run: | - bash utils/uninstall.sh -q -V + ${{ matrix.python2_ex }} utils/install.py -v 0.9.0 -D 2>&1 | grep -q "Version not supported. Min Version: 0.13.0" && echo "Pass: Version not supported. Min Version: 0.13.0 found" \ + || (echo "Failed: Version not supported. Min Version: 0.13.0 not found" && exit 1) + ${{ matrix.python3_ex }} utils/install.py -v 0.9.0 -D 2>&1 | grep -q "Version not supported. Min Version: 0.13.0" && echo "Pass: Version not supported. Min Version: 0.13.0 found" \ + || (echo "Failed: Version not supported. Min Version: 0.13.0 not found" && exit 1) + - name: Uninstall WasmEdge and Source Line removal check run: | ${{ matrix.python2_ex }} utils/install.py && bash utils/uninstall.sh -q @@ -176,51 +166,64 @@ jobs: - name: Plugins Install check run: | - ${{ matrix.python2_ex }} utils/install.py -v 0.10.0-alpha.1 - ls ~/.wasmedge/plugin/ | grep .so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) ${{ matrix.python2_ex }} utils/install.py -v 0.13.0 --plugins wasmedge_tensorflowlite ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflowLite.so && echo "Pass: Plugins found" || (echo "Fail: Wasmedge Tensorflowlite Plugin not found" && exit 1) ${{ matrix.python2_ex }} utils/install.py -v 0.13.0 --plugins wasmedge_tensorflow ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflow.so && echo "Pass: Plugins found" || (echo "Fail: Wasmedge Tensorflowlite Plugin not found" && exit 1) - ${{ matrix.python2_ex }} utils/install.py -v 0.10.0-alpha.1 -p ~/new_wasmedge - ls ~/new_wasmedge/plugin/ | grep .so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - ${{ matrix.python2_ex }} utils/install.py -v 0.10.0-alpha.1 -p /usr - ls /usr/lib/wasmedge/ | grep libwasmedgePluginWasmEdgeProcess.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - ${{ matrix.python3_ex }} utils/install.py -v 0.10.0-alpha.1 - ls ~/.wasmedge/plugin/ | grep .so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) ${{ matrix.python3_ex }} utils/install.py -v 0.13.0 --plugins wasmedge_tensorflowlite ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflowLite.so && echo "Pass: Plugins found" || (echo "Fail: Wasmedge Tensorflowlite Plugin not found" && exit 1) ${{ matrix.python3_ex }} utils/install.py -v 0.13.0 --plugins wasmedge_tensorflow ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflow.so && echo "Pass: Plugins found" || (echo "Fail: Wasmedge Tensorflowlite Plugin not found" && exit 1) - ${{ matrix.python3_ex }} utils/install.py -v 0.10.0-alpha.1 -p ~/new_wasmedge - ls ~/new_wasmedge/plugin/ | grep .so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - ${{ matrix.python3_ex }} utils/install.py -v 0.10.0-alpha.1 -p /usr - ls /usr/lib/wasmedge/ | grep libwasmedgePluginWasmEdgeProcess.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) + + - name: Plugin install test - WasmEdge WASI-NN-GGML + run: | + # Without the build number + ${{ matrix.python2_ex }} utils/install.py -v 0.13.5 --plugins wasi_nn-ggml + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: Plugins found" || (echo "Fail: Wasmedge WASI-NN GGML Plugin not found" && exit 1) + + ${{ matrix.python3_ex }} utils/install.py -v 0.13.5 --plugins wasi_nn-ggml + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: Plugins found" || (echo "Fail: Wasmedge WASI-NN GGML Plugin not found" && exit 1) + + # With the build number + ${{ matrix.python2_ex }} utils/install.py -v 0.13.5 --plugins wasi_nn-ggml-b3075 + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: Plugins found" || (echo "Fail: Wasmedge WASI-NN GGML Plugin not found" && exit 1) + + ${{ matrix.python3_ex }} utils/install.py -v 0.13.5 --plugins wasi_nn-ggml-b3075 + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: Plugins found" || (echo "Fail: Wasmedge WASI-NN GGML Plugin not found" && exit 1) + - name: Plugin install test - WasmEdge WASI-NN-GGML-noavx + if: ${{ matrix.name == 'Ubuntu 20.04' }} + run: | + # Without the build number + ${{ matrix.python2_ex }} utils/install.py -v 0.13.5 --plugins wasi_nn-ggml-noavx + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: Plugins found" || (echo "Fail: Wasmedge WASI-NN GGML Plugin not found" && exit 1) + + ${{ matrix.python3_ex }} utils/install.py -v 0.13.5 --plugins wasi_nn-ggml-noavx + ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: Plugins found" || (echo "Fail: Wasmedge WASI-NN GGML Plugin not found" && exit 1) - name: Plugin install test - WasmEdge rustls if: ${{ matrix.name != 'manylinux2014 aarch64' }} run: | - ${{ matrix.python2_ex }} utils/install.py -v 0.13.4 --plugins wasmedge_rustls + ${{ matrix.python2_ex }} utils/install.py -v 0.13.5 --plugins wasmedge_rustls ls ~/.wasmedge/plugin/ | grep libwasmedge_rustls.so && echo "Pass: Plugins found" || (echo "Fail: Wasmedge Rustls Plugin not found" && exit 1) - ${{ matrix.python3_ex }} utils/install.py -v 0.13.4 --plugins wasmedge_rustls + ${{ matrix.python3_ex }} utils/install.py -v 0.13.5 --plugins wasmedge_rustls ls ~/.wasmedge/plugin/ | grep libwasmedge_rustls.so && echo "Pass: Plugins found" || (echo "Fail: Wasmedge Rustls Plugin not found" && exit 1) - name: Externally Specified plugin install check (single)(Ubuntu) if: ${{ matrix.name == 'Ubuntu 20.04' }} run: | # Single plugin download - ${{ matrix.python2_ex }} utils/install.py -v 0.10.1-alpha.1 --plugins wasi_nn-openvino -D + ${{ matrix.python2_ex }} utils/install.py -v 0.13.0 --plugins wasi_nn-openvino -D ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - ${{ matrix.python2_ex }} utils/install.py -v 0.10.1-alpha.1 -p ~/new_wasmedge --plugins wasi_nn-openvino -D + ${{ matrix.python2_ex }} utils/install.py -v 0.13.0 -p ~/new_wasmedge --plugins wasi_nn-openvino -D ls ~/new_wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - ${{ matrix.python2_ex }} utils/install.py -v 0.10.1-alpha.1 -p /usr --plugins wasi_nn-openvino -D + ${{ matrix.python2_ex }} utils/install.py -v 0.13.0 -p /usr --plugins wasi_nn-openvino -D (ls /usr/lib/wasmedge/; ls /usr/lib/wasmedge/;)2>&1 | grep libwasmedgePluginWasiNN.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - ${{ matrix.python3_ex }} utils/install.py -v 0.10.1-alpha.1 --plugins wasi_nn-openvino -D + ${{ matrix.python3_ex }} utils/install.py -v 0.13.0 --plugins wasi_nn-openvino -D ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - ${{ matrix.python3_ex }} utils/install.py -v 0.10.1-alpha.1 -p ~/new_wasmedge --plugins wasi_nn-openvino -D + ${{ matrix.python3_ex }} utils/install.py -v 0.13.0 -p ~/new_wasmedge --plugins wasi_nn-openvino -D ls ~/new_wasmedge/plugin/ | grep libwasmedgePluginWasiNN.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - ${{ matrix.python3_ex }} utils/install.py -v 0.10.1-alpha.1 -p /usr --plugins wasi_nn-openvino -D + ${{ matrix.python3_ex }} utils/install.py -v 0.13.0 -p /usr --plugins wasi_nn-openvino -D (ls /usr/lib/wasmedge/; ls /usr/lib/wasmedge/;)2>&1 | grep libwasmedgePluginWasiNN.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - name: Externally Specified plugin install check (single)(Ubuntu) - WASI-NN GGML (>= 0.13.4) @@ -250,71 +253,24 @@ jobs: ${{ matrix.python3_ex }} utils/install.py --plugins unknown_plugin_name_on_purpose -D (ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiCrypto.so && echo "Fail: Plugins found" && exit 1) || (echo "Pass: Plugins not found") - - name: Check if distro-specific downloads are selected(Ubuntu) - if: ${{ matrix.name == 'Ubuntu 20.04' }} - run: | - ${{ matrix.python2_ex }} utils/install.py -e tensorflow -D 2>&1 | grep -q "DEBUG - Downloading dist package: ubuntu20.04_x86_64.tar.gz" && echo "Pass: Ubuntu Package selected for tensorflow" || (echo "Fail: Ubuntu Package not selected for tensorflow" && exit 1) - ${{ matrix.python3_ex }} utils/install.py -e tensorflow -D 2>&1 | grep -q "DEBUG - Downloading dist package: ubuntu20.04_x86_64.tar.gz" && echo "Pass: Ubuntu Package selected for tensorflow" || (echo "Fail: Ubuntu Package not selected for tensorflow" && exit 1) - ${{ matrix.python2_ex }} utils/install.py -e image -D -v 0.12.0 2>&1 | grep -q "DEBUG - Downloading dist package: ubuntu20.04_x86_64.tar.gz" && echo "Pass: Ubuntu Package selected for image" || (echo "Fail: Ubuntu Package not selected for image" && exit 1) - ${{ matrix.python3_ex }} utils/install.py -e image -D -v 0.12.0 2>&1 | grep -q "DEBUG - Downloading dist package: ubuntu20.04_x86_64.tar.gz" && echo "Pass: Ubuntu Package selected for image" || (echo "Fail: Ubuntu Package not selected for image" && exit 1) - - - - name: Check if distro-specific downloads are selected(Non-Ubuntu) - if: ${{ matrix.name != 'Ubuntu 20.04' }} - run: | - ${{ matrix.python2_ex }} utils/install.py -e tensorflow -D 2>&1 | grep -q "DEBUG - Downloading dist package: ubuntu20.04_x86_64.tar.gz" && (echo "Fail: Ubuntu Package selected for tensorflow" && exit 1) || (echo "Pass: Ubuntu Package not selected for tensorflow") - ${{ matrix.python3_ex }} utils/install.py -e tensorflow -D 2>&1 | grep -q "DEBUG - Downloading dist package: ubuntu20.04_x86_64.tar.gz" && (echo "Fail: Ubuntu Package selected for tensorflow" && exit 1) || (echo "Pass: Ubuntu Package not selected for tensorflow") - ${{ matrix.python2_ex }} utils/install.py -e image -D -v 0.12.0 2>&1 | grep -q "DEBUG - Downloading dist package: ubuntu20.04_x86_64.tar.gz" && (echo "Fail: Ubuntu Package selected for image" && exit 1) || (echo "Pass: Ubuntu Package not selected for image") - ${{ matrix.python3_ex }} utils/install.py -e image -D -v 0.12.0 2>&1 | grep -q "DEBUG - Downloading dist package: ubuntu20.04_x86_64.tar.gz" && (echo "Fail: Ubuntu Package selected for image" && exit 1) || (echo "Pass: Ubuntu Package not selected for image") - - name: Externally Specified plugin install check (single)(Non Ubuntu) if: ${{ matrix.name != 'manylinux2014 aarch64' }} run: | # Single plugin download - ${{ matrix.python2_ex }} utils/install.py -v 0.10.1-rc.1 --plugins wasi_crypto -D + ${{ matrix.python2_ex }} utils/install.py -v 0.13.0 --plugins wasi_crypto -D ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiCrypto.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - ${{ matrix.python2_ex }} utils/install.py -v 0.10.1-rc.1 -p ~/new_wasmedge --plugins wasi_crypto -D + ${{ matrix.python2_ex }} utils/install.py -v 0.13.0 -p ~/new_wasmedge --plugins wasi_crypto -D ls ~/new_wasmedge/plugin/ | grep libwasmedgePluginWasiCrypto.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - ${{ matrix.python2_ex }} utils/install.py -v 0.10.1-rc.1 -p /usr --plugins wasi_crypto -D + ${{ matrix.python2_ex }} utils/install.py -v 0.13.0 -p /usr --plugins wasi_crypto -D (ls /usr/lib/wasmedge/; ls /usr/lib/wasmedge/;)2>&1 | grep libwasmedgePluginWasiCrypto.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - ${{ matrix.python3_ex }} utils/install.py -v 0.10.1-rc.1 --plugins wasi_crypto -D + ${{ matrix.python3_ex }} utils/install.py -v 0.13.0 --plugins wasi_crypto -D ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasiCrypto.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - ${{ matrix.python3_ex }} utils/install.py -v 0.10.1-rc.1 -p ~/new_wasmedge --plugins wasi_crypto -D + ${{ matrix.python3_ex }} utils/install.py -v 0.13.0 -p ~/new_wasmedge --plugins wasi_crypto -D ls ~/new_wasmedge/plugin/ | grep libwasmedgePluginWasiCrypto.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - ${{ matrix.python3_ex }} utils/install.py -v 0.10.1-rc.1 -p /usr --plugins wasi_crypto -D + ${{ matrix.python3_ex }} utils/install.py -v 0.13.0 -p /usr --plugins wasi_crypto -D (ls /usr/lib/wasmedge/; ls /usr/lib/wasmedge/;)2>&1 | grep libwasmedgePluginWasiCrypto.so && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - - name: Install multiple versions and Tensorflow extension/plugins for pre and post 0.13.x - run: | - ${{ matrix.python3_ex }} utils/install.py -e tensorflow -D 2>&1 -v 0.12.0 - ${{ matrix.python3_ex }} utils/install.py -e tensorflow -D 2>&1 -v 0.13.0 - ${{ matrix.python3_ex }} utils/install.py -e tensorflow -D 2>&1 - ${{ matrix.python2_ex }} utils/install.py -e tensorflow -D 2>&1 -v 0.12.0 - ${{ matrix.python2_ex }} utils/install.py -e tensorflow -D 2>&1 -v 0.13.0 - ${{ matrix.python2_ex }} utils/install.py -e tensorflow -D 2>&1 - - - name: Install multiple versions and Image extension/plugins for pre and post 0.13.x - run: | - ${{ matrix.python3_ex }} utils/install.py -e image -D 2>&1 -v 0.12.0 - ${{ matrix.python3_ex }} utils/install.py -e image -D 2>&1 -v 0.13.0 - ${{ matrix.python3_ex }} utils/install.py -e image -D 2>&1 - ${{ matrix.python2_ex }} utils/install.py -e image -D 2>&1 -v 0.12.0 - ${{ matrix.python2_ex }} utils/install.py -e image -D 2>&1 -v 0.13.0 - ${{ matrix.python2_ex }} utils/install.py -e image -D 2>&1 - - - name: Check for differences in the installation - run: | - PYTHON_EXECUTABLE=${{ matrix.python3_ex }} bash utils/installer_changes.sh "$HOME"/.wasmedge - PYTHON_EXECUTABLE=${{ matrix.python3_ex }} bash utils/installer_changes.sh "$HOME"/new_folder - PYTHON_EXECUTABLE=${{ matrix.python3_ex }} bash utils/installer_changes.sh /usr/local - PYTHON_EXECUTABLE=${{ matrix.python3_ex }} bash utils/installer_changes.sh /usr - - PYTHON_EXECUTABLE=${{ matrix.python3_ex }} bash utils/installer_changes.sh "$HOME"/.wasmedge "-e all" "-v 0.12.1" - PYTHON_EXECUTABLE=${{ matrix.python3_ex }} bash utils/installer_changes.sh "$HOME"/new_folder "-e all" "-v 0.12.1" - PYTHON_EXECUTABLE=${{ matrix.python3_ex }} bash utils/installer_changes.sh /usr/local "-e all" "-v 0.12.1" - PYTHON_EXECUTABLE=${{ matrix.python3_ex }} bash utils/installer_changes.sh /usr "-e all" "-v 0.12.1" - - name: Latest Release Check run: | _res_git_=$(git ls-remote --refs --tags "https://github.com/WasmEdge/WasmEdge.git" | cut -d '/' -f 3 | awk '{ if ($1 ~ /-/) print; else print $0"_" ; }' | sort --version-sort | sed 's/_$//' | grep -e '^[0-9]\+.[0-9]\+.[0-9]\+$' | tail -1) @@ -328,8 +284,8 @@ jobs: fail-fast: false matrix: include: - - name: MacOS-latest - host_runner: macos-latest + - name: MacOS-amd64 + host_runner: macos-13 package_manager: brew - name: MacOS-arm64 host_runner: macos-14 @@ -343,115 +299,58 @@ jobs: fetch-depth: 0 - name: Install python + shell: zsh {0} run: | eval $(/opt/homebrew/bin/brew shellenv) - ${{ matrix.package_manager }} install python + ${{ matrix.package_manager }} upgrade + ${{ matrix.package_manager }} install python zsh - name: Install WasmEdge latest release + shell: zsh {0} run: | python3 utils/install.py -D - name: Uninstall WasmEdge + shell: zsh {0} run: | bash utils/uninstall.sh -q -V - - name: Install WasmEdge latest release with all extensions - if: ${{ matrix.name != 'MacOS-arm64' }} - run: | - python3 utils/install.py -e all -D - - name: Uninstall WasmEdge with all extensions - if: ${{ matrix.name != 'MacOS-arm64' }} + - name: Install WasmEdge specific release (0.13.0) + shell: zsh {0} run: | - bash utils/uninstall.sh -q -V - - name: Install WasmEdge specific release (0.10.0) - run: | - python3 utils/install.py -v 0.10.0 -D + python3 utils/install.py -v 0.13.0 -D - name: Uninstall WasmEdge + shell: zsh {0} run: | bash utils/uninstall.sh -q -V - name: Install WasmEdge deprecated release (0.9.0) - Fails purposefully + shell: zsh {0} run: | - python3 utils/install.py -v 0.9.0 -D 2>&1 | grep -q "Version not supported. Min Version: 0.10.0" && echo "Pass: Version not supported. Min Version: 0.10.0 found" \ - || (echo "Failed: Version not supported. Min Version: 0.10.0 message not found" && exit 1) - - name: Install WasmEdge specific release (0.10.0) with all extensions - if: ${{ matrix.name != 'MacOS-arm64' }} - run: | - python3 utils/install.py -e all -v 0.10.0 -D - - name: Uninstall WasmEdge with all extensions - if: ${{ matrix.name != 'MacOS-arm64' }} - run: | - bash utils/uninstall.sh -q -V - - name: Plugins Install check MacOS-x86 - if: ${{ matrix.name != 'MacOS-arm64' }} - run: | - python3 utils/install.py -v 0.10.0-alpha.1 - ls ~/.wasmedge/plugin/ | grep .dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - python3 utils/install.py -v 0.13.1 --plugins wasmedge_tensorflow - ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflow.dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - python3 utils/install.py -v 0.13.1 --plugins wasmedge_tensorflowlite - ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflowLite.dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - python3 utils/install.py -v 0.13.4 --plugins wasmedge_rustls - ls ~/.wasmedge/plugin/ | grep libwasmedge_rustls.dylib && echo "Pass: Plugins found" || (echo "Fail: Wasmedge Rustls Plugin not found" && exit 1) - python3 utils/install.py -v 0.10.0-alpha.1 -p ~/new_wasmedge - ls ~/new_wasmedge/plugin/ | grep .dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - # MacOS container does not have access for /usr directory - # python3 utils/install.py -v 0.10.0-alpha.1 -p /usr - # ls /usr/lib/wasmedge/ | grep libwasmedgePluginWasmEdgeProcess.dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - - - name: Plugins Install check MacOS-arm64 + python3 utils/install.py -v 0.9.0 -D 2>&1 | grep -q "Version not supported. Min Version: 0.13.0" && echo "Pass: Version not supported. Min Version: 0.13.0 found" \ + || (echo "Failed: Version not supported. Min Version: 0.13.0 message not found" && exit 1) + - name: Plugins Install check MacOS + shell: zsh {0} if: ${{ matrix.name == 'MacOS-arm64' }} run: | python3 utils/install.py -v 0.13.1 --plugins wasmedge_tensorflow ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflow.dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) python3 utils/install.py -v 0.13.1 --plugins wasmedge_tensorflowlite ls ~/.wasmedge/plugin/ | grep libwasmedgePluginWasmEdgeTensorflowLite.dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - python3 utils/install.py -v 0.13.4 --plugins wasmedge_rustls + python3 utils/install.py -v 0.13.5 --plugins wasmedge_rustls ls ~/.wasmedge/plugin/ | grep libwasmedge_rustls.dylib && echo "Pass: Plugins found" || (echo "Fail: Wasmedge Rustls Plugin not found" && exit 1) - name: Install multiple versions and Tensorflow extension/plugins for pre and post 0.13.x - if: ${{ matrix.name != 'MacOS-arm64' }} + shell: zsh {0} run: | - python3 utils/install.py -e tensorflow -D 2>&1 -v 0.12.0 python3 utils/install.py --plugins wasmedge_tensorflow -D 2>&1 -v 0.13.1 python3 utils/install.py --plugins wasmedge_tensorflow -D 2>&1 - - name: Install multiple versions and Tensorflow extension/plugins for pre and post 0.13.x - if: ${{ matrix.name == 'MacOS-arm64' }} - run: | - python3 utils/install.py --plugins wasmedge_tensorflow -D 2>&1 -v 0.13.1 - python3 utils/install.py --plugins wasmedge_tensorflow -D 2>&1 - - - name: Install multiple versions and Image extension/plugins for pre and post 0.13.x - if: ${{ matrix.name != 'MacOS-arm64' }} - run: | - python3 utils/install.py -e image -D 2>&1 -v 0.12.0 - python3 utils/install.py --plugins wasmedge_image -D 2>&1 -v 0.13.1 - python3 utils/install.py --plugins wasmedge_image -D 2>&1 - - name: Install multiple versions and Image extension/plugins for pre and post 0.13.x - if: ${{ matrix.name == 'MacOS-arm64' }} + shell: zsh {0} run: | python3 utils/install.py --plugins wasmedge_image -D 2>&1 -v 0.13.1 python3 utils/install.py --plugins wasmedge_image -D 2>&1 - - name: Check for differences in the installation - if: ${{ matrix.name == 'MacOS-arm64' }} - run: | - bash utils/installer_changes.sh $HOME/.wasmedge - bash utils/installer_changes.sh $HOME/new_folder - - - name: Check for differences in the installation - if: ${{ matrix.name != 'MacOS-arm64' }} - run: | - PYTHON_EXECUTABLE=python3 bash utils/installer_changes.sh "$HOME"/.wasmedge - PYTHON_EXECUTABLE=python3 bash utils/installer_changes.sh "$HOME"/new_folder - PYTHON_EXECUTABLE=python3 bash utils/installer_changes.sh /usr/local - PYTHON_EXECUTABLE=python3 bash utils/installer_changes.sh /usr - - PYTHON_EXECUTABLE=python3 bash utils/installer_changes.sh "$HOME"/.wasmedge "-e all" "-v 0.12.1" - PYTHON_EXECUTABLE=python3 bash utils/installer_changes.sh "$HOME"/new_folder "-e all" "-v 0.12.1" - PYTHON_EXECUTABLE=python3 bash utils/installer_changes.sh /usr/local "-e all" "-v 0.12.1" - PYTHON_EXECUTABLE=python3 bash utils/installer_changes.sh /usr "-e all" "-v 0.12.1" - - name: Latest Release Check + shell: zsh {0} run: | _res_git_=$(git ls-remote --refs --tags "https://github.com/WasmEdge/WasmEdge.git" | cut -d '/' -f 3 | awk '{ if ($1 ~ /-/) print; else print $0"_" ; }' | sort --version-sort | sed 's/_$//' | grep -e '^[0-9]\+.[0-9]\+.[0-9]\+$' | tail -1) _res_curl_=$(curl -w "%{url_effective}\n" -I -L -s -S https://github.com/WasmEdge/WasmEdge/releases/latest -o /dev/null | grep -Eo '[0-9]+.[0-9]+.[0-9]+') diff --git a/.github/workflows/wasi-testsuite.yml b/.github/workflows/wasi-testsuite.yml index 7becc15cce3e..21eeda14aff0 100644 --- a/.github/workflows/wasi-testsuite.yml +++ b/.github/workflows/wasi-testsuite.yml @@ -22,6 +22,9 @@ on: - "include/host/wasi/**" - "thirdparty/wasi/**" +permissions: + contents: read + jobs: test: permissions: @@ -29,10 +32,10 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-2022] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: path: WasmEdge - name: Ensure git safe directory @@ -44,7 +47,7 @@ jobs: working-directory: WasmEdge run: | sudo apt install -y software-properties-common cmake clang ninja-build - cmake -Bbuild -GNinja -DWASMEDGE_BUILD_AOT_RUNTIME=OFF . + cmake -Bbuild -GNinja -DWASMEDGE_USE_LLVM=OFF . cmake --build build echo "$GITHUB_WORKSPACE/WasmEdge/build/tools/wasmedge" >> $GITHUB_PATH @@ -56,19 +59,51 @@ jobs: export LLVM_DIR="/usr/local/opt/llvm/lib/cmake" export CC=clang export CXX=clang++ - cmake -Bbuild -GNinja -DWASMEDGE_BUILD_AOT_RUNTIME=OFF . + cmake -Bbuild -GNinja -DWASMEDGE_USE_LLVM=OFF . cmake --build build echo "$GITHUB_WORKSPACE/WasmEdge/build/tools/wasmedge" >> $GITHUB_PATH + - name: Install dependency on Windows + if: matrix.os == 'windows-2022' + uses: crazy-max/ghaction-chocolatey@v3 + with: + args: install cmake ninja + - name: Upgrade dependency on Windows + if: matrix.os == 'windows-2022' + uses: crazy-max/ghaction-chocolatey@v3 + with: + args: upgrade llvm + - name: Install Windows SDK + if: matrix.os == 'windows-2022' + uses: GuillaumeFalourd/setup-windows10-sdk-action@v2 + with: + sdk-version: 22621 + - name: Build WasmEdge on Windows + if: matrix.os == 'windows-2022' + working-directory: WasmEdge + run: | + $uri = "https://github.com/WasmEdge/llvm-windows/releases/download/llvmorg-17.0.6/LLVM-17.0.6-win64-MultiThreadedDLL.zip" + $llvm = "LLVM-17.0.6-win64-MultiThreadedDLL.zip" + Invoke-WebRequest -Uri "$uri" -HttpVersion 2.0 -OutFile "$llvm" + Expand-Archive -Path $llvm + $Env:CC = "$pwd\\LLVM-17.0.6-win64-MultiThreadedDLL\\LLVM-17.0.6-win64\\bin\\clang-cl.exe" + $Env:CXX = "$pwd\\LLVM-17.0.6-win64-MultiThreadedDLL\\LLVM-17.0.6-win64\\bin\\clang-cl.exe" + $llvm_mt = "$Env:ProgramFiles\\LLVM\\bin\\llvm-mt.exe" + $cmake_sys_version = "10.0.22621.0" + cmake -Bbuild -GNinja "-DCMAKE_SYSTEM_VERSION=$cmake_sys_version" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL -DCMAKE_MT="$llvm_mt" -DWASMEDGE_USE_LLVM=OFF . + cmake --build build + echo "$Env:GITHUB_WORKSPACE\\WasmEdge\\build\\tools\\wasmedge" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append + echo "$Env:GITHUB_WORKSPACE\\WasmEdge\\build\\lib\\api" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append + - name: Checkout wasi-testsuite - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: WebAssembly/wasi-testsuite ref: prod/testsuite-base path: wasi-testsuite - name: Initialize Python environment - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.10' cache: pip diff --git a/.github/workflows/winget-submit.yml b/.github/workflows/winget-submit.yml index 842ae4dbcaa7..92a16c4b54b1 100644 --- a/.github/workflows/winget-submit.yml +++ b/.github/workflows/winget-submit.yml @@ -5,10 +5,12 @@ on: release: types: [published] +permissions: + contents: read + jobs: winget: permissions: - contents: read packages: write name: Publish WinGet Package runs-on: windows-latest diff --git a/.gitignore b/.gitignore index cd8f884f5659..c39b54a71e69 100644 --- a/.gitignore +++ b/.gitignore @@ -75,9 +75,6 @@ docs/_build .direnv .envrc -# mdbook build -docs/book/*/book - bindings/rust/wasmedge-sys/examples/.ipynb_checkpoints/* .DS_Store diff --git a/.gitvote.yml b/.gitvote.yml new file mode 100644 index 000000000000..ae4d9200ef5e --- /dev/null +++ b/.gitvote.yml @@ -0,0 +1,108 @@ +# GitVote configuration file +# +automation: + enabled: false + rules: + - patterns: [] + profile: default + +profiles: + default: + # Voting duration (required) + # + # How long the vote will be open + # + # Units supported (can be combined as in 1hour 30mins): + # + # minutes | minute | mins | min | m + # hours | hour | hrs | hrs | h + # days | day | d + # weeks | week | w + # + duration: 5d + + # Pass threshold (required) + # + # Percentage of votes in favor required to pass the vote + # + # The percentage is calculated based on the number of votes in favor and the + # number of allowed voters (see allowed_voters field below for more details). + pass_threshold: 75 + + # Allowed voters (optional) + # + # List of GitHub teams and users who have binding votes + # + # If no teams or users are provided, all repository collaborators will be + # allowed to vote. For organization-owned repositories, the list of + # collaborators includes outside collaborators, organization members that + # are direct collaborators, organization members with access through team + # memberships, organization members with access through default organization + # permissions, and organization owners. + # + # By default, teams' members with the maintainer role are allowed to vote + # as well. By using the `exclude_team_maintainers` option, it's possible to + # modify this behavior so that only teams' members with the member role are + # considered allowed voters. Please note that this option only applies to + # the teams explicitly listed in `allowed_voters/teams`. + # + # Teams names must be provided without the organization prefix. + # + # allowed_voters: + # teams: + # - team1 + # users: + # - cynthia-sg + # - tegioz + # exclude_team_maintainers: false + # + # We grant the voters to the existing WasmEdge maintainers. + allowed_voters: + teams: [] + users: + - hydai + - ibmibmibm + - q82419 + - juntao + + # Periodic status check + # + # GitVote allows checking the status of a vote in progress manually by + # calling the /check-vote command. The periodic status check option makes + # it possible to automate the execution of status checks periodically. The + # vote status will be published to the corresponding issue or pull request, + # the same way as if the /check-vote command would have been called + # manually. + # + # When this option is enabled, while the vote is open, a status check will + # be run automatically using the frequency configured. Please note that the + # hard limit of one status check per day still applies, so if the command + # has been called manually the automatic periodic run may be delayed. + # Automatic status checks won't be run if the vote will be closed within + # the next hour. + # + # Units supported: + # + # - day / days + # - week / weeks + # + # As an example, using a value of "5 days" would mean that 5 days after the + # vote was created, and every 5 days after that, an automatic status check + # will be run. + # + # periodic_status_check: "5 days" + # + periodic_status_check: "5 days" + + # Close on passing + # + # By default, votes remain open for the configured duration. Sometimes, + # specially on votes that stay open for a long time, it may be preferable + # to close a vote automatically once the passing threshold has been met. + # The close on passing feature makes this possible. Open votes where this + # feature has been enabled will be checked once daily and, if GitVote + # detects that the vote has passed, it will automatically close it. + # + # close_on_passing: true + # + close_on_passing: false diff --git a/CMakeLists.txt b/CMakeLists.txt index 96257ea564b8..fc9438e738ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0091 NEW) @@ -7,51 +7,65 @@ if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") cmake_policy(SET CMP0135 NEW) endif() +set(HUNTER_CACHE_SERVERS + "https://github.com/qdrvm/hunter-binary-cache" + CACHE STRING "Binary cache server" +) + include(cmake/HunterGate.cmake) HunterGate( - URL https://github.com/qdrvm/hunter/archive/b6c44ccfd5d9d0e87628737303084b4cfa9e200e.zip - SHA1 cecd3a154449c1b39fcf5dfaf1bed2c6bce0f67a + URL https://github.com/qdrvm/hunter/archive/refs/tags/v0.25.3-qdrvm14.zip + SHA1 6fc0eb2ab6b85cec6f43d247eb43c0ab0ecdaa65 LOCAL ) -project(WasmEdge) +project(WasmEdge LANGUAGES CXX C) + +# CMake build type. +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RelWithDebInfo) +endif() # Overwrite it if you want to use static MSVC runtime library. set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") +# WasmEdge CAPI and so versions. set(WASMEDGE_CAPI_VERSION "0.1.0" CACHE STRING "WasmEdge C API library version") set(WASMEDGE_CAPI_SOVERSION "0" CACHE STRING "WasmEdge C API library soversion") set(WASMEDGE_WASI_NN_VERSION "0.1.0" CACHE STRING "WasmEdge WASI-NN library version") set(WASMEDGE_WASI_NN_SOVERSION "0" CACHE STRING "WasmEdge WASI-NN library soversion") +# Set cpack package version. find_program(GIT_CMD git) -execute_process(COMMAND - ${GIT_CMD} describe --match "[0-9].[0-9]*" --tag - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_VARIABLE CPACK_PACKAGE_VERSION - RESULT_VARIABLE GIT_VERSION_NOT_FOUND - OUTPUT_STRIP_TRAILING_WHITESPACE -) - +# Assuming the git command is not found and .git folder is not available. +set(GIT_VERSION_NOT_FOUND 1) +if(GIT_CMD AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") + execute_process(COMMAND + ${GIT_CMD} describe --match "[0-9].[0-9]*" --tag + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE CPACK_PACKAGE_VERSION + RESULT_VARIABLE GIT_VERSION_NOT_FOUND + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endif() if(GIT_VERSION_NOT_FOUND AND NOT GIT_VERSION_NOT_FOUND EQUAL 0) set(CPACK_PACKAGE_VERSION "0.0.0-unreleased") endif() -# Overwrite version information once there is a VERSION file +# Overwrite version information once there is a VERSION file. if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION") file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" LOCAL_VERSION) set(CPACK_PACKAGE_VERSION ${LOCAL_VERSION}) unset(LOCAL_VERSION) endif() +# Add the CMake module path. list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE RelWithDebInfo) -endif() -include(FetchContent) +# Export compile commands. +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +# Find threads and filesystem. set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Filesystem REQUIRED Final Experimental) find_package(Threads REQUIRED) @@ -59,35 +73,68 @@ find_package(Threads REQUIRED) # List of WasmEdge options option(WASMEDGE_BUILD_TESTS "Generate build targets for the wasmedge unit tests." OFF) option(WASMEDGE_BUILD_COVERAGE "Generate coverage report. Require WASMEDGE_BUILD_TESTS." OFF) -option(WASMEDGE_BUILD_AOT_RUNTIME "Enable WasmEdge LLVM-based ahead of time compilation runtime." ON) option(WASMEDGE_BUILD_SHARED_LIB "Generate the WasmEdge shared library." ON) option(WASMEDGE_BUILD_STATIC_LIB "Generate the WasmEdge static library." OFF) option(WASMEDGE_BUILD_TOOLS "Generate wasmedge and wasmedgec tools. Depend on and will build the WasmEdge shared library." ON) option(WASMEDGE_BUILD_FUZZING "Generate fuzzing test tools. Couldn't build with wasmedge tools and unit tests." OFF) option(WASMEDGE_BUILD_PLUGINS "Generate plugins." ON) option(WASMEDGE_BUILD_EXAMPLE "Generate examples." OFF) -option(WASMEDGE_BUILD_WASI_NN_RPC "Generate Wasi-NN RPC." OFF) +option(WASMEDGE_BUILD_WASI_NN_RPC "Generate WASI-NN RPC." OFF) +option(WASMEDGE_USE_LLVM "Enable WasmEdge LLVM-based compilation runtime." ON) +if(WASMEDGE_BUILD_AOT_RUNTIME) + message(WARNING "WASMEDGE_BUILD_AOT_RUNTIME option was renamed to WASMEDGE_USE_LLVM.") + set(WASMEDGE_USE_LLVM "${WASMEDGE_BUILD_AOT_RUNTIME}" CACHE STRING "Enable WasmEdge LLVM-based compilation runtime.") + unset(WASMEDGE_BUILD_AOT_RUNTIME CACHE) +endif() option(WASMEDGE_FORCE_DISABLE_LTO "Forcefully disable link time optimization when linking even in Release/RelWithDeb build." OFF) option(WASMEDGE_LINK_LLVM_STATIC "Statically link the LLVM library into the WasmEdge tools and libraries." OFF) option(WASMEDGE_LINK_TOOLS_STATIC "Statically link the wasmedge and wasmedgec tools. Will forcefully link the LLVM library statically." OFF) option(WASMEDGE_ENABLE_UB_SANITIZER "Enable undefined behavior sanitizer." OFF) -set(WASMEDGE_PLUGIN_WASI_NN_BACKEND "" CACHE STRING "Enable WasmEdge Wasi-NN plugin with backends.") -option(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_BLAS "Enable LLAMA_BLAS in the WASI-NN GGML backend" ON) -option(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_CUBLAS "Enable LLAMA_CUBLAS in the WASI-NN GGML backend" OFF) -option(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_METAL "Enable LLAMA_METAL in the WASI-NN GGML backend" OFF) -# Currently supported WASI-NN backend: "OpenVINO" on Linux x86_64 -option(WASMEDGE_PLUGIN_WASI_CRYPTO "Enable WasmEdge Wasi-crypto plugin." OFF) -option(WASMEDGE_PLUGIN_WASI_LOGGING "Enable WasmEdge wasi-logging plugin." OFF) -option(WASMEDGE_PLUGIN_WASM_BPF "Enable WasmEdge wasm-bpf plugin." OFF) -option(WASMEDGE_PLUGIN_OPENCVMINI "Enable WasmEdge opencvmini plugin." OFF) -option(WASMEDGE_PLUGIN_PROCESS "Enable WasmEdge process plugin." OFF) -option(WASMEDGE_PLUGIN_IMAGE "Enable WasmEdge image plugin." OFF) -option(WASMEDGE_PLUGIN_TENSORFLOW "Enable WasmEdge TensorFlow plugin." OFF) -option(WASMEDGE_PLUGIN_TENSORFLOWLITE "Enable WasmEdge TensorFlow-Lite plugin." OFF) -option(WASMEDGE_PLUGIN_RUSTLS "Enable WasmEdge Rustls plugin." OFF) -option(WASMEDGE_PLUGIN_ZLIB "Enable WasmEdge zlib plugin." OFF) -option(WASMEDGE_DISABLE_LIBTINFO "Disable linking against libtinfo when linking LLVM" OFF) - +option(WASMEDGE_DISABLE_LIBTINFO "Disable linking against libtinfo when linking LLVM." OFF) + +# Options about plug-ins. +# WASI plug-in: WASI-Crypto proposal. +option(WASMEDGE_PLUGIN_WASI_CRYPTO "Enable and build WasmEdge wasi-crypto plugin." OFF) +# WASI plug-in: WASI-Http proposal. +option(WASMEDGE_PLUGIN_WASI_HTTP "Enable and build WasmEdge wasi-http plugin." OFF) +# WASI plug-in: WASI-Logging proposal. +# Note: WASMEDGE_PLUGIN_WASI_LOGGING is not used until the new plug-in mechanism ready in 0.15.0. +option(WASMEDGE_PLUGIN_WASI_LOGGING "Enable and build WasmEdge wasi-logging plugin." ON) +# WASI plug-in: WASI-NN proposal with backends. +set(WASMEDGE_PLUGIN_WASI_NN_BACKEND "" CACHE STRING "Enable and build WasmEdge Wasi-NN plugin with backends.") +option(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_NATIVE "Enable LLAMA_NATIVE(AVX/AVX2/FMA) in the WASI-NN GGML backend." ON) +option(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_BLAS "Enable LLAMA_BLAS in the WASI-NN GGML backend." OFF) +option(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_CUBLAS "Enable LLAMA_CUBLAS in the WASI-NN GGML backend." OFF) +option(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_METAL "Enable LLAMA_METAL in the WASI-NN GGML backend. Available on MacOS arm64 only." ON) +set(WASMEDGE_PLUGIN_WASI_NN_BURNRS_MODEL "" CACHE STRING "Enable WasmEdge WASI-NN Burn.rs backend with model.") +# WASI plug-in: WASI-Poll proposal. +option(WASMEDGE_PLUGIN_WASI_POLL "Enable and build WasmEdge wasi-poll plugin." OFF) +# WasmEdge plug-in: wasm-bpf. +option(WASMEDGE_PLUGIN_WASM_BPF "Enable and build WasmEdge wasm-bpf plugin." OFF) +# WasmEdge plug-in: ffmpeg. +option(WASMEDGE_PLUGIN_FFMPEG "Enable and build WasmEdge ffmpeg plugin." OFF) +# WasmEdge plug-in: Image. +option(WASMEDGE_PLUGIN_IMAGE "Enable and build WasmEdge image plugin." OFF) +# WasmEdge plug-in: LLMC. +option(WASMEDGE_PLUGIN_LLMC "Enable and build WasmEdge LLMC plugin." OFF) +# WasmEdge plug-in: OCR. +option(WASMEDGE_PLUGIN_OCR "Enable and build WasmEdge OCR plugin." OFF) +# WasmEdge plug-in: OpenCV-mini. +option(WASMEDGE_PLUGIN_OPENCVMINI "Enable and build WasmEdge opencvmini plugin." OFF) +# WasmEdge plug-in: Process. +option(WASMEDGE_PLUGIN_PROCESS "Enable and build WasmEdge process plugin." OFF) +# WasmEdge plug-in: Stable-diffusion. +option(WASMEDGE_PLUGIN_STABLEDIFFUSION "Enable and build WasmEdge stable-diffusion plugin." OFF) +option(WASMEDGE_PLUGIN_STABLEDIFFUSION_CUBLAS "Enable CUBLAS in the stable-diffusion plugin." OFF) +option(WASMEDGE_PLUGIN_STABLEDIFFUSION_METAL "Enable Metal in the stable-diffusion plugin." OFF) +# WasmEdge plug-in: TensorFlow. +option(WASMEDGE_PLUGIN_TENSORFLOW "Enable and build WasmEdge TensorFlow plugin." OFF) +# WasmEdge plug-in: TensorFlow-Lite. +option(WASMEDGE_PLUGIN_TENSORFLOWLITE "Enable and build WasmEdge TensorFlow-Lite plugin." OFF) +# WasmEdge plug-in: zlib. +option(WASMEDGE_PLUGIN_ZLIB "Enable and build WasmEdge zlib plugin." OFF) + +# Fuzzing and tools and tests are exclusive. if(WASMEDGE_BUILD_TOOLS AND WASMEDGE_BUILD_FUZZING) message(FATAL_ERROR "wasmedge tool and fuzzing tool are exclusive options.") endif() @@ -95,10 +142,12 @@ if(WASMEDGE_BUILD_TESTS AND WASMEDGE_BUILD_FUZZING) message(FATAL_ERROR "unit tests and fuzzing tool are exclusive options.") endif() +# Static library will forcefully turn off the LTO. if(WASMEDGE_BUILD_STATIC_LIB) - # Static library will forcefully turn of the LTO. set(WASMEDGE_FORCE_DISABLE_LTO ON) endif() + +# WasmEdge tool options. if(WASMEDGE_BUILD_TOOLS) if(WASMEDGE_LINK_TOOLS_STATIC) # Static tools will link LLVM statically. @@ -113,28 +162,24 @@ if(WASMEDGE_BUILD_TOOLS) set(WASMEDGE_BUILD_SHARED_LIB ON) endif() endif() -if(WASMEDGE_BUILD_PLUGINS) - if(WASMEDGE_BUILD_STATIC_LIB) - set(WASMEDGE_LINK_PLUGINS_STATIC ON) - endif() -endif() -# * Homebrew: grpc -# * Debian, Ubuntu: libgrpc-dev, libgrpc++-dev -find_package(PkgConfig) -if(PkgConfig_FOUND) - pkg_check_modules(gRPCPP grpc++) -endif() -# Do not check find_package(gRPC), because libgrpc-dev for Ubuntu 22.04 does not contain cmake files. -# https://packages.ubuntu.com/search?keywords=libgrpc-dev -# Do not check find_package(protobuf), because libprotobuf-dev for Ubuntu does not contain cmake files. -# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1027876 -if(gRPCPP_FOUND AND WASMEDGE_BUILD_SHARED_LIB) - message(STATUS "Setting WASMEDGE_BUILD_WASI_NN_RPC to ON. If you see an error related to gRPC or protobuf, try setting this to OFF.") - set(WASMEDGE_BUILD_WASI_NN_RPC ON) -endif() -if(WASMEDGE_BUILD_WASI_NN_RPC AND NOT WASMEDGE_BUILD_SHARED_LIB) - message(FATAL_ERROR "WASMEDGE_BUILD_WASI_NN_RPC depends on WASMEDGE_BUILD_SHARED_LIB") +if(WASMEDGE_BUILD_WASI_NN_RPC) + # * Homebrew: grpc + # * Debian, Ubuntu: libgrpc-dev, libgrpc++-dev + find_package(PkgConfig) + if(PkgConfig_FOUND) + pkg_check_modules(gRPCPP grpc++) + endif() + # Do not check find_package(gRPC), because libgrpc-dev for Ubuntu 22.04 does not contain cmake files. + # https://packages.ubuntu.com/search?keywords=libgrpc-dev + # Do not check find_package(protobuf), because libprotobuf-dev for Ubuntu does not contain cmake files. + # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1027876 + if(gRPCPP_FOUND AND WASMEDGE_BUILD_SHARED_LIB) + message(STATUS "If you see an error related to gRPC or protobuf, try setting WASMEDGE_BUILD_WASI_NN_RPC to OFF.") + endif() + if(WASMEDGE_BUILD_WASI_NN_RPC AND NOT WASMEDGE_BUILD_SHARED_LIB) + message(FATAL_ERROR "WASMEDGE_BUILD_WASI_NN_RPC depends on WASMEDGE_BUILD_SHARED_LIB.") + endif() endif() set(WASMEDGE_BUILD_PACKAGE "DEB;RPM" CACHE STRING "Package generate types") @@ -146,12 +191,13 @@ if(WASMEDGE_BUILD_COVERAGE) append_coverage_compiler_flags() endif() -if(WASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) hunter_add_package(ZLIB) hunter_add_package(LLVM) hunter_add_package(LLD) endif() +include(FetchContent) include(Helper) include(GNUInstallDirs) @@ -183,7 +229,13 @@ endif() add_subdirectory(include) add_subdirectory(lib) -if(WASMEDGE_BUILD_PLUGINS AND WASMEDGE_BUILD_SHARED_LIB) +if(WASMEDGE_BUILD_PLUGINS AND (WASMEDGE_BUILD_STATIC_LIB OR WASMEDGE_BUILD_SHARED_LIB)) + # Plug-ins should depend on the WasmEdge library. + if(WASMEDGE_BUILD_STATIC_LIB AND NOT WASMEDGE_BUILD_SHARED_LIB) + # Link to the static library if only the WasmEdge static library is built. + # If the WasmEdge shared library is built, the plug-ins will link to the shared library. + set(WASMEDGE_LINK_PLUGINS_STATIC ON) + endif() add_subdirectory(plugins) endif() add_subdirectory(thirdparty) @@ -196,4 +248,3 @@ endif() include(CPack) include(CPackComponent) - diff --git a/Changelog.md b/Changelog.md index eba6f9c97737..bf98202c7e3f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,4 +1,63 @@ -### 0.14.0-alpha.1 (2024-01-05) +### 0.14.1 (2024-09-16) + +Features: + +* Supported LLVM 17.0.6. +* Bumpped `spdlog` to `v1.13.0`. +* Bumpped `fmt` to `11.0.2`. +* Bumpped `simdjson` to `v3.10.0`. +* Bumpped `googletest` to `1.15.2`. +* [WASI-NN] ggml backend: + * Bump llama.cpp to b3651. + * Static link `libggml` and `libllama`. + * Refined the CMake to support multiple backends of WASI-NN with ggml backend. + * Supported compute single in RPC mode. +* [WASI-NN] Added support for whisper.cpp backend. +* [WASI-NN] Added support for piper backend. +* [WASI-NN] Added support for ChatTTS backend. +* [WASI-NN] Added support for Burn.rs backend. + * Supported `squeezenet` and `whisper` models. +* [Plugin] Supported `wasmedge_stablediffusion` plug-in. + * Enabled CUBLAS. + * Enabled metal support on MacOS. +* [Plugin] Moved `wasi_logging` into built-in plug-in. + * Instead of installing `wasi_logging` plug-in shared library, developers can find and get this plug-in after calling `WasmEdge_PluginLoadWithDefaultPaths()` API. + * In the WasmEdge CLI tools, the built-in plug-ins will automatically be loaded. +* [Proposal] Initial support for instantiation phase of component model. + * Due to the breaking change of API, bump the plug-in `API_VERSION` to `3`. +* [Proposal] Supported WASM Relaxed-SIMD proposal. + * Added the `WasmEdge_Proposal_RelaxSIMD` for the configuration in WasmEdge C API. + * Users can use the `--enable-relaxed-simd` to enable the proposal in `wasmedge` and `wasmedgec` tools. + +Fixed issues: + +* Fixed warnings on GCC-14. +* Fixed the `fmt` related header inclusion for error logging. +* Fixed WASI test error in Windows. +* Fixed version checking in source tarball. +* Fixed version detection issue when building from source. +* Fixed the visibility of internal symbols. +* [Loader] Fixed alignment checking in loading immediates for memory instructions. +* [Runtime] Fixed allocation issue when configured the limited memory page size. +* Used `fmt::format` instead of string stream in error logging. + +Tests: + +* Added WASI test suites on Windows. + +Known issues: + +* Universal WASM format failed on macOS platforms. + * In the current status, the universal WASM format output of the AOT compiler with the `O1` or upper optimizations on MacOS platforms will cause a bus error during execution. + * We are trying to fix this issue. For a working around, please use the `--optimize=0` to set the compiler optimization level to `O0` in `wasmedgec` CLI. + +Thank all the contributors who made this release possible! + +Biswapriyo Nath, Elmira, Faidon Liambotis, Fusaaaann, Han-Wen Tsao, Jun Zhang, Kefu Chai, Lîm Tsú-thuàn, Michael Morris, PeterD1524, Shen-Ta Hsieh, Shreyas Atre, Sylveon, Yi Huang, Yi-Ying He, alabulei1, dm4, grorge, hydai, junxiangMu, vincent + +If you want to build from source, please use WasmEdge-0.14.1-src.tar.gz instead of the zip or tarball provided by GitHub directly. + +### 0.14.0 (2024-05-22) Breaking changes: @@ -29,16 +88,35 @@ Breaking changes: * `WasmEdge_VMRunWasmFromBytes()` API has the same function as `WasmEdge_VMRunWasmFromBuffer()` and will replace it in the future. * `WasmEdge_VMAsyncRunWasmFromBytes()` API has the same function as `WasmEdge_VMAsyncRunWasmFromBuffer()` and will replace it in the future. * `WasmEdge_VMLoadWasmFromBytes()` API has the same function as `WasmEdge_VMLoadWasmFromBuffer()` and will replace it in the future. + * New APIs for WASM Exception-Handling proposal. + * Added the `WasmEdge_TagTypeContext` struct. + * Added the `WasmEdge_TagInstanceContext` struct. + * Added the `WasmEdge_TagTypeGetFunctionType()` API for retrieving the function type from a tag type. + * Added the `WasmEdge_ImportTypeGetTagType()` API for retrieving the tag type from an import type. + * Added the `WasmEdge_ExportTypeGetTagType()` API for retrieving the tag type from an export type. + * Added the `WasmEdge_ModuleInstanceFindTag()` API for finding an exported tag instance from a module instance. + * Added the `WasmEdge_ModuleInstanceListTagLength()` and `WasmEdge_ModuleInstanceListTag()` APIs for listing the exported tag instances of a module instance. +* Refactored the `OpCode` mechanism for speeding up and supporting WASM multi-bytes instruction OpCodes. Features: +* Bumpped `spdlog` to `v1.13.0`. +* Bumpped `simdjson` to `v3.9.1`. * [Proposal]: Apply new propoals. * Supported WASM Typed Function References proposal. * Added the `WasmEdge_Proposal_FunctionReferences` for the configuration in WasmEdge C API. * Users can use the `--enable-function-reference` to enable the proposal in `wasmedge` and `wasmedgec` tools. + * Supported WASM GC proposal (interpreter only). + * Added the `WasmEdge_Proposal_GC` for the configuration in WasmEdge C API. + * Users can use the `--enable-gc` to enable the proposal in `wasmedge` and `wasmedgec` tools. + * Supported WASM Exception-Handling proposal (interpreter only). + * Added the `WasmEdge_Proposal_ExceptionHandling` for the configuration in WasmEdge C API. + * Users can use the `--enable-exception-handling` to enable the proposal in `wasmedge` and `wasmedgec` tools. + * This proposal supports old deprecated `try`, `catch`, and `catch_all` instructions, and will remove them in the future version. * Component Model proposal (experimental, loader phase only). * Added the `WasmEdge_Proposal_Component` for the configuration in WasmEdge C API. - * Users can use the `--enable-function-reference` to enable the proposal in `wasmedge` tool. + * Users can use the `--enable-component` to enable the proposal in `wasmedge` tool. +* [JIT]: Support LLVM JIT. * [C API]: New C API for supporting the new proposals. * `WasmEdge_ValType` related APIs can help developers to generate or compare value types. * `WasmEdge_ValTypeGenI32()` (replacing `WasmEdge_ValType_I32`) @@ -68,23 +146,43 @@ Features: * [Tools]: Print the plug-in versions when using the `--version` option. * [Installer]: Enabled `ggml-blas` and `rustls` plugin supporting (#3032) (#3108). * [WASI-NN] ggml backend: - * Bump llama.cpp to b1743 + * Bump llama.cpp to b2963. * Support llama.cpp options: * `threads`: the thread number for inference. * `temp`: set temperature for inference. * `repeat-penalty`: set repeat penalty for inference. + * `top-p`: set top-p for inference. + * `grammar`: set grammar syntax for inference. + * `main-gpu`: set the main GPU for inference. + * `tensor-split`: set the tensor split for inference. * Add `enable-debug-log` option to show more debug information. * Default enable Metal on macOS. * Introduce `load_by_name_with_config()` to load model with metadata. * Introduce single token inference by `compute_single`, `get_output_single`, and `fini_single` - * Add some llama errors to WASI-NN + * Introduce `unload()` function to release the model. + * Add some llama errors to WASI-NN. * `EndOfSequence`: returned when encounter `<EOS>` token on single token inferece. * `ContextFull`: returned when the context is full. * `PromptTooLong`: returned when the input size is too large. + * `ModelNotFound`: returned when the model is not found. + * Support Llava and Gemma inference. + * Add `mmproj` option to set the projection model. + * Add `image` option to set the image. + * Improve logging mechanism. + * Show the version of `llama.cpp` in the metadata. + * Support Phi-3-Mini model. + * Support embedding generation. + * Support Windows build. +* [Plugin] Initial support for `wasmedge_ffmpeg` plug-in. +* [Plugin] Updated `wasi-logging` plug-in for supporting logging into file. Fixed issues: * Fixed some API document in the API header. +* [Executor]: Minor fixes. + * Fixed integer overflow on `memGrow` boundary check. + * Refined the slice copy in table instances. + * Cleaned the unused bits of WASM return values to avoid security issues. * [WASI]: Minor fixes. * Fixed the function signature matching for WASI imports when backwarding supporting older version. (#3073) * Fixed large timestamp causing overflow (#3106). @@ -94,15 +192,21 @@ Fixed issues: * Fixed `path_readlink` for not following symbolic link issue. * Fixed `path_open` for checking `O_TRUNC` rights. * Fixed `path_open` for removing path relative rights on file. + * Fixed `fd_allocate` return error value. * Checking `path_symlink` for creating a symlink to an absolute path. * Checking `fd_prestat_dir_name` buffer size. * Checking `filestat_set_times` for invalid flags. * Checking validation of file descriptor in `socket_accept` (#3041). +* Fixed duplicated loading of the same plug-in. +* Fixed option toggle for `wasmedge_process` plug-in. +* Fixed the plug-in searching path on Windows. Tests: -* Updated the WASM spec tests to the date 2023/10/26. +* Updated the WASM spec tests to the date 2024/02/17. +* Updated the spec tests for the Exception Handling proposal. * Added the spec tests for the Typed Function Reference proposal. +* Added the spec tests for the GC proposal. Known issues: @@ -112,9 +216,9 @@ Known issues: Thank all the contributors who made this release possible! -Abhinandan Udupa, Akihiro Suda, Dhruv Jain, Draco, Little Willy, Lîm Tsú-thuàn, Meenu Yadav, Omkar Acharekar, Saiyam Pathak, Shen-Ta Hsieh, Shreyas Atre, Yage Hu, Yi-Ying He, alabulei1, am009, dm4, hydai, richzw, zhumeme +Abhinandan Udupa, Akihiro Suda, Charlie chan, Dhruv Jain, Draco, Harry Chiang, Hrushikesh, Ikko Eltociear Ashimine, Khagan (Khan) Karimov, LFsWang, LO, CHIN-HAO, Little Willy, Lîm Tsú-thuàn, Meenu Yadav, Omkar Acharekar, Saiyam Pathak, Sarrah Bastawala, Shen-Ta Hsieh, Shreyas Atre, Sylveon, Yage Hu, Yi Huang, Yi-Ying He, alabulei1, am009, dm4, hetvishastri, hugo-syn, hydai, redismongo, richzw, tannal, vincent, zhumeme -If you want to build from source, please use WasmEdge-0.14.0-alpha.1-src.tar.gz instead of the zip or tarball provided by GitHub directly. +If you want to build from source, please use WasmEdge-0.14.0-src.tar.gz instead of the zip or tarball provided by GitHub directly. ### 0.13.5 (2023-11-03) @@ -333,7 +437,7 @@ Features: * Added helper functions for Windows CLI. * Added the `WasmEdge_Driver_ArgvCreate()` and `WasmEdge_Driver_ArgvDelete()` APIs to convert UTF-16 arguments to UTF-8. * Added the `WasmEdge_Driver_SetConsoleOutputCPtoUTF8()` API to set the output code page to UTF-8. -* Added the unifed tool API. +* Added the unified tool API. * Added the `WasmEdge_Driver_UniTool()` API to trigger the WasmEdge CLI tool with command line arguments. Fixed issues: diff --git a/LICENSE.spdx b/LICENSE.spdx index d73a6d7c765c..ebbd635997be 100644 --- a/LICENSE.spdx +++ b/LICENSE.spdx @@ -41,7 +41,16 @@ PackageOriginator: Georgi Gerganov PackageLicenseDeclared: MIT PackageDownloadLocation: git://github.com/ggerganov/llama.cpp.git +PackageName: cpr +SPDXID: SPDXRef-cpr +PackageFileName: ./plugins/wasi_http/CMakeLists.txt +PackageHomePage: https://github.com/libcpr/cpr +PackageOriginator: Huu Nguyen +PackageLicenseDeclared: MIT +PackageDownloadLocation: git@github.com:libcpr/cpr.git + ## Relationships Relationship: SPDXRef-wasmedge CONTAINS SPDXRef-blake3 Relationship: SPDXRef-wasmedge CONTAINS SPDXRef-wasi-cpp-header Relationship: SPDXRef-wasmedge CONTAINS SPDXRef-llama.cpp +Relationship: SPDXRef-wasmedge CONTAINS SPDXRef-cpr diff --git a/README-zh-TW.md b/README-zh-TW.md index f8d60c798716..eaf8584f26a9 100644 --- a/README-zh-TW.md +++ b/README-zh-TW.md @@ -23,7 +23,7 @@ WasmEdge (前名為 SSVM ) 是為邊緣運算最佳化的輕量級、高性 # 快速開始指引 🚀 [安装](https://wasmedge.org/docs/zh-tw/start/install) WasmEdge\ -🤖 [編譯](https://wasmedge.org/docs/zh-tw/category/build-wasmedge-from-source) 並[貢獻](docs/book/en/src/contribute.md) WasmEdge\ +🤖 [編譯](https://wasmedge.org/docs/zh-tw/category/build-wasmedge-from-source) 並[貢獻](https://wasmedge.org/docs/zh-tw/contribute/) WasmEdge\ ⌨️ [從 CLI 執行](https://wasmedge.org/docs/zh-tw/category/running-with-wasmedge)一個獨立的 Wasm 程式或 [JavaScript 程式](https://wasmedge.org/docs/zh-tw/category/develop-wasm-apps-in-javascript) \ 🔌 在 [Node.js](https://github.com/second-state/wasm-learning/tree/master/ssvm/file-example) 、 [Go 語言](https://wasmedge.org/docs/zh-tw/category/go-sdk-for-embedding-wasmedge)、或是 [Rust 應用程式](https://www.secondstate.io/articles/getting-started-with-rust-function/)嵌入 Wasm 函式 \ 🛠 使用 [Docker 工具](https://www.secondstate.io/articles/manage-webassembly-apps-in-wasmedge-using-docker-tools/)、[即時資料流框架](https://www.secondstate.io/articles/yomo-wasmedge-real-time-data-streams/), 和 [區塊鏈](https://medium.com/ethereum-on-steroids/running-ethereum-smart-contracts-in-a-substrate-blockchain-56fbc27fc95a) 管理和編排 Wasm runtimes diff --git a/README-zh.md b/README-zh.md index 86941893fca4..d3663597626e 100644 --- a/README-zh.md +++ b/README-zh.md @@ -23,7 +23,7 @@ WasmEdge (之前名为 SSVM) 是为边缘计算优化的轻量级、高性能、 # 快速开始指引 🚀 [安装](https://wasmedge.org/docs/zh/start/install) WasmEdge\ -🤖 [Build](https://wasmedge.org/docs/zh/category/build-wasmedge-from-source) 并[贡献](docs/book/en/src/contribute.md)给 WasmEdge\ +🤖 [Build](https://wasmedge.org/docs/zh/category/build-wasmedge-from-source) 并[贡献](https://wasmedge.org/docs/zh/contribute/)给 WasmEdge\ ⌨️ [从 CLI 跑](https://wasmedge.org/docs/zh/category/running-with-wasmedge)一个独立的 Wasm 程序或 [JavaScript 程序](https://wasmedge.org/docs/zh/category/develop-wasm-apps-in-javascript) \ 🔌 [嵌入一个 Wasm 函数](https://www.secondstate.io/articles/getting-started-with-rust-function/)在你的[Node.js](https://github.com/second-state/wasm-learning/tree/master/ssvm/file-example), [Go语言](https://wasmedge.org/docs/zh/category/go-sdk-for-embedding-wasmedge)或 Rust 应用里 \ 🛠 使用 [Docker 工具](https://www.secondstate.io/articles/manage-webassembly-apps-in-wasmedge-using-docker-tools/)、[数据流框架](https://www.secondstate.io/articles/yomo-wasmedge-real-time-data-streams/), 和 [区块链](https://medium.com/ethereum-on-steroids/running-ethereum-smart-contracts-in-a-substrate-blockchain-56fbc27fc95a) 管理和编排 Wasm runtimes diff --git a/README.md b/README.md index 388642e477a4..7525bfbb3238 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,6 @@ WasmEdge and its contained wasm program can be started from the [CLI](https://wa * [Embed WasmEdge into a host application](https://wasmedge.org/docs/embed/overview) * [Orchestrate and manage WasmEdge instances using container tools](https://wasmedge.org/docs/category/deploy-wasmedge-apps-in-kubernetes) * [Run a WasmEdge app as a Dapr microservice](https://wasmedge.org/docs/develop/rust/dapr) -= # Community diff --git a/SECURITY-INSIGHTS.yml b/SECURITY-INSIGHTS.yml index 457dc429b916..75c89f0cc4ae 100644 --- a/SECURITY-INSIGHTS.yml +++ b/SECURITY-INSIGHTS.yml @@ -66,4 +66,4 @@ dependencies: env-dependencies-policy: policy-url: https://github.com/WasmEdge/WasmEdge/blob/master/SECURITY.md comment: | - You will receive an acknowledgement mail within 24 hours \ No newline at end of file + You will receive an acknowledgement mail within 24 hours diff --git a/SECURITY.md b/SECURITY.md index e4268c5ce4a7..6385328e9e3d 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,8 +1,37 @@ -### Reporting a vulnerability +# Security policy -For all WasmEdge security-related defects, please send an email to security@secondstate.io. You will receive an acknowledgement mail within 24 hours. After that, we will give a detailed response about the subsequent process within 48 hours. Please do not submit security vulnerabilities directly as Github Issues. +## Security bulletins -### Disclosure policy +For information regarding the security of WasmEdge please join: + +* Mailing List <wasmedge@googlegroup.com> + +## Reporting a vulnerability + +Please use the below process to report a vulnerability to WasmEdge: + +Email: + +1. Send email to <wasmedge-security@lists.cncf.io> + * Emails should contain: + * description of the problem + * precise and detailed steps (include screenshots) that created the + problem + * the affected version(s) + * any possible mitigations, if known +1. You will receive a reply from one of the maintainers within 24 hours + acknowledging receipt of the email. After that, we will give a detailed + response about the subsequent process within 48 hours. +1. Please do not submit security vulnerabilities directly as Github Issues. + +Web: + +1. Please visit [GitHub Seuciry Advisory of WasmEdge](https://github.com/WasmEdge/WasmEdge/security/advisories/new) + * You will receive a confirmation email upon submission + +WasmEdge follows a **`90 days` disclosure timeline**. Refer to our [embargo policy](./docs/embargo-policy.md) for more information. + +## Disclosure policy For known public security vulnerabilities, we will disclose the disclosure as soon as possible after receiving the report. Vulnerabilities discovered for the first time will be disclosed in accordance with the following process: @@ -11,3 +40,12 @@ For known public security vulnerabilities, we will disclose the disclosure as so * Invite related personnel to discuss about the fix. * Fork the temporary private repository on Github, and collaborate to fix the vulnerability. * After the fix code is merged into all supported versions, the vulnerability will be publicly posted in the GitHub Advisory Database. + +## Supported Versions + +Information regarding supported versions of WasmEdge are in the below table: + +| Version | Supported | +| ------- | --------- | +| 0.14.0 | :white_check_mark: | +| 0.13.5 | :white_check_mark: | diff --git a/bindings/java/README.md b/bindings/java/README.md index 3291f12571f8..bd355bb6747c 100644 --- a/bindings/java/README.md +++ b/bindings/java/README.md @@ -28,42 +28,47 @@ WasmEdgeVM vm = new WasmEdgeVM(); // Create param list - List<WasmEdgeValue> params = new ArrayList<>(); - params.add(new WasmEdgeI32Value(4)); + List<Value> params = new ArrayList<>(); + params.add(new I32Value(4)); // Create return list - List<WasmEdgeValue> returns = new ArrayList<>(); - returns.add(new WasmEdgeI32Value()); + List<Value> returns = new ArrayList<>(); + returns.add(new I32Value()); ``` ### VM Run a wasm file ```java - WasmEdgeAsync async = vm.asyncrunWasmFromFile("/root/fibonacci.wasm", "fib", params, returns); + String fibWasmPath = "/root/fibonacci.wasm"; + String funcName = "fib"; + + Async async = vm.asyncRunWasmFromFile(fibWasmPath, funcName, params); ``` ### VM Run a wasm from buffer ```java - byte[] data = loadFile(getResourcePath(FIB_WASM_PATH)); - WasmEdgeAsync async = vm.asyncRunWasmFromBuffer(buffer, funcName, params); + byte[] data = Files.readAllBytes(Paths.get(fibWasmPath)); + Async async = vm.asyncRunWasmFromBuffer(data, funcName, params); ``` ### VM Run a wasm from AST module ```java - ASTModuleContext mod = loaderContext.parseFromFile(getResourcePath(FIB_WASM_PATH)); - WasmEdgeAsync async = vm.asyncRunWasmFromBuffer(mod, funcName, params); + LoaderContext loaderContext = new LoaderContext(null); + AstModuleContext mod = loaderContext.parseFromFile(fibWasmPath); + Async async = vm.asyncRunWasmFromAstModule(mod, funcName, params); ``` ### VM Run a wasm step by step ```java - vm.loadWasmFromFile(getResourcePath(FIB_WASM_PATH)); + vm.loadWasmFromFile(fibWasmPath); vm.validate(); vm.instantiate(); - WasmEdgeAsync async = vm.execute("fib", params); + vm.execute(funcName, params, returns); ``` ### VM Execute Register Module ```java - String modName = ...; - vm.registerModuleFromBuffer(modName, loadFile(getResourcePath(FIB_WASM_PATH))); - WasmEdgeAsync async = vm.executeRegistered(modName, FUNC_NAME, params); + String modName = "fibonacciModule"; + byte[] data = Files.readAllBytes(Paths.get(fibWasmPath)); + vm.registerModuleFromBuffer(modName, data); + vm.executeRegistered(modName, funcName, params, returns); ``` @@ -71,38 +76,38 @@ ### Developers can wait the execution until finished ```java WasmEdgeAsync async = ...; - async.wasmEdge_AsyncWait(); + async.asyncWait(); - // wasmEdge_AsyncDelete to delete and free the resource - async.wasmEdge_AsyncDelete(); + // close to delete and free the resource + async.close(); ``` ### Or developers can wait for a time limit. ```java WasmEdgeAsync async = ...; // Get return values - boolean isEnd = async.wasmEdge_AsyncWaitFor(1000); + boolean isEnd = async.waitFor(1000); if (IsEnd) { /* The execution finished. Developers can get the result. */ - async.wasmEdge_AsyncGet(returns); + async.get(returns); } else { /* * The time limit exceeded. Developers can keep waiting or cancel the execution. */ - async.wasmEdge_AsyncCancel(); - async.wasmEdge_AsyncGet(returns); + async.cancel(); + async.get(returns); } - async.wasmEdge_AsyncDelete(); + async.close(); ``` ### Get the execution result of the asynchronous execution  -### Developers can use the wasmEdge_AsyncGetReturnsLength() API to get the return value list length. This function will block and wait for the execution. If the execution has finished, this function will return the length immediately. If the execution failed, this function will return 0. This function can help the developers to create the buffer to get the return values. If developers have already known the buffer length, they can skip this function and use the wasmEdge_AsyncGet() API to get the result. +### Developers can use the getReturnsLength() API to get the return value list length. This function will block and wait for the execution. If the execution has finished, this function will return the length immediately. If the execution failed, this function will return 0. This function can help the developers to create the buffer to get the return values. If developers have already known the buffer length, they can skip this function and use the get() API to get the result. ```java WasmEdgeAsync async = ...; - int len = async.wasmEdge_AsyncGetReturnsLength(); - async.wasmEdge_AsyncDelete(); + int len = async.getReturnsLength(); + async.close(); ``` -### The wasmEdge_AsyncGet() API will block and wait for the execution. If the execution has finished, this function will fill the return values into the buffer and return the execution result immediately. +### The get() API will block and wait for the execution. If the execution has finished, this function will fill the return values into the buffer and return the execution result immediately. ```java WasmEdgeAsync async = ...; @@ -110,6 +115,6 @@ List<WasmEdgeValue> returns = new ArrayList<>(); returns.add(new WasmEdgeI32Value()); - async.wasmEdge_AsyncGet(returns); - async.wasmEdge_AsyncDelete(); -``` \ No newline at end of file + async.get(returns); + async.close(); +``` diff --git a/bindings/java/wasmedge-java/.gitignore b/bindings/java/wasmedge-java/.gitignore new file mode 100644 index 000000000000..e660fd93d319 --- /dev/null +++ b/bindings/java/wasmedge-java/.gitignore @@ -0,0 +1 @@ +bin/ diff --git a/bindings/java/wasmedge-java/build.gradle b/bindings/java/wasmedge-java/build.gradle index 085a169fbff1..ee7aa9cef809 100644 --- a/bindings/java/wasmedge-java/build.gradle +++ b/bindings/java/wasmedge-java/build.gradle @@ -27,7 +27,7 @@ dependencies { sourceSets { main { resources { - srcDirs "src/main/resources", "build/natives/lib" + srcDirs "src/main/resources", "wasmedge-jni/build/lib" } } } @@ -42,9 +42,9 @@ task compileJNI { doLast { exec { if (Os.isFamily(Os.FAMILY_WINDOWS)) { - commandLine 'cmd', '-c', 'mkdir -p build/native && cd build/ && cmake -Bnative -GNinja -DCMAKE_BUILD_TYPE=Release "-DCMAKE_SYSTEM_VERSION=$cmake_sys_version" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL "-DLLVM_DIR=$llvm_dir" -DWASMEDGE_BUILD_PACKAGE="ZIP" ../wasmedge-jni && dir /s . && cmake --build native' + commandLine 'cmd', '-c', 'mkdir -p wasmedge-jni/build && cd wasmedge-jni/build && cmake -Bnative -GNinja -DCMAKE_BUILD_TYPE=Release "-DCMAKE_SYSTEM_VERSION=$cmake_sys_version" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL "-DLLVM_DIR=$llvm_dir" -DWASMEDGE_BUILD_PACKAGE="ZIP" .. && dir /s . && cmake --build .' } else if (Os.isFamily(Os.FAMILY_MAC) || Os.isFamily(Os.FAMILY_UNIX)) { - commandLine 'sh', '-c', 'mkdir -p build/native && cd build/native && cmake ../../wasmedge-jni && make' + commandLine 'sh', '-c', 'mkdir -p wasmedge-jni/build && cd wasmedge-jni/build && cmake .. && make' } } } @@ -59,7 +59,7 @@ clean.doFirst { processResources { dependsOn compileJNI - from "build/native/" + from "wasmedge-jni/build" include "*.dll", "*.so", "*.dylib" @@ -67,7 +67,7 @@ processResources { tasks.withType(Test) { - systemProperty "java.library.path", "build/native/" + systemProperty "java.library.path", "wasmedge-jni/build" testLogging.showStandardStreams = false } diff --git a/bindings/java/wasmedge-java/config/checkstyle/checkstyle.xml b/bindings/java/wasmedge-java/config/checkstyle/checkstyle.xml index ac1a9f4527d8..366de42754ec 100644 --- a/bindings/java/wasmedge-java/config/checkstyle/checkstyle.xml +++ b/bindings/java/wasmedge-java/config/checkstyle/checkstyle.xml @@ -379,4 +379,4 @@ <property name="influenceFormat" value="1"/> </module> </module> -</module> \ No newline at end of file +</module> diff --git a/bindings/java/wasmedge-java/settings.gradle b/bindings/java/wasmedge-java/settings.gradle index ae904ce92a3b..e5e3f5598a5e 100644 --- a/bindings/java/wasmedge-java/settings.gradle +++ b/bindings/java/wasmedge-java/settings.gradle @@ -1,2 +1 @@ rootProject.name = 'wasmedge-java' - diff --git a/bindings/java/wasmedge-java/src/main/java/org/wasmedge/Async.java b/bindings/java/wasmedge-java/src/main/java/org/wasmedge/Async.java index 951837366d9b..28fe464a4e6c 100644 --- a/bindings/java/wasmedge-java/src/main/java/org/wasmedge/Async.java +++ b/bindings/java/wasmedge-java/src/main/java/org/wasmedge/Async.java @@ -41,4 +41,3 @@ public void get(List<Value> returns) { public native void close(); } - diff --git a/bindings/java/wasmedge-java/wasmedge-jni/CMakeLists.txt b/bindings/java/wasmedge-java/wasmedge-jni/CMakeLists.txt index 0a68dd38b589..903a3dcbadaa 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/CMakeLists.txt +++ b/bindings/java/wasmedge-java/wasmedge-jni/CMakeLists.txt @@ -49,4 +49,3 @@ add_library(${TARGET} SHARED lib/Async.c) target_link_libraries(${TARGET} ${WasmEdge_LIBRARIES}) - diff --git a/bindings/java/wasmedge-java/wasmedge-jni/FindWasmEdge.cmake b/bindings/java/wasmedge-java/wasmedge-jni/FindWasmEdge.cmake index 1abf4aeae542..db705a6d2401 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/FindWasmEdge.cmake +++ b/bindings/java/wasmedge-java/wasmedge-jni/FindWasmEdge.cmake @@ -15,8 +15,8 @@ else() set(_WasmEdge_ROOT "${WasmEdge_ROOT}") endif() -message(STATUS "wasmedge root: ${WasmEdge_ROOT}") -find_path(WasmEdge_INCLUDE_DIRS NAMES wasmedge/wasmedge.h HINTS ${_WasmEdge_ROOT}/include ${WasmEdge_ROOT}/include/api /usr/local/include /usr/include) +message(STATUS "wasmedge root: ${_WasmEdge_ROOT}") +find_path(WasmEdge_INCLUDE_DIRS NAMES wasmedge/wasmedge.h HINTS ${_WasmEdge_ROOT}/include ${_WasmEdge_ROOT}/include/api /usr/local/include /usr/include) message(STATUS "wasmedge include dirs: ${WasmEdge_INCLUDE_DIRS}") if(WasmEdge_INCLUDE_DIRS) @@ -68,4 +68,4 @@ find_package_handle_standard_args(WasmEdge WasmEdge_LIBRARIES VERSION_VAR WasmEdge_VERSION - ) \ No newline at end of file + ) diff --git a/bindings/java/wasmedge-java/wasmedge-jni/README.md b/bindings/java/wasmedge-java/wasmedge-jni/README.md index eb6a5f4b954c..834cda589f8b 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/README.md +++ b/bindings/java/wasmedge-java/wasmedge-jni/README.md @@ -1,6 +1,14 @@ -### Build and install +# Build and install + - Clone this project - Go to `WasmEdge/bindings/java/wasmedge-jni` - Run `mkdir build && cd build` - Run `cmake .. && make && make install` +## Environment variables + +To run this build directly, one has to setup a proper `WasmEdge_ROOT`, which contains headers and libraries. + +``` +WasmEdge_ROOT=/path/to/WasmEdge/build cmake .. +``` diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/AstModuleContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/AstModuleContext.c index 4365be50f53e..d74bdd7ffcc8 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/AstModuleContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/AstModuleContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_AstModuleContext.h" #include "ExportTypeContext.h" @@ -60,7 +60,8 @@ jobject createAstModuleContext(JNIEnv *env, const WasmEdge_ASTModuleContext *mod) { jclass cls = findJavaClass(env, ORG_WASMEDGE_ASTMODULECONTEXT); - jmethodID constructor = findJavaMethod(env, cls, DEFAULT_CONSTRUCTOR, VOID_VOID); + jmethodID constructor = + findJavaMethod(env, cls, DEFAULT_CONSTRUCTOR, VOID_VOID); jobject obj = (*env)->NewObject(env, cls, constructor); setPointer(env, obj, (long)mod); return obj; diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/AstModuleContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/AstModuleContext.h index d265c4b7ef1a..5d9e95b26ae1 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/AstModuleContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/AstModuleContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_ASTMODULECONTEXT_H #define WASMEDGE_JAVA_ASTMODULECONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/Async.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/Async.c index 2b6753d6f518..ef50b1abed89 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/Async.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/Async.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "ExportTypeContext.h" #include "ImportTypeContext.h" @@ -18,36 +18,36 @@ WasmEdge_Async *getAsync(JNIEnv *env, jobject thisObject) { return (WasmEdge_Async *)getPointer(env, thisObject); } -JNIEXPORT void JNICALL Java_org_wasmedge_Async_asyncWait( - JNIEnv *env, jobject thisobject) { +JNIEXPORT void JNICALL Java_org_wasmedge_Async_asyncWait(JNIEnv *env, + jobject thisobject) { WasmEdge_Async *ctx = getAsync(env, thisobject); WasmEdge_AsyncWait(ctx); } JNIEXPORT jboolean JNICALL Java_org_wasmedge_Async_waitFor(JNIEnv *env, - jobject thisobject, - jlong milliseconds) { + jobject thisobject, + jlong milliseconds) { WasmEdge_Async *ctx = getAsync(env, thisobject); uint64_t Milliseconds = milliseconds; return WasmEdge_AsyncWaitFor(ctx, Milliseconds); } -JNIEXPORT void JNICALL Java_org_wasmedge_Async_cancel( - JNIEnv *env, jobject thisobject) { +JNIEXPORT void JNICALL Java_org_wasmedge_Async_cancel(JNIEnv *env, + jobject thisobject) { WasmEdge_Async *ctx = getAsync(env, thisobject); WasmEdge_AsyncCancel(ctx); } JNIEXPORT jint JNICALL -Java_org_wasmedge_Async_getReturnsLength( - JNIEnv *env, jobject thisobject) { +Java_org_wasmedge_Async_getReturnsLength(JNIEnv *env, jobject thisobject) { WasmEdge_Async *ctx = getAsync(env, thisobject); return (jint)WasmEdge_AsyncGetReturnsLength(ctx); } -JNIEXPORT void JNICALL Java_org_wasmedge_Async_get( - JNIEnv *env, jobject thisobject, jobjectArray jreturns, - jintArray jReturnTypes) { +JNIEXPORT void JNICALL Java_org_wasmedge_Async_get(JNIEnv *env, + jobject thisobject, + jobjectArray jreturns, + jintArray jReturnTypes) { WasmEdge_Async *ctx = getAsync(env, thisobject); jsize returnsLen = (*env)->GetArrayLength(env, jreturns); WasmEdge_Value *returns = calloc(returnsLen, sizeof(WasmEdge_Value)); @@ -85,8 +85,8 @@ JNIEXPORT void JNICALL Java_org_wasmedge_Async_get( } } -JNIEXPORT void JNICALL Java_org_wasmedge_Async_close( - JNIEnv *env, jobject thisobject) { +JNIEXPORT void JNICALL Java_org_wasmedge_Async_close(JNIEnv *env, + jobject thisobject) { WasmEdge_Async *ctx = getAsync(env, thisobject); WasmEdge_AsyncDelete(ctx); } @@ -94,6 +94,7 @@ JNIEXPORT void JNICALL Java_org_wasmedge_Async_close( jobject createJAsyncObject(JNIEnv *env, WasmEdge_Async *asyncObj) { jclass clazz = (*env)->FindClass(env, ORG_WASMEDGE_ASYNC); - jmethodID constructorId = (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); + jmethodID constructorId = + (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); return (*env)->NewObject(env, clazz, constructorId, (long)asyncObj); } diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/Async.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/Async.h index 833bdf68c86f..d90f6d47e082 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/Async.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/Async.h @@ -1,12 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JNI_ASYNC_H #define WASMEDGE_JNI_ASYNC_H +#include "../jni/org_wasmedge_Async.h" #include "jni.h" #include "wasmedge/wasmedge.h" -#include "../jni/org_wasmedge_Async.h" WasmEdge_Async *getAsync(JNIEnv *env, jobject thisObject); diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/CompilerContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/CompilerContext.c index 3440b0b67b26..dfc604ac6011 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/CompilerContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/CompilerContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_CompilerContext.h" #include "ConfigureContext.h" diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/ConfigureContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/ConfigureContext.c index c5b1fff2d21f..91467453045e 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/ConfigureContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/ConfigureContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_ConfigureContext.h" #include "common.h" @@ -8,7 +8,6 @@ GETTER(ConfigureContext) - JNIEXPORT void JNICALL Java_org_wasmedge_ConfigureContext_nativeInit(JNIEnv *env, jobject thisObj) { WasmEdge_ConfigureContext *ConfigureContext = WasmEdge_ConfigureCreate(); diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/ConfigureContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/ConfigureContext.h index fa1983cbfb54..8593a208e994 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/ConfigureContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/ConfigureContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_CONFIGURECONTEXT_H #define WASMEDGE_JAVA_CONFIGURECONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/ExecutorContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/ExecutorContext.c index dd8a18ba0278..877d3b813538 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/ExecutorContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/ExecutorContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_ExecutorContext.h" #include "AstModuleContext.h" @@ -29,8 +29,7 @@ JNIEXPORT void JNICALL Java_org_wasmedge_ExecutorContext_nativeInit( * Method: instantiate * Signature: (Lorg/wasmedge/StoreContext;Lorg/wasmedge/ASTModuleContext;)V */ -JNIEXPORT jobject JNICALL -Java_org_wasmedge_ExecutorContext_instantiate( +JNIEXPORT jobject JNICALL Java_org_wasmedge_ExecutorContext_instantiate( JNIEnv *env, jobject thisObject, jobject jStoreCxt, jobject jAstModCxt) { WasmEdge_ExecutorContext *exeCxt = getExecutorContext(env, thisObject); WasmEdge_StoreContext *storeCxt = getStoreContext(env, jStoreCxt); diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/ExportTypeContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/ExportTypeContext.c index 80e22bcb0ceb..a58ea169f9e4 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/ExportTypeContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/ExportTypeContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "ExportTypeContext.h" #include "AstModuleContext.h" diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/ExportTypeContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/ExportTypeContext.h index 063681d91009..835cd46492a5 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/ExportTypeContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/ExportTypeContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_EXPORTTYPECONTEXT_H #define WASMEDGE_JAVA_EXPORTTYPECONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/ExternRef.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/ExternRef.c index 415189a8af47..cebef52046bf 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/ExternRef.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/ExternRef.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common.h" #include <stdlib.h> diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeContext.c index 7a0c8c4b5ead..78c7ebc797e6 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_FunctionTypeContext.h" #include "common.h" @@ -76,8 +76,8 @@ jobject ConvertToJavaValueType(JNIEnv *env, enum WasmEdge_ValType *valType) { return NULL; } - jmethodID jmethodId = (*env)->GetStaticMethodID( - env, valueTypeCalss, PARSE_TYPE, INT_VALUETYPE); + jmethodID jmethodId = + (*env)->GetStaticMethodID(env, valueTypeCalss, PARSE_TYPE, INT_VALUETYPE); if (jmethodId == NULL) { return NULL; @@ -101,7 +101,8 @@ jobject ConvertToValueTypeList(JNIEnv *env, enum WasmEdge_ValType *list, return NULL; } - jmethodID listConstructor = findJavaMethod(env, listClass, DEFAULT_CONSTRUCTOR, INT_VOID); + jmethodID listConstructor = + findJavaMethod(env, listClass, DEFAULT_CONSTRUCTOR, INT_VOID); if (listConstructor == NULL) { return NULL; @@ -212,19 +213,18 @@ jobject ConvertToJavaFunctionType( return NULL; } - jmethodID constructor = findJavaMethod(env, functionTypeClass, DEFAULT_CONSTRUCTOR, - LISTLIST_VOID); + jmethodID constructor = findJavaMethod(env, functionTypeClass, + DEFAULT_CONSTRUCTOR, LISTLIST_VOID); jobject jFunc = (*env)->NewObject(env, functionTypeClass, constructor, jParamList, jReturnList); - if (checkAndHandleException(env, - ERROR_CREATE_FUNCTION_TYPE_FAILED)) { + if (checkAndHandleException(env, ERROR_CREATE_FUNCTION_TYPE_FAILED)) { return NULL; } - jmethodID nameSetter = (*env)->GetMethodID(env, functionTypeClass, SET_NAME, - STRING_VOID); + jmethodID nameSetter = + (*env)->GetMethodID(env, functionTypeClass, SET_NAME, STRING_VOID); uint32_t len = 256; char BUF[len]; @@ -233,8 +233,7 @@ jobject ConvertToJavaFunctionType( (*env)->CallVoidMethod(env, jFunc, nameSetter, jstr); - if (checkAndHandleException( - env, ERR_SET_FUNCTION_TYPE_FAILED)) { + if (checkAndHandleException(env, ERR_SET_FUNCTION_TYPE_FAILED)) { return NULL; } @@ -245,7 +244,8 @@ jobject createJFunctionTypeContext( JNIEnv *env, const WasmEdge_FunctionTypeContext *functionTypeContext) { jclass clazz = (*env)->FindClass(env, ORG_WASMEDGE_FUNCTIONTYPECONTEXT); - jmethodID constructorId = (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); + jmethodID constructorId = + (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); return (*env)->NewObject(env, clazz, constructorId, (long)functionTypeContext); } diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeContext.h index 3831dbdc3129..b7d7c19e2441 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_FUNCTIONTYPECONTEXT_H #define WASMEDGE_JAVA_FUNCTIONTYPECONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeInstance.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeInstance.c index 71f223d325ad..8e3fc615431f 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeInstance.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeInstance.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "FunctionTypeInstance.h" #include "FunctionTypeContext.h" @@ -24,17 +24,16 @@ WasmEdge_Result HostFuncWrap(void *This, void *Data, jstring jFuncKey = (*env)->NewStringUTF(env, funcKey); jclass clazz = (*env)->FindClass(env, ORG_WASMEDGE_WASMEDGEVM); - jmethodID funcGetter = (*env)->GetStaticMethodID( - env, clazz, GET_HOST_FUNC, STRING_HOSTFUNCTION); + jmethodID funcGetter = + (*env)->GetStaticMethodID(env, clazz, GET_HOST_FUNC, STRING_HOSTFUNCTION); jobject jFunc = (*env)->CallStaticObjectMethod(env, clazz, funcGetter, jFuncKey); jclass jFuncClass = (*env)->GetObjectClass(env, jFunc); - jmethodID funcMethod = - (*env)->GetMethodID(env, jFuncClass, APPLY, - MEMORYINSTANCECONTEXTLIST_RESULT); + jmethodID funcMethod = (*env)->GetMethodID(env, jFuncClass, APPLY, + MEMORYINSTANCECONTEXTLIST_RESULT); // TODO replace with CallingFrameContext jobject jMem = @@ -97,7 +96,8 @@ jobject createJFunctionInstanceContext( } jclass clazz = (*env)->FindClass(env, ORG_WASMEDGE_FUNCTIONINSTANCECONTEXT); - jmethodID constructorId = (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); + jmethodID constructorId = + (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); return (*env)->NewObject(env, clazz, constructorId, (long)funcInstance); } @@ -106,4 +106,4 @@ GetReturnLen(WasmEdge_FunctionInstanceContext *functionInstanceContext) { const WasmEdge_FunctionTypeContext *type = WasmEdge_FunctionInstanceGetFunctionType(functionInstanceContext); return WasmEdge_FunctionTypeGetReturnsLength(type); -} \ No newline at end of file +} diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeInstance.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeInstance.h index 50807bcac343..0c32b35e9140 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeInstance.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/FunctionTypeInstance.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_FUNCTIONTYPEINSTANCE_H #define WASMEDGE_JAVA_FUNCTIONTYPEINSTANCE_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalInstanceContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalInstanceContext.c index b184a5a6ada5..dcbd34e1e246 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalInstanceContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalInstanceContext.c @@ -2,7 +2,7 @@ // Created by Kenvi Zhu on 2022-01-12. // // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_GlobalInstanceContext.h" #include "GlobalTypeContext.h" @@ -32,8 +32,8 @@ JNIEXPORT void JNICALL Java_org_wasmedge_GlobalInstanceContext_nativeSetValue( WasmEdge_GlobalInstanceSetValue(globalInstanceContext, value); } -JNIEXPORT void JNICALL Java_org_wasmedge_GlobalInstanceContext_close( - JNIEnv *env, jobject thisObject) { +JNIEXPORT void JNICALL +Java_org_wasmedge_GlobalInstanceContext_close(JNIEnv *env, jobject thisObject) { WasmEdge_GlobalInstanceContext *globalInstanceContext = getGlobalInstanceContext(env, thisObject); WasmEdge_GlobalInstanceDelete(globalInstanceContext); @@ -48,6 +48,7 @@ jobject createJGlobalInstanceContext( } jclass clazz = (*env)->FindClass(env, ORG_WASMEDGE_GLOBALINSTANCECONTEXT); - jmethodID constructorId = (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); + jmethodID constructorId = + (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); return (*env)->NewObject(env, clazz, constructorId, (long)globInstance); } diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalInstanceContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalInstanceContext.h index 887e1b09b13d..4c9355d46379 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalInstanceContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalInstanceContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_GLOBALINSTANCECONTEXT_H #define WASMEDGE_JAVA_GLOBALINSTANCECONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalTypeContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalTypeContext.c index 3b2e2b012319..b9aeff70652b 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalTypeContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalTypeContext.c @@ -1,7 +1,7 @@ // // Created by Kenvi Zhu on 2021-12-07. // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_GlobalTypeContext.h" #include "common.h" @@ -22,7 +22,8 @@ createJGlobalTypeContext(JNIEnv *env, const WasmEdge_GlobalTypeContext *globalTypeContext) { jclass clazz = (*env)->FindClass(env, ORG_WASMEDGE_GLOBALTYPECONTEXT); - jmethodID constructorId = (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); + jmethodID constructorId = + (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); return (*env)->NewObject(env, clazz, constructorId, (long)globalTypeContext); } JNIEXPORT void JNICALL @@ -41,4 +42,4 @@ JNIEXPORT jint JNICALL Java_org_wasmedge_GlobalTypeContext_nativeGetMutability( JNIEnv *env, jobject thisObject) { return WasmEdge_GlobalTypeGetMutability( getGlobalTypeContext(env, thisObject)); -} \ No newline at end of file +} diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalTypeContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalTypeContext.h index 9ecc673d7ab0..26f7dc358fc9 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalTypeContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/GlobalTypeContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_GLOBALTYPECONTEXT_H #define WASMEDGE_JAVA_GLOBALTYPECONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/ImportTypeContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/ImportTypeContext.c index e19b3d0fb386..44b9b9d7162c 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/ImportTypeContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/ImportTypeContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "ImportTypeContext.h" #include "AstModuleContext.h" diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/ImportTypeContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/ImportTypeContext.h index 1c3dcf96332f..e80679518fe0 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/ImportTypeContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/ImportTypeContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_IMPORTTYPECONTEXT_H #define WASMEDGE_JAVA_IMPORTTYPECONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/LoaderContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/LoaderContext.c index 248959186a80..ceaaddd207d5 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/LoaderContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/LoaderContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni//org_wasmedge_LoaderContext.h" #include "AstModuleContext.h" diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryInstanceContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryInstanceContext.c index 26a56d5ae52b..d2f71ee68593 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryInstanceContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryInstanceContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_MemoryInstanceContext.h" #include "MemoryTypeContext.h" @@ -81,8 +81,8 @@ JNIEXPORT void JNICALL Java_org_wasmedge_MemoryInstanceContext_growPage( handleWasmEdgeResult(env, &result); } -JNIEXPORT void JNICALL Java_org_wasmedge_MemoryInstanceContext_close( - JNIEnv *env, jobject thisObject) { +JNIEXPORT void JNICALL +Java_org_wasmedge_MemoryInstanceContext_close(JNIEnv *env, jobject thisObject) { WasmEdge_MemoryInstanceDelete(getMemoryInstanceContext(env, thisObject)); setPointer(env, thisObject, 0); } @@ -96,6 +96,7 @@ jobject createJMemoryInstanceContext( } jclass clazz = (*env)->FindClass(env, ORG_WASMEDGE_MEMORYINSTANCECONTEXT); - jmethodID constructorId = (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); + jmethodID constructorId = + (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); return (*env)->NewObject(env, clazz, constructorId, (long)memInstance); } diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryInstanceContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryInstanceContext.h index 5c88a1c4630f..dd97e2f8bbcf 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryInstanceContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryInstanceContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_MEMORYINSTANCECONTEXT_H #define WASMEDGE_JAVA_MEMORYINSTANCECONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryTypeContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryTypeContext.c index e260942cdfda..d8fcca40ab61 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryTypeContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryTypeContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_MemoryTypeContext.h" #include "common.h" @@ -30,7 +30,8 @@ createJMemoryTypeContext(JNIEnv *env, jclass clazz = (*env)->FindClass(env, ORG_WASMEDGE_MEMORYTYPECONTEXT); - jmethodID constructorId = (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); + jmethodID constructorId = + (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); return (*env)->NewObject(env, clazz, constructorId, (long)memTypeContext); } @@ -44,7 +45,8 @@ Java_org_wasmedge_MemoryTypeContext_getLimit(JNIEnv *env, jobject thisObject) { jclass limitClass = findJavaClass(env, ORG_WASMEDGE_LIMIT); - jmethodID constructor = findJavaMethod(env, limitClass, DEFAULT_CONSTRUCTOR, BOOLLONGLONG_VOID); + jmethodID constructor = + findJavaMethod(env, limitClass, DEFAULT_CONSTRUCTOR, BOOLLONGLONG_VOID); return (*env)->NewObject(env, limitClass, constructor, (jboolean)limit.HasMax, (jlong)limit.Min, (jlong)limit.Max); diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryTypeContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryTypeContext.h index be225f7e97cc..3b2ab4efda7e 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryTypeContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/MemoryTypeContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_MEMORYTYPECONTEXT_H #define WASMEDGE_JAVA_MEMORYTYPECONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/ModuleInstanceContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/ModuleInstanceContext.c index da783edc806a..6b107e78fb6b 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/ModuleInstanceContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/ModuleInstanceContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "FunctionTypeInstance.h" #include "GlobalInstanceContext.h" @@ -90,8 +90,8 @@ JNIEXPORT void JNICALL Java_org_wasmedge_ModuleInstanceContext_addGlobal( impObjCxt, JStringToWasmString(env, jGlobalName), globalInstance); } -JNIEXPORT void JNICALL Java_org_wasmedge_ModuleInstanceContext_close( - JNIEnv *env, jobject thisObject) { +JNIEXPORT void JNICALL +Java_org_wasmedge_ModuleInstanceContext_close(JNIEnv *env, jobject thisObject) { WasmEdge_ModuleInstanceContext *impObjCxt = getModuleInstanceContext(env, thisObject); WasmEdge_ModuleInstanceDelete(impObjCxt); @@ -254,7 +254,8 @@ createJModuleInstanceContext(JNIEnv *env, jclass clazz = (*env)->FindClass(env, ORG_WASMEDGE_MODULEINSTANCECONTEXT); - jmethodID constructorId = (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); + jmethodID constructorId = + (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); return (*env)->NewObject(env, clazz, constructorId, (long)impObj); } diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/ModuleInstanceContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/ModuleInstanceContext.h index 5c248c8b3241..3b89b601f04c 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/ModuleInstanceContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/ModuleInstanceContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_MODULEINSTANCECONTEXT_H #define WASMEDGE_JAVA_MODULEINSTANCECONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/StatisticsContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/StatisticsContext.c index 43b49245c3a3..4e168901d2ca 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/StatisticsContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/StatisticsContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_StatisticsContext.h" #include "common.h" @@ -14,7 +14,8 @@ CreateJavaStatisticsContext(JNIEnv *env, WasmEdge_StatisticsContext *statisticsContext) { jclass statClass = findJavaClass(env, ORG_WASMEDGE_STATISTICSCONTEXT); - jmethodID constructor = (*env)->GetMethodID(env, statClass, DEFAULT_CONSTRUCTOR, LONG_VOID); + jmethodID constructor = + (*env)->GetMethodID(env, statClass, DEFAULT_CONSTRUCTOR, LONG_VOID); jobject jStatContext = (*env)->NewObject(env, statClass, constructor, (long)statisticsContext); diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/StatisticsContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/StatisticsContext.h index 4e4b07fe3ec0..4b374befce46 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/StatisticsContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/StatisticsContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_STATISTICSCONTEXT_H #define WASMEDGE_JAVA_STATISTICSCONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/StoreContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/StoreContext.c index 395d362b7dde..4e361a91c073 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/StoreContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/StoreContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "FunctionTypeInstance.h" #include "GlobalInstanceContext.h" @@ -32,7 +32,7 @@ jobject CreateJavaStoreContext(JNIEnv *env, } JNIEXPORT void JNICALL Java_org_wasmedge_StoreContext_close(JNIEnv *env, - jobject thisObj) { + jobject thisObj) { WasmEdge_StoreDelete(getStoreContext(env, thisObj)); } diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/StoreContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/StoreContext.h index 82ea9625dd4a..794bd18c884f 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/StoreContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/StoreContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_STORECONTEXT_H #define WASMEDGE_JAVA_STORECONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/TableInstanceContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/TableInstanceContext.c index ddb2511a4758..fd14bc36694c 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/TableInstanceContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/TableInstanceContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_GlobalInstanceContext.h" #include "TableTypeContext.h" @@ -42,7 +42,8 @@ JNIEXPORT jobject JNICALL Java_org_wasmedge_TableInstanceContext_getData( getTableInstanceContext(env, thisObject); jclass typeClass = (*env)->GetObjectClass(env, jValType); - jmethodID typeGetter = (*env)->GetMethodID(env, typeClass, GET_VALUE, VOID_INT); + jmethodID typeGetter = + (*env)->GetMethodID(env, typeClass, GET_VALUE, VOID_INT); jint valType = (*env)->CallIntMethod(env, jValType, typeGetter); @@ -99,6 +100,7 @@ createJTableInstanceContext(JNIEnv *env, } jclass clazz = (*env)->FindClass(env, ORG_WASMEDGE_TABLEINSTANCECONTEXT); - jmethodID constructorId = (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); + jmethodID constructorId = + (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); return (*env)->NewObject(env, clazz, constructorId, (long)tabInstance); } diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/TableInstanceContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/TableInstanceContext.h index 424310fdd280..dce459eb9fd2 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/TableInstanceContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/TableInstanceContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_TABLEINSTANCECONTEXT_H #define WASMEDGE_JAVA_TABLEINSTANCECONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/TableTypeContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/TableTypeContext.c index 8a98d7bfde9d..4c7216b4214d 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/TableTypeContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/TableTypeContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_TableTypeContext.h" #include "common.h" @@ -12,7 +12,8 @@ JNIEXPORT void JNICALL Java_org_wasmedge_TableTypeContext_nativeInit( jclass cls = (*env)->GetObjectClass(env, jLimit); - jmethodID hasMaxMid = (*env)->GetMethodID(env, cls, LIMIT_IS_HAS_MAX, VOID_BOOL); + jmethodID hasMaxMid = + (*env)->GetMethodID(env, cls, LIMIT_IS_HAS_MAX, VOID_BOOL); jboolean hasMax = (*env)->CallBooleanMethod(env, jLimit, hasMaxMid); jmethodID maxMid = (*env)->GetMethodID(env, cls, LIMIT_GET_MAX, VOID_LONG); @@ -36,7 +37,8 @@ Java_org_wasmedge_TableTypeContext_getLimit(JNIEnv *env, jobject thisObject) { jclass limitClass = findJavaClass(env, ORG_WASMEDGE_LIMIT); - jmethodID constructor = findJavaMethod(env, limitClass, DEFAULT_CONSTRUCTOR, BOOLLONGLONG_VOID); + jmethodID constructor = + findJavaMethod(env, limitClass, DEFAULT_CONSTRUCTOR, BOOLLONGLONG_VOID); return (*env)->NewObject(env, limitClass, constructor, (jboolean)limit.HasMax, (jlong)limit.Min, (jlong)limit.Max); @@ -63,7 +65,8 @@ createJTableTypeContext(JNIEnv *env, jclass clazz = (*env)->FindClass(env, ORG_WASMEDGE_TABLETYPECONTEXT); - jmethodID constructorId = (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); + jmethodID constructorId = + (*env)->GetMethodID(env, clazz, DEFAULT_CONSTRUCTOR, LONG_VOID); jobject table = (*env)->NewObject(env, clazz, constructorId, (long)tableTypeContext); diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/TableTypeContext.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/TableTypeContext.h index f0868e4e0517..8cc818de1ee2 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/TableTypeContext.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/TableTypeContext.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_TABLETYPECONTEXT_H #define WASMEDGE_JAVA_TABLETYPECONTEXT_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/ValidatorContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/ValidatorContext.c index 42c889274627..8f0cbb281f98 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/ValidatorContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/ValidatorContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_ValidatorContext.h" #include "AstModuleContext.h" @@ -36,4 +36,4 @@ Java_org_wasmedge_ValidatorContext_close(JNIEnv *env, jobject thisObject) { WasmEdge_ValidatorContext *validatorContext = getValidatorContext(env, thisObject); WasmEdge_ValidatorDelete(validatorContext); -} \ No newline at end of file +} diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/ValueType.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/ValueType.c index 9ca47ec211c3..1c6d94dc91af 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/ValueType.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/ValueType.c @@ -1,57 +1,56 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC -#include <string.h> #include "common.h" #include "jni.h" #include "wasmedge/wasmedge.h" +#include <string.h> -__int128_t atoint128_t(const char *s) -{ - const char *p = s; - __int128_t val = 0; +__int128_t atoint128_t(const char *s) { + const char *p = s; + __int128_t val = 0; - if (*p == '-' || *p == '+') { - p++; - } - while (*p >= '0' && *p <= '9') { - val = (10 * val) + (*p - '0'); - p++; - } - if (*s == '-') val = val * -1; - return val; + if (*p == '-' || *p == '+') { + p++; + } + while (*p >= '0' && *p <= '9') { + val = (10 * val) + (*p - '0'); + p++; + } + if (*s == '-') + val = val * -1; + return val; } -char* u128toa(uint128_t n) { - static char buf[40]; - unsigned int i, j, m = 39; - memset(buf, 0, 40); - for (i = 128; i-- > 0;) { - int carry = !!(n & ((uint128_t)1 << i)); - for (j = 39; j-- > m + 1 || carry;) { - int d = 2 * buf[j] + carry; - carry = d > 9; - buf[j] = carry ? d - 10 : d; - } - m = j; +char *u128toa(uint128_t n) { + static char buf[40]; + unsigned int i, j, m = 39; + memset(buf, 0, 40); + for (i = 128; i-- > 0;) { + int carry = !!(n & ((uint128_t)1 << i)); + for (j = 39; j-- > m + 1 || carry;) { + int d = 2 * buf[j] + carry; + carry = d > 9; + buf[j] = carry ? d - 10 : d; } - for (i = 0; i < 38; i++) { - if (buf[i]) { - break; - } - } - for (j = i; j < 39; j++) { - buf[j] += '0'; + m = j; + } + for (i = 0; i < 38; i++) { + if (buf[i]) { + break; } - return buf + i; - + } + for (j = i; j < 39; j++) { + buf[j] += '0'; + } + return buf + i; } WasmEdge_Value JavaValueToWasmEdgeValue(JNIEnv *env, jobject jVal) { jclass valueClass = (*env)->FindClass(env, ORG_WASMEDGE_VALUE); - jmethodID getType = (*env)->GetMethodID(env, valueClass, GET_TYPE, - VOID_VALUETYPE); + jmethodID getType = + (*env)->GetMethodID(env, valueClass, GET_TYPE, VOID_VALUETYPE); jobject valType = (*env)->CallObjectMethod(env, jVal, getType); @@ -111,11 +110,11 @@ jobject WasmEdgeValueToJavaValue(JNIEnv *env, WasmEdge_Value value) { } jclass valClass = (*env)->FindClass(env, valClassName); - jmethodID constructor = (*env)->GetMethodID(env, valClass, DEFAULT_CONSTRUCTOR, VOID_VOID); + jmethodID constructor = + (*env)->GetMethodID(env, valClass, DEFAULT_CONSTRUCTOR, VOID_VOID); jobject jVal = (*env)->NewObject(env, valClass, constructor); setJavaValueObject(env, value, jVal); return jVal; } - diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/ValueType.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/ValueType.h index 3f7e6f43a5d3..78292b0785f1 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/ValueType.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/ValueType.h @@ -1,11 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_VALUETYPE_H #define WASMEDGE_JAVA_VALUETYPE_H WasmEdge_Value JavaValueToWasmEdgeValue(JNIEnv *env, jobject jVal); jobject WasmEdgeValueToJavaValue(JNIEnv *env, WasmEdge_Value value); -char* u128toa(uint128_t n); +char *u128toa(uint128_t n); #endif // WASMEDGE_JAVA_VALUETYPE_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/VmContext.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/VmContext.c index 525752cacf11..109e99244f26 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/VmContext.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/VmContext.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "../jni/org_wasmedge_VMContext.h" #include "ConfigureContext.h" @@ -19,4 +19,4 @@ JNIEXPORT void JNICALL Java_org_wasmedge_VMContext_initNative( WasmEdge_VMCreate(ConfigureContext, StoreContext); setPointer(env, jVmContext, (jlong)VMContext); -} \ No newline at end of file +} diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/WasmEdge.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/WasmEdge.c index 773644c4ba72..ec09e724d49b 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/WasmEdge.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/WasmEdge.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "wasmedge/wasmedge.h" #include "jni.h" @@ -41,4 +41,4 @@ Java_org_wasmedge_WasmEdge_setErrorLevel(JNIEnv *env, jobject thisObject) { JNIEXPORT void JNICALL Java_org_wasmedge_WasmEdge_setDebugLevel(JNIEnv *env, jobject thisObject) { WasmEdge_LogSetDebugLevel(); -} \ No newline at end of file +} diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/WasmEdgeVM.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/WasmEdgeVM.c index 657dd2a667f2..e533e4120664 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/WasmEdgeVM.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/WasmEdgeVM.c @@ -1,13 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "AstModuleContext.h" +#include "Async.h" #include "ConfigureContext.h" #include "FunctionTypeContext.h" #include "ModuleInstanceContext.h" #include "StatisticsContext.h" #include "StoreContext.h" -#include "Async.h" #include "common.h" #include "jni.h" #include "string.h" @@ -16,7 +16,6 @@ #include <stdio.h> #include <stdlib.h> - void setJavaIntValue(JNIEnv *env, WasmEdge_Value val, jobject jobj) { int int_val = WasmEdge_ValueGetI32(val); jclass val_clazz = (*env)->GetObjectClass(env, jobj); @@ -49,7 +48,7 @@ void setJavaDoubleValue(JNIEnv *env, WasmEdge_Value val, jobject jobj) { (*env)->CallFloatMethod(env, jobj, val_setter, double_val); } -void setJavaStringValue(JNIEnv *env, char* val, jobject jobj) { +void setJavaStringValue(JNIEnv *env, char *val, jobject jobj) { jclass val_clazz = (*env)->GetObjectClass(env, jobj); jmethodID val_setter = @@ -123,8 +122,7 @@ JNIEXPORT void JNICALL Java_org_wasmedge_WasmEdgeVm_runWasmFromFile( } } else { char exceptionBuffer[1024]; - sprintf(exceptionBuffer, - ERR_RUN_FROM_FILE_TEMPLATE, c_file_path, + sprintf(exceptionBuffer, ERR_RUN_FROM_FILE_TEMPLATE, c_file_path, WasmEdge_ResultGetMessage(Res)); (*env)->ThrowNew(env, (*env)->FindClass(env, JAVA_LANG_EXCEPTION), @@ -242,7 +240,7 @@ JNIEXPORT void JNICALL Java_org_wasmedge_WasmEdgeVm_execute( } JNIEXPORT void JNICALL Java_org_wasmedge_WasmEdgeVm_close(JNIEnv *env, - jobject thisObj) { + jobject thisObj) { WasmEdge_VMDelete(getVmContext(env, thisObj)); } @@ -833,4 +831,4 @@ JNIEXPORT jobject JNICALL Java_org_wasmedge_WasmEdgeVm_asyncExecuteRegistered( vmContext, wModName, wFuncName, wasm_params, paramLen); return createJAsyncObject(env, async); -} \ No newline at end of file +} diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/common.c b/bindings/java/wasmedge-java/wasmedge-jni/lib/common.c index 9c83ff0a456e..b09fd40e588d 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/common.c +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/common.c @@ -1,10 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common.h" +#include "ValueType.h" #include "jni.h" #include "wasmedge/wasmedge.h" -#include "ValueType.h" #include <stdlib.h> #include <string.h> @@ -67,8 +67,7 @@ void getClassName(JNIEnv *env, jobject obj, char *buff) { jclass cls = (*env)->GetObjectClass(env, obj); // First get the class object - jmethodID mid = - (*env)->GetMethodID(env, cls, GET_CLASS, VOID_CLASS); + jmethodID mid = (*env)->GetMethodID(env, cls, GET_CLASS, VOID_CLASS); jobject clsObj = (*env)->CallObjectMethod(env, obj, mid); checkAndHandleException(env, ERR_GET_CLASS_NAME); @@ -116,8 +115,7 @@ void setPointer(JNIEnv *env, jobject obj, long val) { void handleWasmEdgeResult(JNIEnv *env, WasmEdge_Result *result) { if (!WasmEdge_ResultOK(*result)) { char exceptionBuffer[1024]; - sprintf(exceptionBuffer, ERR_TEMPLATE, - WasmEdge_ResultGetMessage(*result)); + sprintf(exceptionBuffer, ERR_TEMPLATE, WasmEdge_ResultGetMessage(*result)); (*env)->ThrowNew(env, (*env)->FindClass(env, JAVA_LANG_EXCEPTION), exceptionBuffer); @@ -158,8 +156,7 @@ double getDoubleVal(JNIEnv *env, jobject val) { char *getStringVal(JNIEnv *env, jobject val) { jclass clazz = (*env)->GetObjectClass(env, val); - jmethodID methodId = - findJavaMethod(env, clazz, GET_VALUE, VOID_STRING); + jmethodID methodId = findJavaMethod(env, clazz, GET_VALUE, VOID_STRING); jstring value = (jstring)(*env)->CallObjectMethod(env, val, methodId); @@ -194,8 +191,7 @@ bool checkAndHandleException(JNIEnv *env, const char *msg) { jclass eclass = (*env)->GetObjectClass(env, e); - jmethodID mid = - (*env)->GetMethodID(env, eclass, TO_STRING, VOID_STRING); + jmethodID mid = (*env)->GetMethodID(env, eclass, TO_STRING, VOID_STRING); jstring jErrorMsg = (*env)->CallObjectMethod(env, e, mid); const char *cMsg = (*env)->GetStringUTFChars(env, jErrorMsg, NULL); @@ -211,7 +207,7 @@ bool checkAndHandleException(JNIEnv *env, const char *msg) { } void setJavaValueObject(JNIEnv *env, WasmEdge_Value value, jobject j_val) { - char* str_val; + char *str_val; switch (value.Type) { case WasmEdge_ValType_I32: setJavaIntValue(env, value, j_val); @@ -256,7 +252,8 @@ jobject CreateJavaArrayList(JNIEnv *env, jint len) { return NULL; } - jmethodID listConstructor = findJavaMethod(env, listClass, DEFAULT_CONSTRUCTOR, INT_VOID); + jmethodID listConstructor = + findJavaMethod(env, listClass, DEFAULT_CONSTRUCTOR, INT_VOID); if (listConstructor == NULL) { return NULL; @@ -289,8 +286,7 @@ bool AddElementToJavaList(JNIEnv *env, jobject jList, jobject ele) { jobject GetListElement(JNIEnv *env, jobject jList, jint idx) { jclass listClass = (*env)->GetObjectClass(env, jList); - jmethodID getMethod = - findJavaMethod(env, listClass, GET, INT_OBJECT); + jmethodID getMethod = findJavaMethod(env, listClass, GET, INT_OBJECT); return (*env)->CallObjectMethod(env, jList, getMethod, idx); } @@ -298,7 +294,8 @@ jobject GetListElement(JNIEnv *env, jobject jList, jint idx) { jint GetListSize(JNIEnv *env, jobject jList) { jclass listClass = (*env)->GetObjectClass(env, jList); - jmethodID sizeMethod = (*env)->GetMethodID(env, listClass, LIST_SIZE, VOID_INT); + jmethodID sizeMethod = + (*env)->GetMethodID(env, listClass, LIST_SIZE, VOID_INT); jint size = (*env)->CallIntMethod(env, jList, sizeMethod); return size; @@ -349,4 +346,3 @@ jobject WasmEdgeStringArrayToJavaList(JNIEnv *env, WasmEdge_String *wStrList, } return strList; } - diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/common.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/common.h index 65386c3b78ea..ab41fb5ca5d9 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/common.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/common.h @@ -1,16 +1,15 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_COMMON_H #define WASMEDGE_JAVA_COMMON_H +#include "constants.h" #include "jni.h" #include "wasmedge/wasmedge.h" -#include "constants.h" #define MAX_BUF_LEN 1024 - enum ErrorCode { JVM_ERROR, WVM_ERROR }; void exitWithError(enum ErrorCode error, char *message); @@ -50,7 +49,7 @@ void setJavaFloatValue(JNIEnv *env, WasmEdge_Value val, jobject jobj); void setJavaDoubleValue(JNIEnv *env, WasmEdge_Value val, jobject jobj); -void setJavaStringValue(JNIEnv *env, char* val, jobject jobj); +void setJavaStringValue(JNIEnv *env, char *val, jobject jobj); enum WasmEdge_ValType *parseValueTypes(JNIEnv *env, jintArray jValueTypes); @@ -77,12 +76,12 @@ jobject GetListElement(JNIEnv *env, jobject jList, jint idx); jint GetListSize(JNIEnv *env, jobject jList); -#define GETTER(NAME) WasmEdge_ ## NAME *get ## NAME(JNIEnv *env,\ - jobject j ## NAME) {\ - if (j ## NAME == NULL) {\ - return NULL;\ - }\ - return (WasmEdge_ ##NAME *)getPointer(env, j ##NAME );\ -} \ +#define GETTER(NAME) \ + WasmEdge_##NAME *get##NAME(JNIEnv *env, jobject j##NAME) { \ + if (j##NAME == NULL) { \ + return NULL; \ + } \ + return (WasmEdge_##NAME *)getPointer(env, j##NAME); \ + } #endif // WASMEDGE_JAVA_COMMON_H diff --git a/bindings/java/wasmedge-java/wasmedge-jni/lib/constants.h b/bindings/java/wasmedge-java/wasmedge-jni/lib/constants.h index 76150fd89f16..feabe5322308 100644 --- a/bindings/java/wasmedge-java/wasmedge-jni/lib/constants.h +++ b/bindings/java/wasmedge-java/wasmedge-jni/lib/constants.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifndef WASMEDGE_JAVA_CONSTANTS_H #define WASMEDGE_JAVA_CONSTANTS_H @@ -13,7 +13,8 @@ #define ORG_WASMEDGE_GLOBALINSTANCECONTEXT "org/wasmedge/GlobalInstanceContext" #define ORG_WASMEDGE_MODULEINSTANCECONTEXT "org/wasmedge/ModuleInstanceContext" #define ORG_WASMEDGE_WASMEDGEVM "org/wasmedge/WasmEdgeVm" -#define ORG_WASMEDGE_FUNCTIONINSTANCECONTEXT "org/wasmedge/FunctionInstanceContext" +#define ORG_WASMEDGE_FUNCTIONINSTANCECONTEXT \ + "org/wasmedge/FunctionInstanceContext" #define ORG_WASMEDGE_TABLEINSTANCECONTEXT "org/wasmedge/TableInstanceContext" #define ORG_WASMEDGE_ASYNC "org/wasmedge/Async" #define ORG_WASMEDGE_ASTMODULECONTEXT "org/wasmedge/AstModuleContext" @@ -83,7 +84,9 @@ #define BOOLLONGLONG_VOID "(ZJJ)V" #define ASTMODULECONTEXT_VOID "(JLorg/wasmedge/AstModuleContext;)V" #define STRING_HOSTFUNCTION "(Ljava/lang/String;)Lorg/wasmedge/HostFunction;" -#define MEMORYINSTANCECONTEXTLIST_RESULT "(Lorg/wasmedge/MemoryInstanceContext;Ljava/util/List;Ljava/util/List;)Lorg/wasmedge/Result;" +#define MEMORYINSTANCECONTEXTLIST_RESULT \ + "(Lorg/wasmedge/MemoryInstanceContext;Ljava/util/List;Ljava/util/" \ + "List;)Lorg/wasmedge/Result;" #define OBJECT_BOOL "(Ljava/lang/Object;)Z" #define LISTLIST_VOID "(Ljava/util/List;Ljava/util/List;)V" #define INT_OBJECT "(I)Ljava/lang/Object;" @@ -103,11 +106,14 @@ #define ERR_GET_INT_VALUE "Error get int value" #define ERR_CREATE_JAVA_LIST "Error when creating java list" #define ERR_GET_NAME_FALIED "get name error" -#define ERR_RUN_FROM_FILE_TEMPLATE "Error running wasm from file %s, error message: %s." +#define ERR_RUN_FROM_FILE_TEMPLATE \ + "Error running wasm from file %s, error message: %s." #define ERR_CREATE_VALUE_TYPE_LIST_FAILED "Error when creating value type list" #define ERR_ADD_VALUE_TYPE "Error when adding value type" -#define ERROR_CREATE_FUNCTION_TYPE_FAILED "Error when creating function type context" -#define ERR_SET_FUNCTION_TYPE_FAILED "Error when setting function type context name" +#define ERROR_CREATE_FUNCTION_TYPE_FAILED \ + "Error when creating function type context" +#define ERR_SET_FUNCTION_TYPE_FAILED \ + "Error when setting function type context name" #define ERR_CREATE_STATICS_CONTEXT_FAILED "error creating stat context" #endif diff --git a/cmake/0001-support-arithmetic-operations-in-uint128_fallback.patch b/cmake/0001-support-arithmetic-operations-in-uint128_fallback.patch new file mode 100644 index 000000000000..9f60c968f7b1 --- /dev/null +++ b/cmake/0001-support-arithmetic-operations-in-uint128_fallback.patch @@ -0,0 +1,201 @@ +From 707dc7d2fe66629aeea8ac1afac7e26372245193 Mon Sep 17 00:00:00 2001 +From: Shen-Ta Hsieh <ibmibmibm.tw@gmail.com> +Date: Thu, 29 Aug 2024 17:08:27 +0800 +Subject: [PATCH] support arithmetic operations in uint128_fallback + +--- + include/fmt/format.h | 154 ++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 151 insertions(+), 3 deletions(-) + +diff --git a/include/fmt/format.h b/include/fmt/format.h +index 67f0ab7..629c9a4 100644 +--- a/include/fmt/format.h ++++ b/include/fmt/format.h +@@ -317,6 +317,65 @@ inline auto is_big_endian() -> bool { + #endif + } + ++FMT_CONSTEXPR20 inline auto countl_zero(uint32_t n) -> int; ++FMT_CONSTEXPR20 inline auto udiv128by64to64(uint64_t u1, uint64_t u0, uint64_t v, uint64_t &r) { ++ if (!is_constant_evaluated()) { ++#if FMT_MSC_VERSION && !FMT_CLANG_VERSION && defined(_M_X64) ++ return _udiv128(u1, u0, v, &r); ++#elif defined(__x86_64__) ++ uint64_t result = 0; ++ __asm__("divq %[v]" : "=a"(result), "=d"(r) : [v]"r"(v), "a"(u0), "d"(u1)); ++ return result; ++#endif ++ } ++ const uint32_t v0 = static_cast<uint32_t>(v); ++ const uint32_t v1 = static_cast<uint32_t>(v >> 32); ++ if (v1 == 0) { ++ auto rem = (u1 << 32) | (u0 >> 32); ++ auto result = rem / v0; ++ rem = ((rem % v0) << 32) | static_cast<uint32_t>(u0); ++ result = (result << 32) | (rem / v0); ++ r = rem % v0; ++ return result; ++ } ++ uint64_t un64 = 0, un10 = 0; ++ const auto s = countl_zero(v1); ++ if (s > 0) { ++ v <<= s; ++ un64 = (u1 << s) | (u0 >> (64 - s)); ++ un10 = u0 << s; ++ } else { ++ un64 = u1; ++ un10 = u0; ++ } ++ uint64_t vn1 = static_cast<uint32_t>(v >> 32); ++ uint64_t vn0 = static_cast<uint32_t>(v); ++ uint64_t un1 = static_cast<uint32_t>(un10 >> 32); ++ uint64_t un0 = static_cast<uint32_t>(un10); ++ uint64_t q1 = un64 / vn1; ++ uint64_t rhat = un64 - q1 * vn1; ++ while ((q1 >> 32) >= 1 || q1 * vn0 > (rhat << 32) + un1) { ++ --q1; ++ rhat += vn1; ++ if ((rhat >> 32) >= 1) { ++ break; ++ } ++ } ++ ++ uint64_t un21 = (un64 << 32) + un1 - q1 * v; ++ uint64_t q0 = un21 / vn1; ++ rhat = un21 - q0 * vn1; ++ while ((q0 >> 32) >= 1 || q0 * vn0 > (rhat << 32) + un0) { ++ --q0; ++ rhat += vn1; ++ if ((rhat >> 32) >= 1) { ++ break; ++ } ++ } ++ r = ((un21 << 32) + un0 - q0 * v) >> s; ++ return (q1 << 32) + q0; ++} ++ + class uint128_fallback { + private: + uint64_t lo_, hi_; +@@ -345,6 +404,18 @@ class uint128_fallback { + const uint128_fallback& rhs) -> bool { + return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_; + } ++ friend constexpr auto operator<(const uint128_fallback& lhs, ++ int rhs) -> bool { ++ return rhs >= 0 && lhs.hi_ == 0 && lhs.lo_ < static_cast<unsigned int>(rhs); ++ } ++ friend constexpr auto operator<(const uint128_fallback& lhs, ++ const uint128_fallback& rhs) -> bool { ++ return lhs.hi_ < rhs.hi_ || (lhs.hi_ == rhs.hi_ && lhs.lo_ < rhs.lo_); ++ } ++ friend constexpr auto operator>=(const uint128_fallback& lhs, ++ int rhs) -> bool { ++ return !(lhs < rhs); ++ } + friend constexpr auto operator|(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { +@@ -426,6 +497,41 @@ class uint128_fallback { + #endif + return *this; + } ++ constexpr auto operator%=(unsigned int n) -> uint128_fallback& { ++ if (hi_ == 0 && lo_ < n) { ++ return *this; ++ } ++ uint64_t rem = 0; ++ udiv128by64to64(hi_ % n, lo_, n, rem); ++ hi_ = 0; ++ lo_ = rem; ++ return *this; ++ } ++ friend constexpr auto operator%(const uint128_fallback& lhs, ++ unsigned int rhs) -> uint128_fallback { ++ auto result = uint128_fallback(lhs); ++ result %= rhs; ++ return result; ++ } ++ constexpr auto operator/=(unsigned int rhs) -> uint128_fallback& { ++ if (hi_ == 0 && lo_ < rhs) { ++ lo_ = 0; ++ return *this; ++ } ++ if (hi_ < rhs) { ++ uint64_t rem = 0; ++ uint64_t q_lo = udiv128by64to64(hi_, lo_, rhs, rem); ++ lo_ = q_lo; ++ hi_ = 0; ++ return *this; ++ } ++ uint64_t q_hi = hi_ / rhs; ++ uint64_t rem = 0; ++ uint64_t q_lo = udiv128by64to64(hi_ % rhs, lo_, rhs, rem); ++ lo_ = q_lo; ++ hi_ = q_hi; ++ return *this; ++ } + }; + + using uint128_t = conditional_t<FMT_USE_INT128, uint128_opt, uint128_fallback>; +@@ -1144,12 +1250,54 @@ template <typename T> FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { + count += 4; + } + } +-#if FMT_USE_INT128 +-FMT_CONSTEXPR inline auto count_digits(uint128_opt n) -> int { +- return count_digits_fallback(n); ++ ++#ifdef FMT_BUILTIN_CLZLL ++inline auto do_count_digits(uint64_t n) -> int; ++inline auto do_count_digits(uint128_t n) -> int { ++ if (static_cast<uint64_t>(n >> 64) == 0) { ++ return do_count_digits(static_cast<uint64_t>(n)); ++ } ++ // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). ++ static constexpr uint8_t bsr2log10[] = { ++ 20, 20, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 24, 24, 24, 25, ++ 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, ++ 30, 30, 30, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 34, 34, 34, ++ 35, 35, 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 38, 38, 39, 39}; ++ auto c = FMT_BUILTIN_CLZLL(static_cast<uint64_t>(n >> 64)); ++ auto t = bsr2log10[c ^ 63]; ++ static constexpr const uint128_t powers_of_10[] = { ++ 0, ++ (uint128_t(5ULL) << 64) | uint128_t(7766279631452241920ULL), ++ (uint128_t(54ULL) << 64) | uint128_t(3875820019684212736ULL), ++ (uint128_t(542ULL) << 64) | uint128_t(1864712049423024128ULL), ++ (uint128_t(5421ULL) << 64) | uint128_t(200376420520689664ULL), ++ (uint128_t(54210ULL) << 64) | uint128_t(2003764205206896640ULL), ++ (uint128_t(542101ULL) << 64) | uint128_t(1590897978359414784ULL), ++ (uint128_t(5421010ULL) << 64) | uint128_t(15908979783594147840ULL), ++ (uint128_t(54210108ULL) << 64) | uint128_t(11515845246265065472ULL), ++ (uint128_t(542101086ULL) << 64) | uint128_t(4477988020393345024ULL), ++ (uint128_t(5421010862ULL) << 64) | uint128_t(7886392056514347008ULL), ++ (uint128_t(54210108624ULL) << 64) | uint128_t(5076944270305263616ULL), ++ (uint128_t(542101086242ULL) << 64) | uint128_t(13875954555633532928ULL), ++ (uint128_t(5421010862427ULL) << 64) | uint128_t(9632337040368467968ULL), ++ (uint128_t(54210108624275ULL) << 64) | uint128_t(4089650035136921600ULL), ++ (uint128_t(542101086242752ULL) << 64) | uint128_t(4003012203950112768ULL), ++ (uint128_t(5421010862427522ULL) << 64) | uint128_t(3136633892082024448ULL), ++ (uint128_t(54210108624275221ULL) << 64) | uint128_t(12919594847110692864ULL), ++ (uint128_t(542101086242752217ULL) << 64) | uint128_t(68739955140067328ULL), ++ (uint128_t(5421010862427522170ULL) << 64) | uint128_t(687399551400673280ULL), ++ }; ++ return t - (n < powers_of_10[t - 20]); + } + #endif + ++FMT_CONSTEXPR20 inline auto count_digits(uint128_t n) -> int { ++#ifdef FMT_BUILTIN_CLZLL ++ if (!is_constant_evaluated()) return do_count_digits(n); ++#endif ++ return count_digits_fallback(n); ++} ++ + #ifdef FMT_BUILTIN_CLZLL + // It is a separate function rather than a part of count_digits to workaround + // the lack of static constexpr in constexpr functions. +-- +2.46.0.windows.1 + diff --git a/cmake/Helper.cmake b/cmake/Helper.cmake index a738ce80617b..8b3ca793bf10 100644 --- a/cmake/Helper.cmake +++ b/cmake/Helper.cmake @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC set(WASMEDGE_INTERPROCEDURAL_OPTIMIZATION OFF) if(CMAKE_BUILD_TYPE STREQUAL Release OR CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo) @@ -18,7 +18,7 @@ endif() if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") list(APPEND WASMEDGE_CFLAGS - /std:c++17 + /utf-8 /WX /W4 /we5030 # treat unknown attribute as error @@ -42,11 +42,6 @@ else() -Werror -Wno-error=pedantic ) - if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 13) - list(APPEND WASMEDGE_CFLAGS - -Wno-error=dangling-reference - ) - endif() endif() if(WASMEDGE_ENABLE_UB_SANITIZER) @@ -69,6 +64,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") -Wno-documentation-unknown-command -Wno-error=nested-anon-types -Wno-error=old-style-cast + -Wno-error=shadow -Wno-error=unused-command-line-argument -Wno-error=unknown-warning-option -Wno-ctad-maybe-unsupported @@ -81,6 +77,19 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") -Wno-switch-enum -Wno-undefined-func-template ) + + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 17.0.0) + list(APPEND WASMEDGE_CFLAGS + -Wno-deprecated-literal-operator + ) + endif() + + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 18.0.0) + list(APPEND WASMEDGE_CFLAGS + -Wno-switch-default + ) + endif() + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0.0) list(APPEND WASMEDGE_CFLAGS -Wno-error=return-std-move-in-c++11 @@ -91,13 +100,23 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") -Wno-reserved-identifier ) endif() +elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 13) + list(APPEND WASMEDGE_CFLAGS + -Wno-error=dangling-reference + ) + endif() + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 14) + list(APPEND WASMEDGE_CFLAGS + -Wno-error=template-id-cdtor + ) + endif() endif() if(WIN32) add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_ENABLE_EXTENDED_ALIGNED_STORAGE -DNOMINMAX -D_ITERATOR_DEBUG_LEVEL=0) - if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") list(APPEND WASMEDGE_CFLAGS - "/EHa" -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-exit-time-destructors @@ -164,8 +183,8 @@ endfunction() function(wasmedge_add_library target) add_library(${target} ${ARGN}) wasmedge_setup_target(${target}) - # Linux needs an explicit INSTALL_RPATH to allow libwasmedge.so to find libwasiNNRPC.so - # in the same directory + # Linux needs an explicit INSTALL_RPATH to allow libwasmedge.so to find + # libwasiNNRPC.so in the same directory. if(CMAKE_SYSTEM_NAME MATCHES "Linux") set_target_properties(${target} PROPERTIES INSTALL_RPATH "$ORIGIN" @@ -189,12 +208,12 @@ function(wasmedge_add_executable target) endfunction() # Generate the list of static libs to statically link LLVM. -if((WASMEDGE_LINK_LLVM_STATIC OR WASMEDGE_BUILD_STATIC_LIB) AND WASMEDGE_BUILD_AOT_RUNTIME) +if((WASMEDGE_LINK_LLVM_STATIC OR WASMEDGE_BUILD_STATIC_LIB) AND WASMEDGE_USE_LLVM) # Pack the LLVM and lld static libraries. find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_PATH}") execute_process( COMMAND ${LLVM_BINARY_DIR}/bin/llvm-config --libs --link-static - core lto native nativecodegen option passes support transformutils all-targets + core lto native nativecodegen option passes support orcjit transformutils all-targets OUTPUT_VARIABLE WASMEDGE_LLVM_LINK_LIBS_NAME ) string(REPLACE "-l" "" WASMEDGE_LLVM_LINK_LIBS_NAME "${WASMEDGE_LLVM_LINK_LIBS_NAME}") @@ -228,7 +247,7 @@ if((WASMEDGE_LINK_LLVM_STATIC OR WASMEDGE_BUILD_STATIC_LIB) AND WASMEDGE_BUILD_A ${LLVM_LIBRARY_DIR}/liblldWasm.a ) endif() - if (APPLE AND LLVM_VERSION_MAJOR GREATER_EQUAL 15) + if(APPLE AND LLVM_VERSION_MAJOR GREATER_EQUAL 15) # For LLVM 15 or greater on MacOS find_package(zstd REQUIRED) get_filename_component(ZSTD_PATH "${zstd_LIBRARY}" DIRECTORY) @@ -273,3 +292,95 @@ if((WASMEDGE_LINK_LLVM_STATIC OR WASMEDGE_BUILD_STATIC_LIB) AND WASMEDGE_BUILD_A endif() endif() endif() + +function(wasmedge_setup_simdjson) + # setup simdjson + find_package(simdjson QUIET) + if(simdjson_FOUND) + message(STATUS "SIMDJSON found") + else() + message(STATUS "Downloading SIMDJSON source") + include(FetchContent) + FetchContent_Declare( + simdjson + GIT_REPOSITORY https://github.com/simdjson/simdjson.git + GIT_TAG tags/v3.10.0 + GIT_SHALLOW TRUE) + set(SIMDJSON_DEVELOPER_MODE OFF) + FetchContent_MakeAvailable(simdjson) + set_property(TARGET simdjson PROPERTY POSITION_INDEPENDENT_CODE ON) + message(STATUS "Downloading SIMDJSON source -- done") + + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + target_compile_options(simdjson + PUBLIC + -Wno-undef + -Wno-suggest-override + -Wno-documentation + -Wno-sign-conversion + -Wno-extra-semi-stmt + -Wno-old-style-cast + -Wno-error=unused-parameter + -Wno-error=unused-template + -Wno-conditional-uninitialized + -Wno-implicit-int-conversion + -Wno-shorten-64-to-32 + -Wno-range-loop-bind-reference + -Wno-format-nonliteral + -Wno-unused-exception-parameter + -Wno-unused-macros + -Wno-unused-member-function + -Wno-missing-prototypes + ) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + target_compile_options(simdjson + PUBLIC + $<$<COMPILE_LANGUAGE:C,CXX>:/wd4100> # unreferenced formal parameter + $<$<COMPILE_LANGUAGE:C,CXX>:/wd4505> # unreferenced local function has been removed + ) + endif() + endif() +endfunction() + +function(wasmedge_setup_spdlog) + find_package(spdlog QUIET) + if(spdlog_FOUND) + else() + FetchContent_Declare( + fmt + GIT_REPOSITORY https://github.com/fmtlib/fmt.git + GIT_TAG 11.0.2 + GIT_SHALLOW TRUE + PATCH_COMMAND "${GIT_CMD}" checkout 11.0.2 . + COMMAND "${GIT_CMD}" "apply" "--whitespace=fix" "${CMAKE_SOURCE_DIR}/cmake/0001-support-arithmetic-operations-in-uint128_fallback.patch" + ) + set(FMT_INSTALL OFF CACHE BOOL "Generate the install target." FORCE) + FetchContent_MakeAvailable(fmt) + wasmedge_setup_target(fmt) + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + target_compile_options(fmt + PUBLIC + -Wno-missing-noreturn + PRIVATE + -Wno-sign-conversion + ) + endif() + if (WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") + target_compile_options(fmt + PUBLIC + -Wno-duplicate-enum + ) + endif() + + FetchContent_Declare( + spdlog + GIT_REPOSITORY https://github.com/gabime/spdlog.git + GIT_TAG v1.13.0 + GIT_SHALLOW TRUE + ) + set(SPDLOG_BUILD_SHARED OFF CACHE BOOL "Build shared library" FORCE) + set(SPDLOG_FMT_EXTERNAL ON CACHE BOOL "Use external fmt library instead of bundled" FORCE) + FetchContent_MakeAvailable(spdlog) + wasmedge_setup_target(spdlog) + endif() +endfunction() diff --git a/cmake/Hunter/config.cmake b/cmake/Hunter/config.cmake index 684d9615017b..e7f6175c1d22 100644 --- a/cmake/Hunter/config.cmake +++ b/cmake/Hunter/config.cmake @@ -19,3 +19,21 @@ hunter_config( LLVM_ENABLE_PROJECTS=lld;clang LLVM_TARGETS_TO_BUILD=${ARCHITECTURE};BPF ) + +hunter_config( + fmt + URL + https://github.com/fmtlib/fmt/archive/refs/tags/10.2.1.tar.gz + SHA1 + d223964b782d2562d6722ffe67027204c6035453 + CMAKE_ARGS + CMAKE_POSITION_INDEPENDENT_CODE=TRUE +) + +hunter_config( + spdlog + VERSION 1.12.0-p0 + CMAKE_ARGS + SPDLOG_BUILD_PIC=ON + SPDLOG_FMT_EXTERNAL=ON +) diff --git a/cmake/WASINNDeps.cmake b/cmake/WASINNDeps.cmake index 43f235cf5b9a..5279be517dfa 100644 --- a/cmake/WASINNDeps.cmake +++ b/cmake/WASINNDeps.cmake @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC include(FetchContent) @@ -7,41 +7,43 @@ if(NOT WASMEDGE_DEPS_VERSION) set(WASMEDGE_DEPS_VERSION "TF-2.12.0-CC") endif() -# Set the system name and hash of TF and TFLite releases. -if(ANDROID) - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") - set(WASMEDGE_TENSORFLOW_SYSTEM_NAME "android_aarch64") - set(WASMEDGE_TENSORFLOW_DEPS_TFLITE_HASH "2d7dcd7381479d9ffc0968ea66e24a5207b404c7f2ccbdddec6f2a4d6f9813f2") - elseif() - message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}") - endif() -elseif(APPLE) - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64") - set(WASMEDGE_TENSORFLOW_SYSTEM_NAME "darwin_x86_64") - set(WASMEDGE_TENSORFLOW_DEPS_TF_HASH "60da72a093cf65d733ca2cb9f331356a1637acfe1645050809bd0cf056b1520f") - set(WASMEDGE_TENSORFLOW_DEPS_TFLITE_HASH "04b58f4b97220633a8e299a63aba73d9a1f228904081e7d5f18e78d1e38d5f00") - elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - set(WASMEDGE_TENSORFLOW_SYSTEM_NAME "darwin_arm64") - set(WASMEDGE_TENSORFLOW_DEPS_TF_HASH "2ede6d96c7563eb826331469d7d0a1f51c9b1ca311f4398d841f679a5b96705a") - set(WASMEDGE_TENSORFLOW_DEPS_TFLITE_HASH "cb4562a80ac2067bdabe2464b80e129b9d8ddc6d97ad1a2d7215e06a1e1e8cda") - else() - message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}") - endif() -elseif(UNIX) - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64") - set(WASMEDGE_TENSORFLOW_SYSTEM_NAME "manylinux2014_x86_64") - set(WASMEDGE_TENSORFLOW_DEPS_TF_HASH "266465acd642a9d2d80e56c93aa0a255597bfb3034a826bb2225e61f2bebe2e2") - set(WASMEDGE_TENSORFLOW_DEPS_TFLITE_HASH "110a06bcda1fdc3e744b1728157b66981e235de130f3a34755684e6adcf08341") - elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") - set(WASMEDGE_TENSORFLOW_SYSTEM_NAME "manylinux2014_aarch64") - set(WASMEDGE_TENSORFLOW_DEPS_TF_HASH "9c15a3aeeda614c9677fe8980d8fa2cd9600072c4701b8a8189225855b9ca1a8") - set(WASMEDGE_TENSORFLOW_DEPS_TFLITE_HASH "672b81d3f4b5a6c25dc9bbc3b8c6ac1c0357cfab8105b2a85b8bb8c0b59afcb4") +function(wasmedge_setup_tf_variables) + # Set the system name and hash of TF and TFLite releases. + if(ANDROID) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + set(WASMEDGE_TENSORFLOW_SYSTEM_NAME "android_aarch64" PARENT_SCOPE) + set(WASMEDGE_TENSORFLOW_DEPS_TFLITE_HASH "2d7dcd7381479d9ffc0968ea66e24a5207b404c7f2ccbdddec6f2a4d6f9813f2" PARENT_SCOPE) + elseif() + message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}") + endif() + elseif(APPLE) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64") + set(WASMEDGE_TENSORFLOW_SYSTEM_NAME "darwin_x86_64" PARENT_SCOPE) + set(WASMEDGE_TENSORFLOW_DEPS_TF_HASH "60da72a093cf65d733ca2cb9f331356a1637acfe1645050809bd0cf056b1520f" PARENT_SCOPE) + set(WASMEDGE_TENSORFLOW_DEPS_TFLITE_HASH "04b58f4b97220633a8e299a63aba73d9a1f228904081e7d5f18e78d1e38d5f00" PARENT_SCOPE) + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + set(WASMEDGE_TENSORFLOW_SYSTEM_NAME "darwin_arm64" PARENT_SCOPE) + set(WASMEDGE_TENSORFLOW_DEPS_TF_HASH "2ede6d96c7563eb826331469d7d0a1f51c9b1ca311f4398d841f679a5b96705a" PARENT_SCOPE) + set(WASMEDGE_TENSORFLOW_DEPS_TFLITE_HASH "cb4562a80ac2067bdabe2464b80e129b9d8ddc6d97ad1a2d7215e06a1e1e8cda" PARENT_SCOPE) + else() + message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}") + endif() + elseif(UNIX) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64") + set(WASMEDGE_TENSORFLOW_SYSTEM_NAME "manylinux2014_x86_64" PARENT_SCOPE) + set(WASMEDGE_TENSORFLOW_DEPS_TF_HASH "266465acd642a9d2d80e56c93aa0a255597bfb3034a826bb2225e61f2bebe2e2" PARENT_SCOPE) + set(WASMEDGE_TENSORFLOW_DEPS_TFLITE_HASH "110a06bcda1fdc3e744b1728157b66981e235de130f3a34755684e6adcf08341" PARENT_SCOPE) + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + set(WASMEDGE_TENSORFLOW_SYSTEM_NAME "manylinux2014_aarch64" PARENT_SCOPE) + set(WASMEDGE_TENSORFLOW_DEPS_TF_HASH "9c15a3aeeda614c9677fe8980d8fa2cd9600072c4701b8a8189225855b9ca1a8" PARENT_SCOPE) + set(WASMEDGE_TENSORFLOW_DEPS_TFLITE_HASH "672b81d3f4b5a6c25dc9bbc3b8c6ac1c0357cfab8105b2a85b8bb8c0b59afcb4" PARENT_SCOPE) + else() + message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}") + endif() else() - message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}") + message(FATAL_ERROR "Unsupported system: ${CMAKE_SYSTEM_NAME}") endif() -else() - message(FATAL_ERROR "Unsupported system: ${CMAKE_SYSTEM_NAME}") -endif() +endfunction() function(wasmedge_setup_tf_headers) FetchContent_Declare( @@ -60,6 +62,7 @@ function(wasmedge_setup_tf_headers) endfunction() function(wasmedge_setup_tflite_lib) + wasmedge_setup_tf_variables() # Fetch Tensorflow-lite library. FetchContent_Declare( wasmedge_tensorflow_lib_tflite @@ -96,6 +99,7 @@ function(wasmedge_setup_tflite_lib) endfunction() function(wasmedge_setup_tf_lib) + wasmedge_setup_tf_variables() # Fetch Tensorflow-lite library. FetchContent_Declare( wasmedge_tensorflow_lib_tf @@ -173,6 +177,19 @@ function(wasmedge_setup_wasinn_target target) elseif(BACKEND STREQUAL "ggml") message(STATUS "WASI-NN: Build ggml backend for WASI-NN") add_definitions(-DWASMEDGE_PLUGIN_WASI_NN_BACKEND_GGML) + elseif(BACKEND STREQUAL "neuralspeed") + message(NOTICE "WASI-NN: Neural Speed backend is removed due to the upstream end-of-life.") + elseif(BACKEND STREQUAL "piper") + message(STATUS "WASI-NN: Build piper backend for WASI-NN") + add_definitions(-DWASMEDGE_PLUGIN_WASI_NN_BACKEND_PIPER) + wasmedge_setup_piper() + list(APPEND WASMEDGE_PLUGIN_WASI_NN_DEPS piper) + elseif(BACKEND STREQUAL "whisper") + message(STATUS "WASI-NN: Build whisper.cpp backend for WASI-NN") + add_definitions(-DWASMEDGE_PLUGIN_WASI_NN_BACKEND_WHISPER) + elseif(BACKEND STREQUAL "chattts") + message(STATUS "WASI-NN: Build chatTTS backend for WASI-NN") + add_definitions(-DWASMEDGE_PLUGIN_WASI_NN_BACKEND_CHATTTS) else() # Add the other backends here. message(FATAL_ERROR "WASI-NN: backend ${BACKEND} not found or unimplemented.") @@ -214,3 +231,41 @@ function(wasmedge_setup_tflite_target target) ${WASMEDGE_TENSORFLOW_DEPS_TFLITE_LIB} ) endfunction() + +function(wasmedge_setup_piper) + include(Helper) + wasmedge_setup_spdlog() + find_package(onnxruntime) + if(NOT onnxruntime_FOUND) + find_library(ONNXRUNTIME_LIBRARY onnxruntime) + if(NOT "${ONNXRUNTIME_LIBRARY}" STREQUAL "ONNXRUNTIME_LIBRARY-NOTFOUND") + find_path(ONNXRUNTIME_PATH "onnxruntime_cxx_api.h" PATH_SUFFIXES "onnxruntime") + if(NOT "${ONNXRUNTIME_PATH}" STREQUAL "ONNXRUNTIME_PATH-NOTFOUND") + set(onnxruntime_FOUND TRUE) + endif() + endif() + endif() + if(NOT onnxruntime_FOUND) + message(FATAL_ERROR "Cannot find onnxruntime") + endif() + message(STATUS "Downloading piper source") + include(FetchContent) + set(BUILD_SHARED_LIBS OFF) + set(CMAKE_POSITION_INDEPENDENT_CODE ON) + set(BUILD_TESTING OFF) + find_program(GIT_CMD git REQUIRED) + FetchContent_Declare( + piper + GIT_REPOSITORY https://github.com/rhasspy/piper.git + GIT_TAG 38917ffd8c0e219c6581d73e07b30ef1d572fce1 # 2023.11.14-2 + UPDATE_DISCONNECTED TRUE + PATCH_COMMAND "${GIT_CMD}" "apply" "${CMAKE_SOURCE_DIR}/plugins/wasi_nn/piper.patch" + ) + FetchContent_GetProperties(piper) + if(NOT piper_POPULATED) + FetchContent_Populate(piper) + add_subdirectory("${piper_SOURCE_DIR}" "${piper_BINARY_DIR}" EXCLUDE_FROM_ALL) + endif() + # suppress src/cpp/piper.cpp:302:29: error: unused parameter ‘config’ [-Werror=unused-parameter] + target_compile_options(piper PRIVATE -Wno-error=unused-parameter) +endfunction() diff --git a/cmake/cpack_config.cmake b/cmake/cpack_config.cmake index 4cce93c1f37a..f534c846d9b1 100644 --- a/cmake/cpack_config.cmake +++ b/cmake/cpack_config.cmake @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC if(CPACK_GENERATOR STREQUAL "DEB") else() diff --git a/cmake/wasmedge-config.cmake b/cmake/wasmedge-config.cmake index b410c53b00bb..58dfd78422bc 100644 --- a/cmake/wasmedge-config.cmake +++ b/cmake/wasmedge-config.cmake @@ -1,16 +1,32 @@ +include(GNUInstallDirs) + +set(WASMEDGE_SHARED_LIB "${WASMEDGE_ROOT}/${CMAKE_INSTALL_LIBDIR}/libwasmedge${CMAKE_SHARED_LIBRARY_SUFFIX}") +set(WASMEDGE_STATIC_LIB "${WASMEDGE_ROOT}/${CMAKE_INSTALL_LIBDIR}/libwasmedge${CMAKE_STATIC_LIBRARY_SUFFIX}") +set(WASMEDGE_STATIC_LIB_DEBUG "${WASMEDGE_ROOT}/${CMAKE_INSTALL_LIBDIR}/libwasmedged${CMAKE_STATIC_LIBRARY_SUFFIX}") + +if (EXISTS "${WASMEDGE_SHARED_LIB}") + add_library(WasmEdge::WasmEdge SHARED IMPORTED) + set_property(TARGET WasmEdge::WasmEdge PROPERTY IMPORTED_LOCATION "${WASMEDGE_SHARED_LIB}") + +elseif(EXISTS "${WASMEDGE_STATIC_LIB_DEBUG}" AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + add_library(WasmEdge::WasmEdge STATIC IMPORTED) + set_property(TARGET WasmEdge::WasmEdge PROPERTY IMPORTED_LOCATION "${WASMEDGE_STATIC_LIB_DEBUG}") + +elseif(EXISTS "${WASMEDGE_STATIC_LIB}") + add_library(WasmEdge::WasmEdge STATIC IMPORTED) + set_property(TARGET WasmEdge::WasmEdge PROPERTY IMPORTED_LOCATION "${WASMEDGE_STATIC_LIB}") + +else() + message(FATAL_ERROR "WasmEdge not found in ${WASMEDGE_ROOT}!\n" + "Tried:\n" + " - ${WASMEDGE_SHARED_LIB}\n" + " - ${WASMEDGE_STATIC_LIB}\n" + " - ${WASMEDGE_STATIC_LIB_DEBUG}\n" + ) +endif() -add_library(WasmEdge::WasmEdge STATIC IMPORTED) target_include_directories(WasmEdge::WasmEdge INTERFACE "${WASMEDGE_ROOT}/include") target_link_libraries(WasmEdge::WasmEdge INTERFACE curses) if(APPLE) target_link_libraries(WasmEdge::WasmEdge INTERFACE xar) endif() -set(WASMEDGE_LIB "${WASMEDGE_ROOT}/lib/libwasmedge.a") -set(WASMEDGE_LIB_DEBUG "${WASMEDGE_ROOT}/lib/libwasmedged.a") -if(NOT EXISTS "${WASMEDGE_LIB}") - set(WASMEDGE_LIB "${WASMEDGE_LIB_DEBUG}") -endif() -set_property(TARGET WasmEdge::WasmEdge PROPERTY IMPORTED_LOCATION "${WASMEDGE_LIB}") -if(EXISTS "${WASMEDGE_LIB_DEBUG}") - set_property(TARGET WasmEdge::WasmEdge PROPERTY IMPORTED_LOCATION_DEBUG "${WASMEDGE_LIB_DEBUG}") -endif() diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md index 0a07dd986fe8..f95a89fdc31b 100644 --- a/docs/CODE_OF_CONDUCT.md +++ b/docs/CODE_OF_CONDUCT.md @@ -2,7 +2,7 @@ As a CNCF project, WasmEdge follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). In addition to this code of conduct, we have also implemented guidelines for the use of other developers' open-source work in your code. -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the WasmEdge team via <WasmEdge@googlegroups.com>. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the WasmEdge team via <WasmEdge@googlegroups.com> or the private maintainer mailing list <cncf-wasmedge-runtime-maintainers@lists.cncf.io>. As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. diff --git a/docs/GOVERNANCE.md b/docs/GOVERNANCE.md index dc2d54bd6598..27829f76e2c6 100644 --- a/docs/GOVERNANCE.md +++ b/docs/GOVERNANCE.md @@ -23,19 +23,20 @@ Reviewers are part of the organization but do not have write access. Becoming a ## Committers A committer is a core maintainer who is responsible for the overall quality and stewardship of the project. They share the same reviewing responsibilities as reviewers, but are also responsible for upholding the project bylaws as well as participating in project level votes. + Committers are part of the organization with write access to all repositories. Committers are expected to remain actively involved in the project and participate in voting and discussing proposed project-level changes. ## Adding maintainers -Maintainers are first and foremost contributors that have shown they are committed to the long term success of a project. Contributors wanting to become maintainers are expected to be deeply involved in contributing code, pull request review, and triage of issues in the project for more than three months. +Maintainers are first and foremost contributors who have shown they are committed to the long-term success of a project. Contributors wanting to become maintainers are expected to be deeply involved in contributing code, pull request review, and triage of issues in the project for more than three months. Just contributing does not make you a maintainer, it is about building trust with the current maintainers of the project and being a person that they can depend on and trust to make decisions in the best interest of the project. -Periodically, the existing maintainers curate a list of contributors that have shown regular activity on the project over the prior months. From this list, maintainer candidates are selected and proposed in the maintainers forum. +Periodically, the existing maintainers curate a list of contributors who have shown regular activity on the project over the prior months. From this list, maintainer candidates are selected and proposed in a maintainers channel. -After a candidate has been informally proposed in the maintainers forum, the existing maintainers are given seven days to discuss the candidate, raise objections and show their support. Formal voting takes place on a pull request that adds the contributor to the MAINTAINERS file. Candidates must be approved by 2/3 of the current committers by adding their approval or LGTM to the pull request. The reviewer role has the same process but only requires 1/3 of current committers. +After a candidate has been informally proposed in the maintainers' channel, the existing maintainers are given seven days to discuss the candidate, raise objections, and show their support. Formal voting takes place on a pull request that adds the contributor to the MAINTAINERS file. Candidates must be approved by 2/3 of the current maintainers by adding their approval or LGTM to the pull request. The reviewer role has the same process but only requires 1/3 of current maintainers. -If a candidate is approved, they will be invited to add their own LGTM or approval to the pull request to acknowledge their agreement. A committer will verify the numbers of votes that have been received and the allotted seven days have passed, then merge the pull request and invite the contributor to the organization. +If a candidate is approved, they will be invited to add their own LGTM or approval to the pull request to acknowledge their agreement. A maintainer will verify the number of votes that have been received and the allotted seven days have passed, then merge the pull request and invite the contributor to the organization and the [private maintainer mailing list](cncf-wasmedge-runtime-maintainers@lists.cncf.io)). ## When does a maintainer lose maintainer status @@ -45,16 +46,46 @@ If a maintainer is no longer interested or cannot perform the maintainer duties In general, we prefer that technical issues and maintainer membership are amicably worked out between the persons involved. If a dispute cannot be decided independently, the maintainers can be called in to decide an issue. If the maintainers themselves cannot decide an issue, the issue will be resolved by voting. The voting process is a simple majority in which each maintainer receives one vote. -## Adding new projects to the WasmRuntime GitHub organization +## Adding new projects to the WasmEdge Runtime GitHub organization New projects will be added to the WasmEdge organization via GitHub issue discussion in one of the existing projects in the organization. Once sufficient discussion has taken place (~3-5 business days but depending on the volume of conversation), the maintainers of *the project where the issue was opened* (since different projects in the organization may have different maintainers) will decide whether the new project should be added. See the section above on voting if the maintainers cannot easily decide. -## DCO and Licenses +## Meetings + +Time zones permitting, Maintainers are expected to participate in the public developer meeting, which occurs on the first Tuesday of each month. +* [Public meeting link](https://us06web.zoom.us/j/89156807241?pwd=VHl5VW5BbmY2eUtTYkY0Zm9yUHRRdz09) +* [Public meeting note](https://docs.google.com/document/d/1iFlVl7R97Lze4RDykzElJGDjjWYDlkI8Rhf8g4dQ5Rk/edit?usp=sharing) + +Maintainers will also have closed meetings in order to discuss security reports or Code of Conduct violations. Such meetings should be scheduled by any Maintainer on receipt of a security issue or CoC report. All current Maintainers must be invited to such closed meetings, except for any Maintainer who is accused of a CoC violation. + +## CNCF Resources +Any Maintainer may suggest a request for CNCF resources, either in the [mailing list](cncf-wasmedge-runtime-maintainers@lists.cncf.io), or during a meeting. A simple majority of Maintainers approve the request. The Maintainers may also choose to delegate working with the CNCF to non-Maintainer community members, who will then be added to the CNCF's Maintainer List for that purpose. + +### Code of Conduct +Code of Conduct violations by community members will be discussed and resolved on the private Maintainer mailing list. If a Maintainer is directly involved in the report, the Maintainers will instead designate two Maintainers to work with the CNCF Code of Conduct Committee in resolving it. + +## Security Response Team + +The Maintainers will appoint a Security Response Team to handle security reports. This committee may simply consist of the Maintainer Council themselves. If this responsibility is delegated, the Maintainers will appoint a team of at least two contributors to handle it. The Maintainers will review who is assigned to this at least once a year. + +The Security Response Team is responsible for handling all reports of security holes and breaches according to the [security policy](./SECURITY.md). + + + +## Voting + +While most business in WasmEdge runtime is conducted by "lazy consensus", periodically the Maintainers may need to vote on specific actions or changes. + +Generally, a vote will happen on A vote can be taken on the developer mailing list(wasmedge@googlegroup.com) or the private Maintainer mailing list (cncf-wasmedge-runtime-maintainers@lists.cncf.io) for security or conduct matters. Votes may also be taken at the developer meeting. Any Maintainer may demand a vote be taken. + +Most votes require a simple majority of all Maintainers to succeed, except where otherwise noted. Two-thirds majority votes mean at least two-thirds of all existing maintainers. + + +## Modifying this Charter + +Changes to this Governance and its supporting documents may be approved by a 2/3 vote of the Maintainers. -The following licenses and contributor agreements will be used for WasmRuntime projects: -* [Apache 2.0](https://opensource.org/licenses/Apache-2.0) for code -* [Developer Certificate of Origin](https://developercertificate.org/) for new contributions ## Credits diff --git a/docs/OWNER.md b/docs/OWNER.md index 5a5be6789cb7..082a99413478 100644 --- a/docs/OWNER.md +++ b/docs/OWNER.md @@ -11,13 +11,17 @@ ## WasmEdge Committers -| Committers | GitHub ID | Organization | Email | -| --------------- | --------- | ----------- | ----------- | -| dm4 | @dm4 | Second State | <dm4@secondstate.io> | -| yi | @0yi0 | Second State | <yi@secondstate.io> | -| Sam | @apepkuss | Second State | <sam@secondstate.io> | -| danny | @dannypsnl | Second State | <dannypsnl@secondstate.io> | -| Shreyas Atre | @SAtacker | SRA VJTI | <shreyasatre16@gmail.com> | +| Committers | GitHub ID | Organization | Email | +| --------------- | --------- | ----------- | ----------- | +| dm4 | @dm4 | Second State | <dm4@secondstate.io> | +| yi | @0yi0 | Second State | <yi@secondstate.io> | +| Sam | @apepkuss | Second State | <sam@secondstate.io> | +| danny | @dannypsnl | Second State | <dannypsnl@secondstate.io> | +| Shreyas Atre | @SAtacker | SRA VJTI | <shreyasatre16@gmail.com> | +| csh | @L-jasmine | Second State | <458761603@qq.com> | +| Vivian Hu | @alabulei1 | Second State | <vivian@secondstate.io> | +| Wang-Yang Li | @LFsWang | National Tsing Hua University | <s108062578@m108.nthu.edu.tw> | +| HanWen Tsao | @grorge123 | National Tsing Hua University | <chodehirgd157842@gmail.com> | ## WasmEdge Reviewers @@ -26,9 +30,8 @@ | 叶坚白 | @gusye1234 | University of Science and Technology of China | <jianbaiye@outlook.com> | | Tricster | @MediosZ | Southeast University | <mediosrity@gmail.com> | | Wenshuo Yang | @sonder-joker | Bytedance | <highmagic@outlook.com> | -| csh | @L-jasmine | Second State | <458761603@qq.com> | | Amun | @hangedfish | Giant Network Group Co., Ltd. | <bravohangedman@outlook.com> | | yb | @yanghaku | Nanjing University | <bo.yang@smail.nju.edu.cn> | | WenYuan Huang | @michael1017 | Purdue University | <huan2086@purdue.edu> | | 王纪开 | @am009 | Huazhong University of Science and Technology | <warrenwjk@qq.com> | - +| Shao-Yu Yu | @PeterD1524 | National Taiwan University | <qaz246135@gmail.com> | diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index b9dbdd779b96..f39e654c7570 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -1,40 +1,71 @@ # WasmEdge Roadmap -## About this document +## About This Document -This document should serve as a reference point for WasmEdge users and contributors to understand where the project is heading, and help determine if a contribution could be conflicting with a longer term plan. +This document serves as a reference point for WasmEdge users and contributors to understand where the project is heading, and help to determine if a contribution could be conflicting with a longer term plan. Additionally, this document also describes the rules and steps of proposing and retiring roadmap entries. -## How to help? +## Planning for Roadmap -Discussion on the roadmap can take place in threads under [Issues](https://github.com/WasmEdge/WasmEdge/issues). Please open and comment on an issue if you want to give suggestions and feedback to items in the roadmap. Please review the roadmap to avoid potential duplicated efforts. +WasmEdge roadmap will be updated quarterly with the following steps. -## How to add an item to the roadmap? +### New Roadmap Discussion -Please open an issue to track any initiative on the roadmap of WasmEdge (Usually driven by new feature requests). We will work with and rely on our community to focus our efforts to improve WasmEdge. +1. WasmEdge maintainers will open an issue on the upcoming roadmap at least 14 days before the start of a new quarter. +2. Any participation can request a roadmap entry by commenting on the issue and volunteering as an assignee. +3. WasmEdge maintainers will collect the proposed roadmap entries along with their respective timelines and assignees, then update them within the issue. +4. When the new quarter starts, the roadmap discussion issue will be finalized, this document will be updated, and new issues for the roadmap entries will be opened. + +### Updating Roadmap Status + +1. The completed roadmap entries will be marked as `"Completed"` when in a quarterly discussion. +2. Existing roadmap entries which not reach their deadlines will be retained in the new quarter and marked as `"Active"`. + +### Stale And Close + +1. For roadmap entries which have reached their deadlines, mark them as `"Staled"`. +2. The assignees of roadmap entries can request for updating the timeline. +3. The staled roadmap entries will be marked as `"Closed"` if no response from their assignees in the next quarterly discussion, and their related issues and pull requests will also be closed. ## Current Roadmap -The following table includes the current roadmap for WasmEdge. If you have any questions or would like to contribute to WasmEdge, please create an issue to discuss with our team. If you don't know where to start, we are always looking for contributors that will help us reduce technical, automation, and documentation debt. Please take the timelines & dates as proposals and goals. Priorities and requirements change based on community feedback, roadblocks encountered, community contributions, etc. - -Last Updated: Mar 2023 - -| Theme | Description | Timeline | -| --- | --- | --- | -| Proposal | Function reference proposal | Q2 / 2023 | -| Proposal | Exception handling proposal | Q2 / 2023 | -| Proposal | Typed continuation proposal | Q2 / 2023 | -| Proposal | Stack-switch proposal | Q2 / 2023 | -| Proposal | GC proposal | Q2 / 2023 | -| Feature | WasmEdge unified tool | Q2 / 2023 | -| Feature | WASM serialization/deserialization | Q2 / 2023 | -| Proposal | WASI signature proposal | Q3 / 2023 | -| Feature | Enhance info/debug logging, provide verbose mode (wasmedge a.wasm –verbose=3) | Q3 / 2023 | -| Feature | Wasm coredump | Q3 / 2023 | -| Proposal | WASM C API proposal | Q4 / 2023 | -| Proposal | WASM memory64 proposal | Q4 / 2023 | -| Feature | WASI-NN training extension | Q4 / 2023 | -| Feature | DWARF symbol | Q4 / 2023 | -| Proposal | Component model proposal | ?? / 2023 | -| Languages Bindings | [Python SDK](https://github.com/WasmEdge/WasmEdge/pull/633) | ?? / 2023 | -| Feature | Enable PaddlePaddle backend for WASI-NN | ?? / 2023 | -| Open Source Collaboration | Eventmesh, Krustlet, APISIX, Dapr, MOSN, KubeEdge, OpenYurt, Fedora, SuperEdge, UDF for SaaS and Databases, Substrate, ParaState, Filecoin | long term work | +Last Updated: Q3 / 2024 + +| Theme | Description | Timeline | Assignee | +| --- | ----------- | -------- | -------- | +| Proposal | GC proposal for AOT/JIT | Q4 / 2024 | [@q82419](https://github.com/q82419) | +| Proposal | Exception-Handling proposal for AOT/JIT | Q4 / 2024 | [@q82419](https://github.com/q82419) | +| Proposal | [Relaxed-SIMD proposal](https://github.com/WasmEdge/WasmEdge/pull/3311) | Q4 / 2024 | [@LFsWang](https://github.com/LFsWang) | +| Proposal | Typed continuation proposal | Q2 / 2025 | | +| Proposal | Stack-switch proposal | Q2 / 2025 | | +| Proposal | [WASI signature proposal](https://github.com/WasmEdge/WasmEdge/pull/517) | Q2 / 2025 | | +| Feature | Wasm coredump | Q2 / 2025 | | +| Proposal | [WASM C API proposal](https://github.com/WasmEdge/WasmEdge/pull/346) | Q4 / 2024 | [@q82419](https://github.com/q82419) | +| Proposal | [WASM memory64 proposal](https://github.com/WasmEdge/WasmEdge/pull/2964) | Q4 / 2024 | [@dannypsnl](https://github.com/dannypsnl) | +| Feature | DWARF symbol | Q2 / 2025 | | +| Proposal | [Instantiation of Component model proposal](https://github.com/WasmEdge/WasmEdge/pull/3218) | Q4 / 2024 | [@dannypsnl](https://github.com/dannypsnl) | +| Languages Bindings | [Python SDK](https://github.com/WasmEdge/WasmEdge/pull/633) | Q2 / 2025 | | +| Proposal | Whisper backend for WASI-NN | Q3 / 2024 | [@q82419](https://github.com/q82419) | +| Proposal | WASI-NN GGML plugin with latest llama.cpp integration | Q3 / 2024 | [@dm4](https://github.com/dm4) | +| Language Bindings | Update Java binding with 0.14 | Q3 / 2024 | | +| Language Bindings | Move Go binding back into WasmEdge org | Q4 / 2024 | [@q82419](https://github.com/q82419) | +| Feature | Deprecate manylinux2014 and make sure everything goes well on manylinux_2_28 | Q3 / 2024 | [@0yi0](https://github.com/0yi0) | +| Proposal | WASI-NN rust (burn) plugin and also added more models support | Q3 / 2024 | [@CaptainVincent](https://github.com/CaptainVincent) | + +## Previous Roadmap + +### Q2/2024 + +| Theme | Description | Assignee | Status | +| ----- | ----------- | -------- | ------ | +| Proposal | GC proposal for interpreter | [@q82419](https://github.com/q82419), [@little-willy](https://github.com/little-willy) | Completed | +| Proposal | Exception-Handling proposal for interpreter | [@harry900831](https://github.com/harry900831), [@q82419](https://github.com/q82419) | Completed | +| Proposal | GGML backend for WASI-NN | [@dm4](https://github.com/dm4), [@CaptainVincent](https://github.com/CaptainVincent) | Completed | +| Feature | JIT support | [@ibmibmibm](https://github.com/ibmibmibm) | Completed | + +### Q1/2024 + +| Theme | Description | Assignee | Status | +| ----- | ----------- | -------- | ------ | +| Proposal | Typed-function references proposal | [@q82419](https://github.com/q82419), [@little-willy](https://github.com/little-willy) | Completed | +| Proposal | Loader phase of Component model proposal | [@dannypsnl](https://github.com/dannypsnl) | Completed | +| Feature | WASM serialization | [@dracoooooo](https://github.com/dracoooooo) | Completed | diff --git a/docs/SECURITY_CONTACTS.md b/docs/SECURITY_CONTACTS.md new file mode 100644 index 000000000000..89f3d1d3ab48 --- /dev/null +++ b/docs/SECURITY_CONTACTS.md @@ -0,0 +1,17 @@ +# Security Contacts + +Defined below are the security persons of contact for WasmEdge. If you have +questions regarding the triaging and handling of incoming problems, they may be +contacted. + +The following security contacts have agreed to abide by the [Embargo Policy](./embargo-policy.md) +and will be removed and replaced if found to be in violation of that agreement. + +DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, USE THE +INSTRUCTIONS AT OUR [SECURITY POLICY](../SECURITY.md). + +Security Contacts: + +* @hydai, hydai@secondstate.io +* @ibmibmibm, beststeve@secondstate.io +* @dm4, dm4@secondstate.io diff --git a/docs/book/en/book.toml b/docs/book/en/book.toml deleted file mode 100644 index f61eb8812f6e..000000000000 --- a/docs/book/en/book.toml +++ /dev/null @@ -1,166 +0,0 @@ -[book] -title = "WasmEdge Runtime" -description = "" -author = ["Second State", "Michael Yuan", "Vivian Hu", "Miley Fu", "YiYing He"] -language = "en" - -[output.html] -git-repository-url = "https://github.com/WasmEdge/WasmEdge" -git-repository-icon = "fa-github" -edit-url-template = "https://github.com/WasmEdge/WasmEdge/tree/master/docs/book/en/{path}" -site-url = "/book/en/" -cname = "wasmedge.org" - -[output.html.playground] -editable = false -copy-js = true -line-numbers = false - -[output.html.fold] -enable = true - -[output.html.search] -enable = true -limit-results = 30 -teaser-word-count = 30 -use-boolean-and = true -boost-title = 2 -boost-hierarchy = 1 -boost-paragraph = 1 -expand = true -heading-split-level = 3 -copy-js = true - -[output.html.redirect] -"/intro.html" = "/book/en/index.html" -"/start/install.html" = "/book/en/quick_start/install.html" -"/start/docker.html" = "/book/en/quick_start/use_docker.html" -"/start/cli.html" = "/book/en/quick_start/run_cli.html" -"/start/universal.html" = "/book/en/quick_start/run_in_aot_mode.html" -"/intro/features.html" = "/book/en/features.html" -"/intro/standard.html" = "/book/en/features/proposals.html" -"/intro/proprietary.html" = "/book/en/features/proprietary_extend.html" -"/intro/integrations.html" = "/book/en/features/integrations.html" -"/intro/faq.html" = "/book/en/features/comparison.html" -"/intro/use.html" = "/book/en/use_cases.html" -"/intro/use/jamstack.html" = "/book/en/use_cases/server_side_render.html" -"/intro/use/microservice.html" = "/book/en/use_cases/microservice.html" -"/intro/use/serverless.html" = "/book/en/use_cases/serverless_faas.html" -"/intro/use/saas.html" = "/book/en/use_cases/serverless_saas.html" -"/intro/use/device.html" = "/book/en/use_cases/smart_device.html" -"/intro/use/js.html" = "/book/en/use_cases/js_or_dsl_runtime.html" -"/kubernetes.html" = "/book/en/use_cases/kubernetes.html" -"/kubernetes/quickstart.html" = "/book/en/use_cases/kubernetes/quickstart.html" -"/kubernetes/demo.html" = "/book/en/use_cases/kubernetes/demo.html" -"/kubernetes/demo/wasi.html" = "/book/en/use_cases/kubernetes/demo/wasi.html" -"/kubernetes/demo/server.html" = "/book/en/use_cases/kubernetes/demo/server.html" -"/kubernetes/container.html" = "/book/en/use_cases/kubernetes/container.html" -"/kubernetes/container/crun.html" = "/book/en/use_cases/kubernetes/container/crun.html" -"/kubernetes/container/runc.html" = "/book/en/use_cases/kubernetes/container/runc.html" -"/kubernetes/container/youki.html" = "/book/en/use_cases/kubernetes/container/youki.html" -"/kubernetes/cri.html" = "/book/en/use_cases/kubernetes/cri.html" -"/kubernetes/cri/crio.html" = "/book/en/use_cases/kubernetes/cri/crio.html" -"/kubernetes/cri/containerd.html" = "/book/en/use_cases/kubernetes/cri/containerd.html" -"/kubernetes/kubernetes.html" = "/book/en/use_cases/kubernetes/kubernetes.html" -"/kubernetes/kubernetes/kubernetes-crio.html" = "/book/en/use_cases/kubernetes/kubernetes/kubernetes-crio.html" -"/kubernetes/kubernetes/kubernetes-containerd.html" = "/book/en/use_cases/kubernetes/kubernetes/kubernetes-containerd.html" -"/kubernetes/kubernetes/kind.html" = "/book/en/use_cases/kubernetes/kubernetes/kind.html" -"/kubernetes/kubernetes/kubeedge.html" = "/book/en/use_cases/kubernetes/kubernetes/kubeedge.html" -"/kubernetes/kubernetes/superedge.html" = "/book/en/use_cases/kubernetes/kubernetes/superedge.html" -"/kubernetes/kubernetes/openyurt.html" = "/book/en/use_cases/kubernetes/kubernetes/openyurt.html" -"/kubernetes/docker.html" = "/book/en/use_cases/kubernetes/docker.html" -"/kubernetes/docker/lxc.html" = "/book/en/use_cases/kubernetes/docker/lxc.html" -"/kubernetes/docker/containerd.html" = "/book/en/use_cases/kubernetes/docker/containerd.html" -"/frameworks.html" = "/book/en/use_cases/frameworks.html" -"/frameworks/mesh.html" = "/book/en/use_cases/frameworks/mesh.html" -"/frameworks/mesh/dapr.html" = "/book/en/use_cases/frameworks/mesh/dapr.html" -"/frameworks/mesh/mosn.html" = "/book/en/use_cases/frameworks/mesh/mosn.html" -"/frameworks/mesh/wasm-nginx-module.html" = "/book/en/use_cases/frameworks/mesh/wasm-nginx-module.html" -"/frameworks/mesh/eventmesh.html" = "/book/en/use_cases/frameworks/mesh/eventmesh.html" -"/frameworks/app.html" = "/book/en/use_cases/frameworks/app.html" -"/frameworks/app/yomo.html" = "/book/en/use_cases/frameworks/app/yomo.html" -"/frameworks/app/reactr.html" = "/book/en/use_cases/frameworks/app/reactr.html" -"/frameworks/serverless.html" = "/book/en/use_cases/frameworks/serverless.html" -"/frameworks/serverless/vercel.html" = "/book/en/use_cases/frameworks/serverless/vercel.html" -"/frameworks/serverless/netlify.html" = "/book/en/use_cases/frameworks/serverless/netlify.html" -"/frameworks/serverless/aws.html" = "/book/en/use_cases/frameworks/serverless/aws.html" -"/frameworks/serverless/tencent.html" = "/book/en/use_cases/frameworks/serverless/tencent.html" -"/frameworks/serverless/secondstate.html" = "/book/en/use_cases/frameworks/serverless/secondstate.html" -"/dev.html" = "/book/en/write_wasm.html" -"/dev/rust.html" = "/book/en/write_wasm/rust.html" -"/dev/rust/bindgen.html" = "/book/en/write_wasm/rust/bindgen.html" -"/dev/rust/command.html" = "/book/en/write_wasm/rust/command.html" -"/dev/rust/networking.html" = "/book/en/write_wasm/rust/networking.html" -"/dev/rust/networking-https.html" = "/book/en/write_wasm/rust/networking-https.html" -"/dev/rust/networking-nonblocking.html" = "/book/en/write_wasm/rust/networking-nonblocking.html" -"/dev/rust/ssr.html" = "/book/en/write_wasm/rust/ssr.html" -"/dev/rust/tensorflow.html" = "/book/en/write_wasm/rust/tensorflow.html" -"/dev/rust/wasi.html" = "/book/en/write_wasm/rust/wasi.html" -"/dev/rust/wasicrypto.html" = "/book/en/write_wasm/rust/wasicrypto.html" -"/dev/rust/wasinn.html" = "/book/en/write_wasm/rust/wasinn.html" -"/dev/js.html" = "/book/en/write_wasm/js.html" -"/dev/js/es6.html" = "/book/en/write_wasm/js/es6.html" -"/dev/js/modules.html" = "/book/en/write_wasm/js/modules.html" -"/dev/js/networking.html" = "/book/en/write_wasm/js/networking.html" -"/dev/js/nodejs.html" = "/book/en/write_wasm/js/nodejs.html" -"/dev/js/npm.html" = "/book/en/write_wasm/js/npm.html" -"/dev/js/quickstart.html" = "/book/en/write_wasm/js/quickstart.html" -"/dev/js/rust.html" = "/book/en/write_wasm/js/rust.html" -"/dev/js/ssr.html" = "/book/en/write_wasm/js/ssr.html" -"/dev/js/tensorflow.html" = "/book/en/write_wasm/js/tensorflow.html" -"/dev/as.html" = "/book/en/write_wasm/as.html" -"/dev/grain.html" = "/book/en/write_wasm/grain.html" -"/dev/go.html" = "/book/en/write_wasm/go.html" -"/dev/kotlin.html" = "/book/en/write_wasm/kotlin.html" -"/dev/python.html" = "/book/en/write_wasm/python.html" -"/dev/swift.html" = "/book/en/write_wasm/swift.html" -"/embed.html" = "/book/en/sdk.html" -"/embed/c.html" = "/book/en/sdk/c.html" -"/embed/c/ref.html" = "/book/en/sdk/c/ref.html" -"/embed/c/0.10.1/ref.html" = "/book/en/sdk/c/0.10.1/ref.html" -"/embed/c/0.10.1/upgrade_to_0.11.0.html" = "/book/en/sdk/c/0.10.1/upgrade_to_0.11.0.html" -"/embed/c/0.9.1/ref.html" = "/book/en/sdk/c/0.9.1/ref.html" -"/embed/c/0.9.1/upgrade_to_0.10.0.html" = "/book/en/sdk/c/0.9.1/upgrade_to_0.10.0.html" -"/embed/go.html" = "/book/en/sdk/go.html" -"/embed/go/ref.html" = "/book/en/sdk/go/ref.html" -"/embed/go/app.html" = "/book/en/sdk/go/app.html" -"/embed/go/bindgen.html" = "/book/en/sdk/go/bindgen.html" -"/embed/go/function.html" = "/book/en/sdk/go/function.html" -"/embed/go/memory.html" = "/book/en/sdk/go/memory.html" -"/embed/go/tensorflow.html" = "/book/en/sdk/go/tensorflow.html" -"/embed/go/0.9.1/ref.html" = "/book/en/sdk/go/0.9.1/ref.html" -"/embed/go/0.9.1/upgrade_to_0.10.0.html" = "/book/en/sdk/go/0.9.1/upgrade_to_0.10.0.html" -"/embed/node.html" = "/book/en/sdk/node.html" -"/embed/python.html" = "/book/en/sdk/python.html" -"/embed/rust.html" = "/book/en/sdk/rust.html" -"/embed/rust/concurrent_fib.html" = "/book/en/sdk/rust/concurrent_fib.html" -"/embed/rust/how_to_use_module_instance.html" = "/book/en/sdk/rust/how_to_use_module_instance.html" -"/embed/rust/memory_manipulation.html" = "/book/en/sdk/rust/memory_manipulation.html" -"/embed/rust/say_hello.html" = "/book/en/sdk/rust/say_hello.html" -"/embed/rust/sys_run_host_func.html" = "/book/en/sdk/rust/sys_run_host_func.html" -"/embed/rust/table_and_funcref.html" = "/book/en/sdk/rust/table_and_funcref.html" -"/extend/plugin.html" = "/book/en/plugin.html" -"/extend/plugin/loadable.html" = "/book/en/plugin.html" -"/extend/plugin/externref.html" = "/book/en/sdk/c/externref.html" -"/extend/plugin/hostfunction.html" = "/book/en/sdk/c/hostfunction.html" -"/extend.html" = "/book/en/contribute.html" -"/extend/contribute.html" = "/book/en/contribute.html" -"/os.html" = "/book/en/features/platforms.html" -"/os/linux.html" = "/book/en/contribute/build_from_src/linux.html" -"/os/windows.html" = "/book/en/contribute/build_from_src/windows.html" -"/os/mac.html" = "/book/en/contribute/build_from_src/macos.html" -"/os/android.html" = "/book/en/contribute/build_from_src/android.html" -"/os/android/cli.html" = "/book/en/contribute/build_from_src/android/cli.html" -"/os/android/ndk.html" = "/book/en/contribute/build_from_src/android/ndk.html" -"/os/android/apk.html" = "/book/en/contribute/build_from_src/android/apk.html" -"/os/sel4.html" = "/book/en/contribute/build_from_src/sel4.html" -"/os/openharmony.html" = "/book/en/contribute/build_from_src/openharmony.html" -"/os/raspberrypi.html" = "/book/en/contribute/build_from_src/raspberrypi.html" -"/extend/build.html" = "/book/en/contribute/build_from_src.html" -"/extend/build_on_mac.html" = "/book/en/contribute/build_from_src/macos.html" -"/extend/build_on_windows.html" = "/book/en/contribute/build_from_src/windows.html" -"/extend/build_for_android.html" = "/book/en/contribute/build_from_src/android.html" -"/cli/wasmedgec.html" = "/book/en/cli/wasmedge_compile.html" - -[preprocessor.variables.variables] -wasmedge_version = "0.12.1" diff --git a/docs/book/en/src/SUMMARY.md b/docs/book/en/src/SUMMARY.md deleted file mode 100644 index 2be69c0a33f9..000000000000 --- a/docs/book/en/src/SUMMARY.md +++ /dev/null @@ -1,163 +0,0 @@ -# Summary - -- [Introduction](index.md) - -- [Quick Start](quick_start.md) - - [Installation And Uninstallation](quick_start/install.md) - - [Using WasmEdge in Docker](quick_start/use_docker.md) - - [Running WASM with WasmEdge CLI](quick_start/run_cli.md) - - [Execution in AOT Mode](quick_start/run_in_aot_mode.md) - -- [WasmEdge Features](features.md) - - [Supported WASM And WASI Proposals](features/proposals.md) - - [WasmEdge Proprietary extensions](features/proprietary_extend.md) - - [Integrations](features/integrations.md) - - [Supported Platforms](features/platforms.md) - - [Comparison](features/comparison.md) - -- [WasmEdge Use Cases](use_cases.md) - - [Server-Side Rendering Modern Web UI](use_cases/server_side_render.md) - - [Microservices](use_cases/microservice.md) - - [Serverless Function-As-A-Service in Public Clouds](use_cases/serverless_faas.md) - - [Serverless Software-As-A-Service Functions](use_cases/serverless_saas.md) - - [Smart devices](use_cases/smart_device.md) - - [JavaScript or Domain Specific Language Runtime](use_cases/js_or_dsl_runtime.md) - - [WasmEdge in Kubernetes](use_cases/kubernetes.md) - - [Quick start](use_cases/kubernetes/quickstart.md) - - [Demo apps](use_cases/kubernetes/demo.md) - - [Simple example](use_cases/kubernetes/demo/wasi.md) - - [HTTP service](use_cases/kubernetes/demo/server.md) - - [Container runtimes](use_cases/kubernetes/container.md) - - [crun](use_cases/kubernetes/container/crun.md) - - [runc](use_cases/kubernetes/container/runc.md) - - [youki](use_cases/kubernetes/container/youki.md) - - [CRI runtimes](use_cases/kubernetes/cri.md) - - [CRI-O](use_cases/kubernetes/cri/crio.md) - - [containerd](use_cases/kubernetes/cri/containerd.md) - - [Kubernetes](use_cases/kubernetes/kubernetes.md) - - [Kubernetes + CRI-O](use_cases/kubernetes/kubernetes/kubernetes-crio.md) - - [Kubernetes + containerd](use_cases/kubernetes/kubernetes/kubernetes-containerd.md) - - [KinD](use_cases/kubernetes/kubernetes/kind.md) - - [KubeEdge](use_cases/kubernetes/kubernetes/kubeedge.md) - - [SuperEdge](use_cases/kubernetes/kubernetes/superedge.md) - - [OpenYurt](use_cases/kubernetes/kubernetes/openyurt.md) - - [Knative](use_cases/kubernetes/kubernetes/knative.md) - - [Kwasm](use_cases/kubernetes/kubernetes/Kwasm.md) - - [Docker](use_cases/kubernetes/docker.md) - - [Slim container](use_cases/kubernetes/docker/lxc.md) - - [containerd integration](use_cases/kubernetes/docker/containerd.md) - - [App Frameworks & Platforms](use_cases/frameworks.md) - - [Service mesh & runtimes](use_cases/frameworks/mesh.md) - - [Dapr](use_cases/frameworks/mesh/dapr.md) - - [MOSN](use_cases/frameworks/mesh/mosn.md) - - [Nginx](use_cases/frameworks/mesh/wasm-nginx-module.md) - - [Apache EventMesh](use_cases/frameworks/mesh/eventmesh.md) - - [Application frameworks](use_cases/frameworks/app.md) - - [YoMo](use_cases/frameworks/app/yomo.md) - - [Reactr](use_cases/frameworks/app/reactr.md) - - [Serverless platforms](use_cases/frameworks/serverless.md) - - [Vercel](use_cases/frameworks/serverless/vercel.md) - - [Netlify](use_cases/frameworks/serverless/netlify.md) - - [AWS](use_cases/frameworks/serverless/aws.md) - - [Tencent](use_cases/frameworks/serverless/tencent.md) - - [Second State](use_cases/frameworks/serverless/secondstate.md) - -- [Write a WebAssembly Application](write_wasm.md) - - [C](write_wasm/c.md) - - [Getting Started](write_wasm/c/quickstart.md) - - [simd](write_wasm/c/simd.md) - - [Rust](write_wasm/rust.md) - - [Bindgen of Rust Functions](write_wasm/rust/bindgen.md) - - [Access OS Services](write_wasm/rust/wasi.md) - - [TensorFlow](write_wasm/rust/tensorflow.md) - - [Neural Network for WASI](write_wasm/rust/wasinn.md) - - [Crypto for WASI](write_wasm/rust/wasicrypto.md) - - [Simple HTTP Client & Server](write_wasm/rust/networking.md) - - [Simple HTTPS Client & Server](write_wasm/rust/networking-https.md) - - [Non-Blocking Network Apps](write_wasm/rust/networking-nonblocking.md) - - [Server-Side Rendering](write_wasm/rust/ssr.md) - - [Command Interface](write_wasm/rust/command.md) - - [JavaScript](write_wasm/js.md) - - [Getting Started](write_wasm/js/quickstart.md) - - [Node.js Compatibility](write_wasm/js/nodejs.md) - - [Networking Apps](write_wasm/js/networking.md) - - [React SSR](write_wasm/js/ssr.md) - - [TensorFlow](write_wasm/js/tensorflow.md) - - [ES6 Modules](write_wasm/js/es6.md) - - [Node.js & NPM Modules](write_wasm/js/npm.md) - - [Built-in Modules](write_wasm/js/modules.md) - - [Native JS API in Rust](write_wasm/js/rust.md) - - [Go](write_wasm/go.md) - - [Swift](write_wasm/swift.md) - - [AssemblyScript](write_wasm/as.md) - - [Kotlin](write_wasm/kotlin.md) - - [Grain](write_wasm/grain.md) - - [Python](write_wasm/python.md) - -- [Use WasmEdge Library](sdk.md) - - [C SDK](sdk/c.md) - - [Use the WasmEdge C Library](sdk/c/library.md) - - [Host Function Implementation](sdk/c/hostfunction.md) - - [ExternRef Example](sdk/c/externref.md) - - [Multiple Module Example](sdk/c/multimodule.md) - - [0.12.0 API references](sdk/c/ref.md) - - [0.11.2 API references](sdk/c/0.11.2/ref.md) - - [Upgrade to 0.12.0](sdk/c/0.11.2/upgrade_to_0.12.0.md) - - [0.10.1 API references](sdk/c/0.10.1/ref.md) - - [Upgrade to 0.11.0](sdk/c/0.10.1/upgrade_to_0.11.0.md) - - [0.9.1 API references](sdk/c/0.9.1/ref.md) - - [Upgrade to 0.10.0](sdk/c/0.9.1/upgrade_to_0.10.0.md) - - [Go SDK](sdk/go.md) - - [Embed WASM apps](sdk/go/app.md) - - [Embed WASM funcs](sdk/go/function.md) - - [Pass complex data](sdk/go/memory.md) - - [Tensorflow](sdk/go/tensorflow.md) - - [Embed bindgen funcs](sdk/go/bindgen.md) - - [v0.12.0 API references](sdk/go/ref.md) - - [v0.11.2 API references](sdk/go/0.11.2/ref.md) - - [Upgrade to 0.12.0](sdk/go/0.11.2/upgrade_to_0.12.0.md) - - [v0.10.1 API references](sdk/go/0.10.1/ref.md) - - [Upgrade to v0.11.0](sdk/go/0.10.1/upgrade_to_0.11.0.md) - - [v0.9.1 API references](sdk/go/0.9.1/ref.md) - - [Upgrade to v0.10.0](sdk/go/0.9.1/upgrade_to_0.10.0.md) - - [Node.js SDK](sdk/node.md) - - [Rust SDK](sdk/rust.md) - - [Hello World!](sdk/rust/say_hello.md) - - [Memory Manipulation](sdk/rust/memory_manipulation.md) - - [Table and FuncRef](sdk/rust/table_and_funcref.md) - - [Run a WebAssembly function with WasmEdge low-level APIs](sdk/rust/sys_run_host_func.md) - - [Compute Fibonacci numbers concurrently](sdk/rust/concurrent_fib.md) - - [Usage of WasmEdge module instances](sdk/rust/how_to_use_module_instance.md) - - [Python SDK](sdk/python.md) - -- [Use WasmEdge CLI](cli.md) - - [`wasmedge` WASM Runner](cli/wasmedge.md) - - [`wasmedgec` AOT Compiler](cli/wasmedge_compile.md) - - [`wasmedge run` WASM Runner](cli/wasmedge_tool.md) - -- [Develop WasmEdge Plug-in](plugin.md) - - [Develop Plug-in in C API](develop_plugin/c.md) - - [Develop Plug-in in C++](develop_plugin/cpp.md) - -- [Contribute to WasmEdge](contribute.md) - - [Release Process](contribute/release_process.md) - - [Contribute Steps](contribute/contribute.md) - - [Build WasmEdge from source](contribute/build_from_src.md) - - [Build on Linux](contribute/build_from_src/linux.md) - - [Build on MacOS](contribute/build_from_src/macos.md) - - [Build on Windows](contribute/build_from_src/windows.md) - - [Build for Android](contribute/build_from_src/android.md) - - [CLI tools](contribute/build_from_src/android/cli.md) - - [NDK native app](contribute/build_from_src/android/ndk.md) - - [APK app](contribute/build_from_src/android/apk.md) - - [Build for seL4](contribute/build_from_src/sel4.md) - - [Build for OpenHarmony](contribute/build_from_src/openharmony.md) - - [Build for Raspberry Pi](contribute/build_from_src/raspberrypi.md) - - [Build for OpenWrt](contribute/build_from_src/openwrt.md) - - [Build with WASI-Crypto Plug-in](contribute/build_from_src/plugin_wasi_crypto.md) - - [Build with WASI-Logging Plug-in](contribute/build_from_src/plugin_wasi_logging.md) - - [Build with WASI-NN Plug-in](contribute/build_from_src/plugin_wasi_nn.md) - - [Build with WasmEdge-process Plug-in](contribute/build_from_src/plugin_wasmedge_process.md) - - [WasmEdge Installer Guide](contribute/installer.md) - - [WasmEdge Internal](contribute/internal.md) - - [Wish List](contribute/wish_list.md) diff --git a/docs/book/en/src/cli.md b/docs/book/en/src/cli.md deleted file mode 100644 index 9ee34e840308..000000000000 --- a/docs/book/en/src/cli.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Command Line Tools - -> This part has been moved to <https://wasmedge.org/docs/start/build-and-run/cli>. Please use our new docs. diff --git a/docs/book/en/src/cli/wasmedge.md b/docs/book/en/src/cli/wasmedge.md deleted file mode 100644 index 9b29f85537c7..000000000000 --- a/docs/book/en/src/cli/wasmedge.md +++ /dev/null @@ -1,3 +0,0 @@ -# `wasmedge` CLI - -This part has been moved to <https://wasmedge.org/docs/start/build-and-run/cli>. Please use our new docs. diff --git a/docs/book/en/src/cli/wasmedge_compile.md b/docs/book/en/src/cli/wasmedge_compile.md deleted file mode 100644 index 121efd5b7bcb..000000000000 --- a/docs/book/en/src/cli/wasmedge_compile.md +++ /dev/null @@ -1,4 +0,0 @@ -# `wasmedge compile` CLI - -> This part has been moved to <https://wasmedge.org/docs/start/build-and-run/aot>. Please use our new docs. - diff --git a/docs/book/en/src/cli/wasmedge_tool.md b/docs/book/en/src/cli/wasmedge_tool.md deleted file mode 100644 index d39bb08851ba..000000000000 --- a/docs/book/en/src/cli/wasmedge_tool.md +++ /dev/null @@ -1,3 +0,0 @@ -# `wasmedge run` CLI - -> This part has been moved to <https://wasmedge.org/docs/start/build-and-run/run>. Please use our new docs. diff --git a/docs/book/en/src/contribute.md b/docs/book/en/src/contribute.md deleted file mode 100644 index a1a4fa679921..000000000000 --- a/docs/book/en/src/contribute.md +++ /dev/null @@ -1,3 +0,0 @@ -# Contribute to WasmEdge - -> This part has been moved to <https://wasmedge.org/docs/contribute/>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src.md b/docs/book/en/src/contribute/build_from_src.md deleted file mode 100644 index 3de18d85e2b9..000000000000 --- a/docs/book/en/src/contribute/build_from_src.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build WasmEdge from source - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/build_from_src>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/android.md b/docs/book/en/src/contribute/build_from_src/android.md deleted file mode 100644 index 7cf700fef40e..000000000000 --- a/docs/book/en/src/contribute/build_from_src/android.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build WasmEdge for Android - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/os/android/build>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/android/apk.md b/docs/book/en/src/contribute/build_from_src/android/apk.md deleted file mode 100644 index 69c91e50ba4a..000000000000 --- a/docs/book/en/src/contribute/build_from_src/android/apk.md +++ /dev/null @@ -1,3 +0,0 @@ -# Call WasmEdge functions from an Android APK app - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/os/android/apk>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/android/cli.md b/docs/book/en/src/contribute/build_from_src/android/cli.md deleted file mode 100644 index 4bf8265259e5..000000000000 --- a/docs/book/en/src/contribute/build_from_src/android/cli.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge CLI tools for Android - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/os/android/cli>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/android/ndk.md b/docs/book/en/src/contribute/build_from_src/android/ndk.md deleted file mode 100644 index ee02aab347f8..000000000000 --- a/docs/book/en/src/contribute/build_from_src/android/ndk.md +++ /dev/null @@ -1,3 +0,0 @@ -# Call WasmEdge functions from an NDK native app - -> *This part has moved to <https://wasmedge.org/docs/contribute/source/os/android/ndk>. Please use our new docs.* diff --git a/docs/book/en/src/contribute/build_from_src/linux.md b/docs/book/en/src/contribute/build_from_src/linux.md deleted file mode 100644 index 2ea30cfa65c0..000000000000 --- a/docs/book/en/src/contribute/build_from_src/linux.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build WasmEdge on Linux - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/os/linux>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/macos.md b/docs/book/en/src/contribute/build_from_src/macos.md deleted file mode 100644 index 6b9ae190c330..000000000000 --- a/docs/book/en/src/contribute/build_from_src/macos.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build WasmEdge on MacOS - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/os/macos>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/openharmony.md b/docs/book/en/src/contribute/build_from_src/openharmony.md deleted file mode 100644 index 34a93a1cd959..000000000000 --- a/docs/book/en/src/contribute/build_from_src/openharmony.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build WasmEdge for Open Harmony - -WIP. For Chinese speakers, please [check out this instruction](https://github.com/WasmEdge/WasmEdge/blob/master/utils/ohos/README-zh.md). diff --git a/docs/book/en/src/contribute/build_from_src/openwrt.md b/docs/book/en/src/contribute/build_from_src/openwrt.md deleted file mode 100644 index 79e93c161a32..000000000000 --- a/docs/book/en/src/contribute/build_from_src/openwrt.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build and test WasmEdge for OpenWrt - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/os/openwrt>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/plugin_wasi_crypto.md b/docs/book/en/src/contribute/build_from_src/plugin_wasi_crypto.md deleted file mode 100644 index 6ade73db56ae..000000000000 --- a/docs/book/en/src/contribute/build_from_src/plugin_wasi_crypto.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build WasmEdge With WASI-Crypto Plug-in - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/plugin/wasi_crypto>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/plugin_wasi_logging.md b/docs/book/en/src/contribute/build_from_src/plugin_wasi_logging.md deleted file mode 100644 index 10510663874a..000000000000 --- a/docs/book/en/src/contribute/build_from_src/plugin_wasi_logging.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build WasmEdge With WASI-Logging Plug-in - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/plugin/wasi_logging>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/plugin_wasi_nn.md b/docs/book/en/src/contribute/build_from_src/plugin_wasi_nn.md deleted file mode 100644 index ac858f66ede1..000000000000 --- a/docs/book/en/src/contribute/build_from_src/plugin_wasi_nn.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build WasmEdge With WASI-NN Plug-in - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/plugin/wasi_nn>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/plugin_wasmedge_process.md b/docs/book/en/src/contribute/build_from_src/plugin_wasmedge_process.md deleted file mode 100644 index 6f9590e23ad9..000000000000 --- a/docs/book/en/src/contribute/build_from_src/plugin_wasmedge_process.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build WasmEdge With WasmEdge-Process Plug-in - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/plugin/process>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/raspberrypi.md b/docs/book/en/src/contribute/build_from_src/raspberrypi.md deleted file mode 100644 index 65eecd7e7a92..000000000000 --- a/docs/book/en/src/contribute/build_from_src/raspberrypi.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build WasmEdge for Raspberry Pi 3/4 - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/os/raspberrypi>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/riscv64.md b/docs/book/en/src/contribute/build_from_src/riscv64.md deleted file mode 100644 index b0354c9e24b5..000000000000 --- a/docs/book/en/src/contribute/build_from_src/riscv64.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build and test WasmEdge on RISC-V 64 arch - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/os/riscv64>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/sel4.md b/docs/book/en/src/contribute/build_from_src/sel4.md deleted file mode 100644 index 55a816134376..000000000000 --- a/docs/book/en/src/contribute/build_from_src/sel4.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build WasmEdge for seL4 - -This part hs moved to <https://wasmedge.org/docs/contribute/source/os/sel4>. Please use our new docs. diff --git a/docs/book/en/src/contribute/build_from_src/windows.md b/docs/book/en/src/contribute/build_from_src/windows.md deleted file mode 100644 index eb58a00aad44..000000000000 --- a/docs/book/en/src/contribute/build_from_src/windows.md +++ /dev/null @@ -1,3 +0,0 @@ -# Build WasmEdge on Windows 10 - -> This part has been moved to <https://wasmedge.org/docs/contribute/source/os/windows>. Please use our new docs. diff --git a/docs/book/en/src/contribute/contribute.md b/docs/book/en/src/contribute/contribute.md deleted file mode 100644 index eaba062657e5..000000000000 --- a/docs/book/en/src/contribute/contribute.md +++ /dev/null @@ -1,3 +0,0 @@ -# Contribution Steps - -> This part has been moved to <https://wasmedge.org/docs/contribute/>. Please use our new docs. diff --git a/docs/book/en/src/contribute/installer.md b/docs/book/en/src/contribute/installer.md deleted file mode 100644 index c05ff5d2a23e..000000000000 --- a/docs/book/en/src/contribute/installer.md +++ /dev/null @@ -1,3 +0,0 @@ -# Installer Guide - -> This part has been moved to <https://wasmedge.org/docs/contribute/installer>. Please use our new docs. diff --git a/docs/book/en/src/contribute/internal.md b/docs/book/en/src/contribute/internal.md deleted file mode 100644 index 313f9fd83064..000000000000 --- a/docs/book/en/src/contribute/internal.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Internal - -> This part has been moved to <https://wasmedge.org/docs/contribute/internal>. Please use our new docs. diff --git a/docs/book/en/src/contribute/release_process.md b/docs/book/en/src/contribute/release_process.md deleted file mode 100644 index 58c387017197..000000000000 --- a/docs/book/en/src/contribute/release_process.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Release Process - -> This part has been moved to <https://wasmedge.org/docs/contribute/release>. Please use our new docs. diff --git a/docs/book/en/src/contribute/wish_list.md b/docs/book/en/src/contribute/wish_list.md deleted file mode 100644 index 508c7121a96a..000000000000 --- a/docs/book/en/src/contribute/wish_list.md +++ /dev/null @@ -1,3 +0,0 @@ -# Wish list - -> This part has been moved to <https://wasmedge.org/docs/contribute/overview#ideas-for-contributions>. Please use our new docs. diff --git a/docs/book/en/src/develop_plugin/c.md b/docs/book/en/src/develop_plugin/c.md deleted file mode 100644 index 3a9bca6d8723..000000000000 --- a/docs/book/en/src/develop_plugin/c.md +++ /dev/null @@ -1,3 +0,0 @@ -# Develop WasmEdge Plug-in in C API - -This part has been moved to <https://wasmedge.org/docs/contribute/plugin/develop_plugin_c>. Please use our new docs. diff --git a/docs/book/en/src/develop_plugin/cpp.md b/docs/book/en/src/develop_plugin/cpp.md deleted file mode 100644 index 41ea497a85cf..000000000000 --- a/docs/book/en/src/develop_plugin/cpp.md +++ /dev/null @@ -1,3 +0,0 @@ -# Develop WasmEdge Plug-in in C++ API - -This part has been moved to <https://wasmedge.org/docs/contribute/plugin/develop_plugin_cpp>. Please use our new docs. diff --git a/docs/book/en/src/develop_plugin/rust-sdk.md b/docs/book/en/src/develop_plugin/rust-sdk.md deleted file mode 100644 index d4095409dda4..000000000000 --- a/docs/book/en/src/develop_plugin/rust-sdk.md +++ /dev/null @@ -1,3 +0,0 @@ -# Develop Plugin Rust SDK with witc - -> This part has been moved to <https://wasmedge.org/docs/contribute/plugin/develop_plugin_rustsdk/>. Please use our new docs. diff --git a/docs/book/en/src/features.md b/docs/book/en/src/features.md deleted file mode 100644 index f0430199a746..000000000000 --- a/docs/book/en/src/features.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Features - -> This Part has been moved to<https://wasmedge.org/docs/start/wasmedge/features>. Please use our new docs. diff --git a/docs/book/en/src/features/comparison.md b/docs/book/en/src/features/comparison.md deleted file mode 100644 index c4beb4cccff6..000000000000 --- a/docs/book/en/src/features/comparison.md +++ /dev/null @@ -1,3 +0,0 @@ -# Comparison - -// TODO: TBD in New Docs - @adithyaakrishna diff --git a/docs/book/en/src/features/integrations.md b/docs/book/en/src/features/integrations.md deleted file mode 100644 index e07470bc6234..000000000000 --- a/docs/book/en/src/features/integrations.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Integrations - -> This part has been moved to <https://wasmedge.org/docs/start/wasmedge/integrations>. Please use our new docs. diff --git a/docs/book/en/src/features/platforms.md b/docs/book/en/src/features/platforms.md deleted file mode 100644 index 524cf53fe229..000000000000 --- a/docs/book/en/src/features/platforms.md +++ /dev/null @@ -1,3 +0,0 @@ -# Supported Platforms - -> This part has been moved to <https://wasmedge.org/docs/start/wasmedge/features#cross-platform>. Please use our new docs. diff --git a/docs/book/en/src/features/proposals.md b/docs/book/en/src/features/proposals.md deleted file mode 100644 index 6b10534a8319..000000000000 --- a/docs/book/en/src/features/proposals.md +++ /dev/null @@ -1,3 +0,0 @@ -# Supported WASM And WASI Proposals - -> This part has been moved to <https://wasmedge.org/docs/start/wasmedge/extensions/proposals>. Please use our new docs. \ No newline at end of file diff --git a/docs/book/en/src/features/proprietary_extend.md b/docs/book/en/src/features/proprietary_extend.md deleted file mode 100644 index c66c81cc9bc6..000000000000 --- a/docs/book/en/src/features/proprietary_extend.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Proprietary Extensions - -> This part has been moved to <https://wasmedge.org/docs/develop/wasmedge/extensions/unique_extensions>. Please use our new docs. diff --git a/docs/book/en/src/index.md b/docs/book/en/src/index.md deleted file mode 100644 index a3705f8e48f3..000000000000 --- a/docs/book/en/src/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Introduction - -> This Part has been moved to<https://wasmedge.org/docs/develop/overview>. Please use our new docs. diff --git a/docs/book/en/src/plugin.md b/docs/book/en/src/plugin.md deleted file mode 100644 index 8a3506b0d34d..000000000000 --- a/docs/book/en/src/plugin.md +++ /dev/null @@ -1,3 +0,0 @@ -# Develop WasmEdge Plug-in - -> This Part has been moved to <https://wasmedge.org/docs/contribute/plugin/intro>, Please use our new docs.. diff --git a/docs/book/en/src/quick_start.md b/docs/book/en/src/quick_start.md deleted file mode 100644 index 90f4db8423ef..000000000000 --- a/docs/book/en/src/quick_start.md +++ /dev/null @@ -1,3 +0,0 @@ -# Quick Start - -> This part has been moved to <https://wasmedge.org/docs/category/getting-started-with-wasmedge>. Please use our new docs. \ No newline at end of file diff --git a/docs/book/en/src/quick_start/install.md b/docs/book/en/src/quick_start/install.md deleted file mode 100644 index 2feec05f9c51..000000000000 --- a/docs/book/en/src/quick_start/install.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Installation And Uninstallation - -> This part has been moved to <https://wasmedge.org/docs/start/install>. Please use our new docs. \ No newline at end of file diff --git a/docs/book/en/src/quick_start/run_cli.md b/docs/book/en/src/quick_start/run_cli.md deleted file mode 100644 index 4d5bf2af8627..000000000000 --- a/docs/book/en/src/quick_start/run_cli.md +++ /dev/null @@ -1,3 +0,0 @@ -# Running WASM with WasmEdge CLI - -> This part has been moved to <https://wasmedge.org/docs/start/build-and-run/cli>. Please use our new docs. \ No newline at end of file diff --git a/docs/book/en/src/quick_start/run_in_aot_mode.md b/docs/book/en/src/quick_start/run_in_aot_mode.md deleted file mode 100644 index 792471edc36c..000000000000 --- a/docs/book/en/src/quick_start/run_in_aot_mode.md +++ /dev/null @@ -1,3 +0,0 @@ -# Execution in AOT Mode - -> This part has been moved to <https://wasmedge.org/docs/start/build-and-run/aot>. Please use our new docs. diff --git a/docs/book/en/src/quick_start/use_docker.md b/docs/book/en/src/quick_start/use_docker.md deleted file mode 100644 index e2ae193b3664..000000000000 --- a/docs/book/en/src/quick_start/use_docker.md +++ /dev/null @@ -1,3 +0,0 @@ -# Using WasmEdge in Docker - -> This part has been moved to <https://wasmedge.org/docs/develop/deploy/kubernetes/docker-slim>. Please use our new docs. \ No newline at end of file diff --git a/docs/book/en/src/sdk.md b/docs/book/en/src/sdk.md deleted file mode 100644 index 5062ed7d0781..000000000000 --- a/docs/book/en/src/sdk.md +++ /dev/null @@ -1,3 +0,0 @@ -# Use WasmEdge Library in Programming Languages - -> This doc has been moved to <https://wasmedge.org/docs/embed/overview>. Please use our new docs. diff --git a/docs/book/en/src/sdk/c++.md b/docs/book/en/src/sdk/c++.md deleted file mode 100644 index b1e7486d1e27..000000000000 --- a/docs/book/en/src/sdk/c++.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge C++ SDK - -> This part has been moved to <https://wasmedge.org/docs/embed/c++/intro>. Please use our new docs. \ No newline at end of file diff --git a/docs/book/en/src/sdk/c.md b/docs/book/en/src/sdk/c.md deleted file mode 100644 index 72085fffb334..000000000000 --- a/docs/book/en/src/sdk/c.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge C SDK - -> This part has been moved to <https://wasmedge.org/docs/embed/c/intro>. Please use our new docs. diff --git a/docs/book/en/src/sdk/c/0.10.1/ref.md b/docs/book/en/src/sdk/c/0.10.1/ref.md deleted file mode 100644 index e96bd795bd55..000000000000 --- a/docs/book/en/src/sdk/c/0.10.1/ref.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge 0.10.1 C API Documentation - -> This part has been moved to <https://wasmedge.org/docs/embed/c/reference/0.10.x>. Please use our new docs. diff --git a/docs/book/en/src/sdk/c/0.10.1/upgrade_to_0.11.0.md b/docs/book/en/src/sdk/c/0.10.1/upgrade_to_0.11.0.md deleted file mode 100644 index f65817ba5a79..000000000000 --- a/docs/book/en/src/sdk/c/0.10.1/upgrade_to_0.11.0.md +++ /dev/null @@ -1,3 +0,0 @@ -# Upgrade to WasmEdge 0.11.0 - -> This part has been moved to <https://wasmedge.org/docs/embed/c/reference/upgrade_to_0.11.0>. Please use our new docs. diff --git a/docs/book/en/src/sdk/c/0.11.2/ref.md b/docs/book/en/src/sdk/c/0.11.2/ref.md deleted file mode 100644 index 0304e4332f1e..000000000000 --- a/docs/book/en/src/sdk/c/0.11.2/ref.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge C 0.11.2 API Documentation - -This part has moved to <https://wasmedge.org/docs/embed/c/reference/0.11.x>. Please use our new docs. diff --git a/docs/book/en/src/sdk/c/0.11.2/upgrade_to_0.12.0.md b/docs/book/en/src/sdk/c/0.11.2/upgrade_to_0.12.0.md deleted file mode 100644 index 5dce86178c01..000000000000 --- a/docs/book/en/src/sdk/c/0.11.2/upgrade_to_0.12.0.md +++ /dev/null @@ -1,3 +0,0 @@ -# Upgrade to WasmEdge 0.12.0 - -Thias part has moved to <https://wasmedge.org/docs/embed/c/reference/upgrade_to_0.12.0>. Please use our new docs. diff --git a/docs/book/en/src/sdk/c/0.9.1/ref.md b/docs/book/en/src/sdk/c/0.9.1/ref.md deleted file mode 100644 index bac78bba51ff..000000000000 --- a/docs/book/en/src/sdk/c/0.9.1/ref.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge 0.9.1 C API Documentation - -> This part has been moved to <https://wasmedge.org/docs/embed/c/reference/0.9.x>. Please use our new docs. diff --git a/docs/book/en/src/sdk/c/0.9.1/upgrade_to_0.10.0.md b/docs/book/en/src/sdk/c/0.9.1/upgrade_to_0.10.0.md deleted file mode 100644 index 26c3811d35d3..000000000000 --- a/docs/book/en/src/sdk/c/0.9.1/upgrade_to_0.10.0.md +++ /dev/null @@ -1,3 +0,0 @@ -# Upgrade to WasmEdge 0.10.0 - -> This part has been moved to <https://wasmedge.org/docs/embed/c/reference/upgrade_to_0.10.0>. Please use our new docs. diff --git a/docs/book/en/src/sdk/c/externref.md b/docs/book/en/src/sdk/c/externref.md deleted file mode 100644 index 133c1e3886a5..000000000000 --- a/docs/book/en/src/sdk/c/externref.md +++ /dev/null @@ -1,3 +0,0 @@ -# Customized External References - -> This part has been moved to <https://wasmedge.org/docs/embed/c/externref>. Please use our new docs. diff --git a/docs/book/en/src/sdk/c/hostfunction.md b/docs/book/en/src/sdk/c/hostfunction.md deleted file mode 100644 index f3c09747a20d..000000000000 --- a/docs/book/en/src/sdk/c/hostfunction.md +++ /dev/null @@ -1,3 +0,0 @@ -# Host Functions - -> This part has been moved to <https://wasmedge.org/docs/embed/c/host_function>. Please use our new docs. diff --git a/docs/book/en/src/sdk/c/library.md b/docs/book/en/src/sdk/c/library.md deleted file mode 100644 index 615cea585b31..000000000000 --- a/docs/book/en/src/sdk/c/library.md +++ /dev/null @@ -1,3 +0,0 @@ -# Use the WasmEdge Library - -> This part has been moved to <https://wasmedge.org/docs/embed/c/library>. Please use our new docs. diff --git a/docs/book/en/src/sdk/c/multimodule.md b/docs/book/en/src/sdk/c/multimodule.md deleted file mode 100644 index 0d06ecb9e3b2..000000000000 --- a/docs/book/en/src/sdk/c/multimodule.md +++ /dev/null @@ -1,3 +0,0 @@ -# Multiple WASM Module Example - -> This part has been moved to <https://wasmedge.org/docs/embed/c/multiple_modules>. Please use our new docs. diff --git a/docs/book/en/src/sdk/c/ref.md b/docs/book/en/src/sdk/c/ref.md deleted file mode 100644 index 9923ddad3ed3..000000000000 --- a/docs/book/en/src/sdk/c/ref.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge C 0.12.0 API Documentation - -> This part has been moved to <https://wasmedge.org/docs/embed/c/reference/0.12.x>. Please use our new docs. diff --git a/docs/book/en/src/sdk/go.md b/docs/book/en/src/sdk/go.md deleted file mode 100644 index 76e92aea824d..000000000000 --- a/docs/book/en/src/sdk/go.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Go SDK - -> This part has been moved to <https://wasmedge.org/docs/embed/go/intro>. Please use our new doc. diff --git a/docs/book/en/src/sdk/go/0.10.1/ref.md b/docs/book/en/src/sdk/go/0.10.1/ref.md deleted file mode 100644 index 47e5e04c3134..000000000000 --- a/docs/book/en/src/sdk/go/0.10.1/ref.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Go v0.10.1 API references - -> This part has been moved to <https://wasmedge.org/docs/embed/go/reference/0.10.x>. Please use our new docs. diff --git a/docs/book/en/src/sdk/go/0.10.1/upgrade_to_0.11.0.md b/docs/book/en/src/sdk/go/0.10.1/upgrade_to_0.11.0.md deleted file mode 100644 index 35dd88138fa3..000000000000 --- a/docs/book/en/src/sdk/go/0.10.1/upgrade_to_0.11.0.md +++ /dev/null @@ -1,3 +0,0 @@ -# Upgrade to WasmEdge-Go v0.11.0 - -> This part has been moved to <https://wasmedge.org/docs/embed/go/reference/upgrade_to_0.11.0>. Please use our new docs. diff --git a/docs/book/en/src/sdk/go/0.11.2/ref.md b/docs/book/en/src/sdk/go/0.11.2/ref.md deleted file mode 100644 index 06683497d050..000000000000 --- a/docs/book/en/src/sdk/go/0.11.2/ref.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Go v0.11.2 API references - -> This part has been moved to <https://wasmedge.org/docs/embed/go/reference/0.11.x>. Please use our new docs. diff --git a/docs/book/en/src/sdk/go/0.11.2/upgrade_to_0.12.0.md b/docs/book/en/src/sdk/go/0.11.2/upgrade_to_0.12.0.md deleted file mode 100644 index ef37818350a7..000000000000 --- a/docs/book/en/src/sdk/go/0.11.2/upgrade_to_0.12.0.md +++ /dev/null @@ -1,3 +0,0 @@ -# Upgrade to WasmEdge-Go v0.12.0 - -> This part has been moved to <https://wasmedge.org/docs/embed/go/reference/upgrade_to_0.12.0>. Please use our new docs. diff --git a/docs/book/en/src/sdk/go/0.9.1/ref.md b/docs/book/en/src/sdk/go/0.9.1/ref.md deleted file mode 100644 index 9e963be4b596..000000000000 --- a/docs/book/en/src/sdk/go/0.9.1/ref.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Go v0.9.1 API Documentation - -> This part has been moved to <https://wasmedge.org/docs/embed/go/reference/0.9.x>. Please use our new docs. diff --git a/docs/book/en/src/sdk/go/0.9.1/upgrade_to_0.10.0.md b/docs/book/en/src/sdk/go/0.9.1/upgrade_to_0.10.0.md deleted file mode 100644 index 2a8bf1f2b792..000000000000 --- a/docs/book/en/src/sdk/go/0.9.1/upgrade_to_0.10.0.md +++ /dev/null @@ -1,3 +0,0 @@ -# Upgrade to WasmEdge-Go v0.10.0 - -> This part has been moved to <https://wasmedge.org/docs/embed/go/reference/upgrade_to_0.10.0>. Please use our new docs. diff --git a/docs/book/en/src/sdk/go/app.md b/docs/book/en/src/sdk/go/app.md deleted file mode 100644 index 7a47b8bf932a..000000000000 --- a/docs/book/en/src/sdk/go/app.md +++ /dev/null @@ -1,3 +0,0 @@ -# Embed a standalone WASM app - -> This part has been moved to <https://wasmedge.org/docs/embed/go/app>. Please use our new docs. diff --git a/docs/book/en/src/sdk/go/bindgen.md b/docs/book/en/src/sdk/go/bindgen.md deleted file mode 100644 index 3fe051921c2e..000000000000 --- a/docs/book/en/src/sdk/go/bindgen.md +++ /dev/null @@ -1,3 +0,0 @@ -# Embed a bindgen function - -> This part has been moved to <https://wasmedge.org/docs/embed/go/bindgen>. Please use our new docs. diff --git a/docs/book/en/src/sdk/go/function.md b/docs/book/en/src/sdk/go/function.md deleted file mode 100644 index 0b977f922852..000000000000 --- a/docs/book/en/src/sdk/go/function.md +++ /dev/null @@ -1,3 +0,0 @@ -# Embed a Wasm function - -> This part has been moved to <https://wasmedge.org/docs/embed/go/function>. Please use our new docs. diff --git a/docs/book/en/src/sdk/go/memory.md b/docs/book/en/src/sdk/go/memory.md deleted file mode 100644 index 92ba8f458794..000000000000 --- a/docs/book/en/src/sdk/go/memory.md +++ /dev/null @@ -1,3 +0,0 @@ -# Pass complex parameters to Wasm functions - -> This part has been moved to <https://wasmedge.org/docs/embed/go/passing_data>. Please use pur new docs. diff --git a/docs/book/en/src/sdk/go/ref.md b/docs/book/en/src/sdk/go/ref.md deleted file mode 100644 index c809bf8d60d8..000000000000 --- a/docs/book/en/src/sdk/go/ref.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Go v0.12.0 API references - -This part has been moved to <https://wasmedge.org/docs/embed/go/reference/0.12.x>. Please use our new docs. diff --git a/docs/book/en/src/sdk/go/tensorflow.md b/docs/book/en/src/sdk/go/tensorflow.md deleted file mode 100644 index 9ec58f595f8c..000000000000 --- a/docs/book/en/src/sdk/go/tensorflow.md +++ /dev/null @@ -1,3 +0,0 @@ -# Tensorflow - -This part has moved to <https://wasmedge.org/docs/embed/go/ai>. Please use our new docs. diff --git a/docs/book/en/src/sdk/python.md b/docs/book/en/src/sdk/python.md deleted file mode 100644 index b826af88a923..000000000000 --- a/docs/book/en/src/sdk/python.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Python SDK - -Coming soon, or you can [help out](https://github.com/WasmEdge/WasmEdge/pull/633). diff --git a/docs/book/en/src/sdk/rust.md b/docs/book/en/src/sdk/rust.md deleted file mode 100644 index 348432d4c8b4..000000000000 --- a/docs/book/en/src/sdk/rust.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Rust SDK - -> This part has been moved to <https://wasmedge.org/docs/embed/rust/intro>. Please use our new docs. diff --git a/docs/book/en/src/sdk/rust/concurrent_fib.md b/docs/book/en/src/sdk/rust/concurrent_fib.md deleted file mode 100644 index d03ba3d7194f..000000000000 --- a/docs/book/en/src/sdk/rust/concurrent_fib.md +++ /dev/null @@ -1,85 +0,0 @@ -# Compute Fibonacci numbers concurrently - -## Overview - -In this example, we will demonstrate how to use the objects and the APIs defined in `wasmedge-sys` to compute Fibonacci numbers concurrently. we creates two child threads, `thread_a` and `thread_b`, which are responsible for compute `Fib(4)` and `Fib(5)` by calling the host function `fib`, respectively. After that, the main thread computes `Fib(6)` by adding the numbers returned by `thread_a` and `thread_b`. - -> The code in the example is verified on -> -> * wasmedge-sys v0.10.0 -> * wasmedge-types v0.3.0 - -### Step 1: create a Vm context and register the WebAssembly module - - ```rust - // create a Config context - let mut config = Config::create()?; - config.bulk_memory_operations(true); - - // create a Store context - let mut store = Store::create()?; - - // create a Vm context with the given Config and Store - let mut vm = Vm::create(Some(config), Some(&mut store))?; - - // register a wasm module from a wasm file - let file = std::path::PathBuf::from(env!("WASMEDGE_DIR")) - .join("bindings/rust/wasmedge-sys/tests/data/fibonacci.wasm"); - vm.register_wasm_from_file("extern", file)?; - - ``` - -### Step 2: create two child threads to compute `Fib(4)` and `Fib(5)` respectively - - ```rust - let vm = Arc::new(Mutex::new(vm)); - - // compute fib(4) by a child thread - let vm_cloned = Arc::clone(&vm); - let handle_a = thread::spawn(move || { - let vm_child_thread = vm_cloned.lock().expect("fail to lock vm"); - let returns = vm_child_thread - .run_registered_function("extern", "fib", [WasmValue::from_i32(4)]) - .expect("fail to compute fib(4)"); - - let fib4 = returns[0].to_i32(); - println!("fib(4) by child thread: {}", fib4); - - fib4 - }); - - // compute fib(5) by a child thread - let vm_cloned = Arc::clone(&vm); - let handle_b = thread::spawn(move || { - let vm_child_thread = vm_cloned.lock().expect("fail to lock vm"); - let returns = vm_child_thread - .run_registered_function("extern", "fib", [WasmValue::from_i32(5)]) - .expect("fail to compute fib(5)"); - - let fib5 = returns[0].to_i32(); - println!("fib(5) by child thread: {}", fib5); - - fib5 - }); - - ``` - -### Step3: Get the returns from the two child threads, and compute `Fib(6)` - - ```Rust - let fib4 = handle_a.join().unwrap(); - let fib5 = handle_b.join().unwrap(); - - // compute fib(6) - println!("fib(6) = fib(5) + fib(1) = {}", fib5 + fib4); - ``` - -The final result of the code above should be printed on the screen like below: - -```bash -fib(4) by child thread: 5 -fib(5) by child thread: 8 -fib(6) = fib(5) + fib(1) = 13 -``` - -The complete code in this demo can be found in [threads.rs](https://github.com/WasmEdge/WasmEdge/blob/master/bindings/rust/wasmedge-sys/examples/threads.rs). diff --git a/docs/book/en/src/sdk/rust/how_to_use_module_instance.md b/docs/book/en/src/sdk/rust/how_to_use_module_instance.md deleted file mode 100644 index 14b6a9937818..000000000000 --- a/docs/book/en/src/sdk/rust/how_to_use_module_instance.md +++ /dev/null @@ -1,301 +0,0 @@ -# Introduction to WasmEdge module instance - -> The code in the following examples are verified on -> -> * wasmedge-sys v0.10.0 -> * wasmedge-types v0.3.0 - -## Example 1 - -In this example, we'll demonstrate how to use the APIs of `Vm` to - -* Create Wasi and WasmEdgeProcess module instances implicitly by using a `Config` while creating a `Vm`. - - ```rust - // create a Config context - let mut config = Config::create()?; - config.bulk_memory_operations(true); - assert!(config.bulk_memory_operations_enabled()); - config.wasi(true); - assert!(config.wasi_enabled()); - config.wasmedge_process(true); - assert!(config.wasmedge_process_enabled()); - - // create a Vm context with the given Config and Store - let mut vm = Vm::create(Some(config), None)?; - - ``` - -* Retrieve the Wasi and WasmEdgeProcess module instances from the `Vm`. - - ```rust - // get the default Wasi module - let wasi_instance = vm.wasi_module_mut()?; - assert_eq!(wasi_instance.name(), "wasi_snapshot_preview1"); - // get the default WasmEdgeProcess module instance - let wasmedge_process_instance = vm.wasmedge_process_module_mut()?; - assert_eq!(wasmedge_process_instance.name(), "wasmedge_process"); - - ``` - -* Register an import module as a named module into the `Vm`. - - ```rust - // create ImportModule instance - let module_name = "extern_module"; - let mut import = ImportModule::create(module_name)?; - - // a function to import - #[sys_host_function] - fn real_add(_frame: &CallingFrame, inputs: Vec<WasmValue>) -> Result<Vec<WasmValue>, u8> { - if inputs.len() != 2 { - return Err(1); - } - - let a = if inputs[0].ty() == ValType::I32 { - inputs[0].to_i32() - } else { - return Err(2); - }; - - let b = if inputs[1].ty() == ValType::I32 { - inputs[1].to_i32() - } else { - return Err(3); - }; - - let c = a + b; - - Ok(vec![WasmValue::from_i32(c)]) - } - - // add host function - let func_ty = FuncType::create(vec![ValType::I32; 2], vec![ValType::I32])?; - let host_func = Function::create(&func_ty, Box::new(real_add), 0)?; - import.add_func("add", host_func); - - // add table - let table_ty = TableType::create(RefType::FuncRef, 0..=u32::MAX)?; - let table = Table::create(&table_ty)?; - import.add_table("table", table); - - // add memory - let mem_ty = MemType::create(0..=u32::MAX)?; - let memory = Memory::create(&mem_ty)?; - import.add_memory("mem", memory); - - // add global - let ty = GlobalType::create(ValType::F32, Mutability::Const)?; - let global = Global::create(&ty, WasmValue::from_f32(3.5))?; - import.add_global("global", global); - - // register the import module as a named module - vm.register_wasm_from_import(ImportObject::Import(import))?; - - ``` - -* Retrieve the internal `Store` instance from the `Vm`, and retrieve the named module instance from the `Store` instance. - - ```rust - let mut store = vm.store_mut()?; - let named_instance = store.module(module_name)?; - assert!(named_instance.get_func("add").is_ok()); - assert!(named_instance.get_table("table").is_ok()); - assert!(named_instance.get_memory("mem").is_ok()); - assert!(named_instance.get_global("global").is_ok()); - - ``` - -* Register an active module into the `Vm`. - - ```rust - // read the wasm bytes - let wasm_bytes = wat2wasm( - br#" - (module - (export "fib" (func $fib)) - (func $fib (param $n i32) (result i32) - (if - (i32.lt_s - (get_local $n) - (i32.const 2) - ) - (return - (i32.const 1) - ) - ) - (return - (i32.add - (call $fib - (i32.sub - (get_local $n) - (i32.const 2) - ) - ) - (call $fib - (i32.sub - (get_local $n) - (i32.const 1) - ) - ) - ) - ) - ) - ) - "#, - )?; - - // load a wasm module from a in-memory bytes, and the loaded wasm module works as an anonymous - // module (aka. active module in WasmEdge terminology) - vm.load_wasm_from_bytes(&wasm_bytes)?; - - // validate the loaded active module - vm.validate()?; - - // instantiate the loaded active module - vm.instantiate()?; - - // get the active module instance - let active_instance = vm.active_module()?; - assert!(active_instance.get_func("fib").is_ok()); - - ``` - -* Retrieve the active module from the `Vm`. - - ```rust - // get the active module instance - let active_instance = vm.active_module()?; - assert!(active_instance.get_func("fib").is_ok()); - - ``` - -The complete code in this demo can be found on [WasmEdge Github](https://github.com/WasmEdge/WasmEdge/blob/master/bindings/rust/wasmedge-sys/examples/mdbook_example_module_instance.rs). - -## Example 2 - -In this example, we'll demonstrate how to use the APIs of `Executor` to - -* Create an `Executor` and a `Store`. - - ```rust - // create an Executor context - let mut executor = Executor::create(None, None)?; - - // create a Store context - let mut store = Store::create()?; - - ``` - -* Register an import module into the `Executor`. - - ```rust - // read the wasm bytes - let wasm_bytes = wat2wasm( - br#" - (module - (export "fib" (func $fib)) - (func $fib (param $n i32) (result i32) - (if - (i32.lt_s - (get_local $n) - (i32.const 2) - ) - (return - (i32.const 1) - ) - ) - (return - (i32.add - (call $fib - (i32.sub - (get_local $n) - (i32.const 2) - ) - ) - (call $fib - (i32.sub - (get_local $n) - (i32.const 1) - ) - ) - ) - ) - ) - ) - "#, - )?; - - // load module from a wasm file - let config = Config::create()?; - let loader = Loader::create(Some(config))?; - let module = loader.from_bytes(&wasm_bytes)?; - - // validate module - let config = Config::create()?; - let validator = Validator::create(Some(config))?; - validator.validate(&module)?; - - // register a wasm module into the store context - let module_name = "extern"; - let named_instance = executor.register_named_module(&mut store, &module, module_name)?; - assert!(named_instance.get_func("fib").is_ok()); - - ``` - -* Register an active module into the `Executor`. - - ```rust - // read the wasm bytes - let wasm_bytes = wat2wasm( - br#" - (module - (export "fib" (func $fib)) - (func $fib (param $n i32) (result i32) - (if - (i32.lt_s - (get_local $n) - (i32.const 2) - ) - (return - (i32.const 1) - ) - ) - (return - (i32.add - (call $fib - (i32.sub - (get_local $n) - (i32.const 2) - ) - ) - (call $fib - (i32.sub - (get_local $n) - (i32.const 1) - ) - ) - ) - ) - ) - ) - "#, - )?; - - // load module from a wasm file - let config = Config::create()?; - let loader = Loader::create(Some(config))?; - let module = loader.from_bytes(&wasm_bytes)?; - - // validate module - let config = Config::create()?; - let validator = Validator::create(Some(config))?; - validator.validate(&module)?; - - // register a wasm module as an active module - let active_instance = executor.register_active_module(&mut store, &module)?; - assert!(active_instance.get_func("fib").is_ok()); - - ``` - -The complete code in this demo can be found in [mdbook_example_module_instance.rs](https://github.com/WasmEdge/WasmEdge/blob/master/bindings/rust/wasmedge-sys/examples/mdbook_example_module_instance.rs). diff --git a/docs/book/en/src/sdk/rust/memory_manipulation.md b/docs/book/en/src/sdk/rust/memory_manipulation.md deleted file mode 100644 index bf3b0d60d4a9..000000000000 --- a/docs/book/en/src/sdk/rust/memory_manipulation.md +++ /dev/null @@ -1,156 +0,0 @@ -# Memory Manipulation - -In this example, we'll present how to manipulate the linear memory with the APIs defined in [wasmedge_sdk::Memory](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Memory.html). - -> The code in the following example is verified on -> -> * wasmedge-sdk v0.5.0 -> * wasmedge-sys v0.10.0 -> * wasmedge-types v0.3.0 - -## Wasm module - -Before talking about the code, let's first see the wasm module we use in this example. In the wasm module, a linear memory of 1-page (64KiB) size is defined; in addition, three functions are exported from this module: `get_at`, `set_at`, and `mem_size`. - -```wasm -(module - (type $mem_size_t (func (result i32))) - (type $get_at_t (func (param i32) (result i32))) - (type $set_at_t (func (param i32) (param i32))) - - # A memory with initial size of 1 page - (memory $mem 1) - - (func $get_at (type $get_at_t) (param $idx i32) (result i32) - (i32.load (local.get $idx))) - - (func $set_at (type $set_at_t) (param $idx i32) (param $val i32) - (i32.store (local.get $idx) (local.get $val))) - - (func $mem_size (type $mem_size_t) (result i32) - (memory.size)) - - # Exported functions - (export "get_at" (func $get_at)) - (export "set_at" (func $set_at)) - (export "mem_size" (func $mem_size)) - (export "memory" (memory $mem))) -``` - -Next, we'll demonstrate how to manipulate the linear memory by calling the exported functions. - -## Load and Register Module - -Let's start off by getting all imports right away so you can follow along - -```rust -// please add this feature if you're using rust of version < 1.63 -// #![feature(explicit_generic_args_with_impl_trait)] - -use wasmedge_sdk::{params, wat2wasm, Executor, Module, Store, WasmVal}; -``` - -To load a `Module`, `wasmedge-sdk` defines two methods: - -* [from_file](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Module.html#method.from_file) loads a wasm module from a file, and meanwhile, validates the loaded wasm module. - -* [from_bytes](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Module.html#method.from_bytes) loads a wasm module from an array of in-memory bytes, and meanwhile, validates the loaded wasm module. - -Here we use `Module::from_bytes` method to load our wasm module from an array of in-memory bytes. - -```rust -let wasm_bytes = wat2wasm( - r#" -(module - (type $mem_size_t (func (result i32))) - (type $get_at_t (func (param i32) (result i32))) - (type $set_at_t (func (param i32) (param i32))) - - (memory $mem 1) - - (func $get_at (type $get_at_t) (param $idx i32) (result i32) - (i32.load (local.get $idx))) - - (func $set_at (type $set_at_t) (param $idx i32) (param $val i32) - (i32.store (local.get $idx) (local.get $val))) - - (func $mem_size (type $mem_size_t) (result i32) - (memory.size)) - - (export "get_at" (func $get_at)) - (export "set_at" (func $set_at)) - (export "mem_size" (func $mem_size)) - (export "memory" (memory $mem))) -"# - .as_bytes(), -)?; - -// loads a wasm module from the given in-memory bytes -let module = Module::from_bytes(None, &wasm_bytes)?; -``` - -The module returned by `Module::from_bytes` is a compiled module, also called AST Module in WasmEdge terminology. To use it in WasmEdge runtime environment, we need to instantiate the AST module. We use [Store::register_named_module](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Store.html#method.register_named_module) API to achieve the goal. - -```rust -// create an executor -let mut executor = Executor::new(None, None)?; - -// create a store -let mut store = Store::new()?; - -// register the module into the store -let extern_instance = store.register_named_module(&mut executor, "extern", &module)?; -``` - -In the code above, we register the AST module into a `Store`, in which the module is instantiated, and as a result, a [module instance](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Instance.html) named `extern` is returned. - -## Memory - -In the previous section, we get an instance by registering a compiled module into the runtime environment. Now we retrieve the memory instance from the module instance, and make use of the APIs defined in [Memory](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Memory.html) to manipulate the linear memory. - -```rust -// get the exported memory instance -let mut memory = extern_instance - .memory("memory") - .ok_or_else(|| anyhow::anyhow!("failed to get memory instance named 'memory'"))?; - -// check memory size -assert_eq!(memory.size(), 1); -assert_eq!(memory.data_size(), 65536); - -// grow memory size -memory.grow(2)?; -assert_eq!(memory.size(), 3); -assert_eq!(memory.data_size(), 3 * 65536); - -// get the exported functions: "set_at" and "get_at" -let set_at = extern_instance - .func("set_at") - .ok_or_else(|| anyhow::Error::msg("Not found exported function named 'set_at'."))?; -let get_at = extern_instance - .func("get_at") - .ok_or_else(|| anyhow::Error::msg("Not found exported function named 'get_at`."))?; - -// call the exported function named "set_at" -let mem_addr = 0x2220; -let val = 0xFEFEFFE; -set_at.call(&mut executor, params!(mem_addr, val))?; - -// call the exported function named "get_at" -let returns = get_at.call(&mut executor, params!(mem_addr))?; -assert_eq!(returns[0].to_i32(), val); - -// call the exported function named "set_at" -let page_size = 0x1_0000; -let mem_addr = (page_size * 2) - std::mem::size_of_val(&val) as i32; -let val = 0xFEA09; -set_at.call(&mut executor, params!(mem_addr, val))?; - -// call the exported function named "get_at" -let returns = get_at.call(&mut executor, params!(mem_addr))?; -assert_eq!(returns[0].to_i32(), val); -``` - -The comments in the code explain the meaning of the code sample above, so we don't describe more. - -The complete code of this example can be found in [memory.rs](https://github.com/WasmEdge/WasmEdge/blob/master/bindings/rust/wasmedge-sdk/examples/memory.rs). diff --git a/docs/book/en/src/sdk/rust/say_hello.md b/docs/book/en/src/sdk/rust/say_hello.md deleted file mode 100644 index 66f27aad0808..000000000000 --- a/docs/book/en/src/sdk/rust/say_hello.md +++ /dev/null @@ -1,131 +0,0 @@ -# Hello World - -In this example, we'll use a wasm module, in which a function `run` is exported and it will call a function `say_hello` from an import module named `env`. The imported function `say_hello` has no inputs and outputs, and only prints a greeting message out. - -> The code in the following example is verified on -> -> * wasmedge-sdk v0.5.0 -> * wasmedge-sys v0.10.0 -> * wasmedge-types v0.3.0 - -Let's start off by getting all imports right away so you can follow along - -```rust -// please add this feature if you're using rust of version < 1.63 -// #![feature(explicit_generic_args_with_impl_trait)] - -#![feature(never_type)] - -use wasmedge_sdk::{ - error::HostFuncError, host_function, params, wat2wasm, Caller, Executor, ImportObjectBuilder, - Module, Store, WasmValue, -}; - -``` - -## Step 1: Define a native function and Create an ImportObject - -First, let's define a native function named `say_hello_world` that prints out `Hello, World!`. - -```rust -#[host_function] -fn say_hello(caller: &Caller, _args: Vec<WasmValue>) -> Result<Vec<WasmValue>, HostFuncError> { - println!("Hello, world!"); - - Ok(vec![]) -} -``` - -To use the native function as an import function in the `WasmEdge` runtime, we need an `ImportObject`. `wasmedge-sdk` defines a [ImportObjectBuilder](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.ImportObjectBuilder.html), which provides a group of chaining methods used to create an `ImportObject`. Let's see how to do it. - -```rust -// create an import module -let import = ImportObjectBuilder::new() - .with_func::<(), (), !>("say_hello", say_hello, None)? - .build("env")?; -``` - -Now, we have an import module named `env` which holds a host function `say_hello`. As you may notice, the names we used for the import module and the host function are exactly the same as the ones appearing in the wasm module. You can find the wasm module in [Step 2](#step-2-load-a-wasm-module). - -## Step 2: Load a wasm module - -Now, let's load a wasm module. `wasmedge-sdk` defines two methods in `Module`: - -* [from_file](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Module.html#method.from_file) loads a wasm module from a file, and meanwhile, validates the loaded wasm module. - -* [from_bytes](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Module.html#method.from_bytes) loads a wasm module from an array of in-memory bytes, and meanwhile, validates the loaded wasm module. - -Here we choose `Module::from_bytes` method to load our wasm module from an array of in-memory bytes. - -```rust -let wasm_bytes = wat2wasm( - br#" -(module - ;; First we define a type with no parameters and no results. - (type $no_args_no_rets_t (func (param) (result))) - - ;; Then we declare that we want to import a function named "env" "say_hello" with - ;; that type signature. - (import "env" "say_hello" (func $say_hello (type $no_args_no_rets_t))) - - ;; Finally we create an entrypoint that calls our imported function. - (func $run (type $no_args_no_rets_t) - (call $say_hello)) - ;; And mark it as an exported function named "run". - (export "run" (func $run))) -"#, -)?; - -// loads a wasm module from the given in-memory bytes and returns a compiled module -let module = Module::from_bytes(None, &wasm_bytes)?; -``` - -## Step 3: Register import module and compiled module - -To register a compiled module, we need to check if it has dependency on some import modules. In the wasm module this statement `(import "env" "say_hello" (func $say_hello (type $no_args_no_rets_t)))` tells us that it depends on an import module named `env`. Therefore, we need to register the import module first before registering the compiled wasm module. - -```rust -// loads a wasm module from the given in-memory bytes -let module = Module::from_bytes(None, &wasm_bytes)?; - -// create an executor -let mut executor = Executor::new(None, None)?; - -// create a store -let mut store = Store::new()?; - -// register the module into the store -store.register_import_module(&mut executor, &import)?; - -// register the compiled module into the store and get an module instance -let extern_instance = store.register_named_module(&mut executor, "extern", &module)?; -``` - -In the code above we use [Executor](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Executor.html) and [Store](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Store.html) to register the import module and the compiled module. `wasmedge-sdk` also provides alternative APIs to do the same thing: -[Vm::register_import_module](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Vm.html#method.register_import_module) and [Vm::register_module_from_bytes](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Vm.html#method.register_module_from_bytes). - -## Step 4: Run the exported function - -Now we are ready to run the exported function. - -```rust -// get the exported function "run" -let run = extern_instance - .func("run") - .ok_or_else(|| anyhow::Error::msg("Not found exported function named 'run'."))?; - -// run host function -run.call(&mut executor, params!())?; -``` - -In this example we created an instance of `Executor`, hence, we have two choices to call a [function instance](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Func.html): - -* [Func::call](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Func.html#method.call) - -* [Executor::run_func](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/trait.Engine.html#tymethod.run_func) - -Any one of these two methods requires that you have to get a [function instance](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Func.html). - -In addition, [Vm](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Vm.html) defines a group of methods which can invoke host function in different ways. For details, please reference [Vm](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Vm.html). - -The complete example can be found in [hello_world.rs](https://github.com/WasmEdge/WasmEdge/blob/master/bindings/rust/wasmedge-sdk/examples/hello_world.rs). diff --git a/docs/book/en/src/sdk/rust/sys_run_host_func.md b/docs/book/en/src/sdk/rust/sys_run_host_func.md deleted file mode 100644 index c5c2ba531496..000000000000 --- a/docs/book/en/src/sdk/rust/sys_run_host_func.md +++ /dev/null @@ -1,105 +0,0 @@ -# Run a WebAssembly function with WasmEdge low-level Rust APIs - -## Overview - -This section demonstrates how to use the Rust APIs of the `wasmedge-sys` crate to run a host function. - -As you may know, several mainstream programming languages, such as C/C++, Rust, Go, and Python, support compiling their programs into WebAssembly binary. In this demo, we'll introduce how to use the APIs defined in `Vm` of `wasmedge-sys` crate to call a WebAssembly function which could be coded in any programming language mentioned above. - -> The code in the example is verified on -> -> * wasmedge-sys v0.10.0 -> * wasmedge-types v0.3.0 - -## Example - -We use `fibonacci.wasm` in this demo, and the contents of the WebAssembly file are presented below. The statement, `(export "fib" (func $fib))`, declares an exported function named `fib`. This function computes a Fibonacci number with a given `i32` number as input. We'll use the function name later to achieve the goal of computing a Fibonacci number. - -```wasm -(module - (export "fib" (func $fib)) - (func $fib (param $n i32) (result i32) - (if - (i32.lt_s - (get_local $n) - (i32.const 2) - ) - (return - (i32.const 1) - ) - ) - (return - (i32.add - (call $fib - (i32.sub - (get_local $n) - (i32.const 2) - ) - ) - (call $fib - (i32.sub - (get_local $n) - (i32.const 1) - ) - ) - ) - ) - ) -) -``` - -### Step 1: Create a WasmEdge AST Module - -In this step, we'll create a WasmEdge `AST Module` instance from a WebAssembly file. - -* First, create a `Loader` context; - -* Then, load a specified WebAssebly file ("fibonacci.wasm") via the `from_file` method of the `Loader` context. If the process is successful, then a WasmEdge `AST Module` instance is returned. - -```rust -use wasmedge_sys::Loader; -use std::path::PathBuf; - -// create a Loader context -let loader = Loader::create(None).expect("fail to create a Loader context"); - -// load a wasm module from a specified wasm file, and return a WasmEdge AST Module instance -let path = PathBuf::from("fibonacci.wasm"); -let module = loader.from_file(path).expect("fail to load the WebAssembly file"); -``` - -### Step 2: Create a WasmEdge `Vm` context - -In WasmEdge, a `Vm` defines a running environment, in which all varieties of instances and contexts are stored and maintained. In the demo code below, we explicitly create a WasmEdge `Store` context, and then use it as one of the inputs in the creation of a `Vm` context. If not specify a `Store` context explicitly, then `Vm` will create a store by itself. - -```rust -use wasmedge_sys::{Config, Store, Vm}; - -// create a Config context -let config = Config::create().expect("fail to create a Config context"); - -// create a Store context -let mut store = Store::create().expect("fail to create a Store context"); - -// create a Vm context with the given Config and Store -let mut vm = Vm::create(Some(config), Some(&mut store)).expect("fail to create a Vm context"); -``` - -### Step 3: Invoke the `fib` function - -In Step 1, we got a module that hosts the target `fib` function defined in the WebAssembly. Now, we can call the function via the `run_wasm_from_module` method of the `Vm` context by passing the exported function name, `fib`. - -```rust -use wasmedge_sys::WasmValue; - -// run a function -let returns = vm.run_wasm_from_module(module, "fib", [WasmValue::from_i32(5)]).expect("fail to run the target function in the module"); - -println!("The result of fib(5) is {}", returns[0].to_i32()); -``` - -This is the final result printing on the screen: - -```bash -The result of fib(5) is 8 -``` diff --git a/docs/book/en/src/sdk/rust/table_and_funcref.md b/docs/book/en/src/sdk/rust/table_and_funcref.md deleted file mode 100644 index 97b9a7b59879..000000000000 --- a/docs/book/en/src/sdk/rust/table_and_funcref.md +++ /dev/null @@ -1,140 +0,0 @@ -# Table and FuncRef - -In this example, we'll present how to use [Table](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.Table.html) and [FuncRef](https://wasmedge.github.io/WasmEdge/wasmedge_sdk/struct.FuncRef.html) stored in a slot of a `Table` instance to implement indirect function invocation. - -> The code in the following example is verified on -> -> * wasmedge-sdk v0.5.0 -> * wasmedge-sys v0.10.0 -> * wasmedge-types v0.3.0 - -Let's start off by getting all imports right away so you can follow along - -```rust -// If the version of rust used is less than v1.63, please uncomment the follow attribute. -// #![feature(explicit_generic_args_with_impl_trait)] - -#![feature(never_type)] - -use wasmedge_sdk::{ - config::{CommonConfigOptions, ConfigBuilder}, - error::HostFuncError, - host_function, params, - types::Val, - Caller, Executor, Func, ImportObjectBuilder, RefType, Store, Table, TableType, ValType, - WasmVal, WasmValue, -}; -``` - -## Define host function - -In this example we defines a native function `real_add` that takes two numbers and returns their sum. This function will be registered as a host function into WasmEdge runtime environment - -```rust -#[host_function] -fn real_add(_caller: &Caller, input: Vec<WasmValue>) -> Result<Vec<WasmValue>, HostFuncError> { - println!("Rust: Entering Rust function real_add"); - - if input.len() != 2 { - return Err(HostFuncError::User(1)); - } - - let a = if input[0].ty() == ValType::I32 { - input[0].to_i32() - } else { - return Err(HostFuncError::User(2)); - }; - - let b = if input[1].ty() == ValType::I32 { - input[1].to_i32() - } else { - return Err(HostFuncError::User(3)); - }; - - let c = a + b; - println!("Rust: calculating in real_add c: {:?}", c); - - println!("Rust: Leaving Rust function real_add"); - Ok(vec![WasmValue::from_i32(c)]) -} -``` - -## Register Table instance - -The first thing we need to do is to create a `Table` instance. After that, we register the table instance along with an import module into the WasmEdge runtime environment. Now let's see the code. - -```rust -// create an executor -let config = ConfigBuilder::new(CommonConfigOptions::default()).build()?; -let mut executor = Executor::new(Some(&config), None)?; - -// create a store -let mut store = Store::new()?; - -// create a table instance -let result = Table::new(TableType::new(RefType::FuncRef, 10, Some(20))); -assert!(result.is_ok()); -let table = result.unwrap(); - -// create an import object -let import = ImportObjectBuilder::new() - .with_table("my-table", table)? - .build("extern")?; - -// register the import object into the store -store.register_import_module(&mut executor, &import)?; -``` - -In the code snippet above, we create a `Table` instance with the initial size of `10` and the maximum size of 20. The element type of the `Table` instance is `reference to function`. - -## Store a function reference into Table - -In the previous steps, we defined a native function `real_add` and registered a `Table` instance named `my-table` into the runtime environment. Now we'll save a reference to `read_add` function to a slot of `my-table`. - -```rust -// get the imported module instance -let instance = store - .module_instance("extern") - .expect("Not found module instance named 'extern'"); - -// get the exported table instance -let mut table = instance - .table("my-table") - .expect("Not found table instance named 'my-table'"); - -// create a host function -let host_func = Func::wrap::<(i32, i32), i32, !>(Box::new(real_add), None)?; - -// store the reference to host_func at the given index of the table instance -table.set(3, Val::FuncRef(Some(host_func.as_ref())))?; -``` - -We save the reference to `host_func` into the third slot of `my-table`. Next, we can retrieve the function reference from the table instance by index and call the function via its reference. - -## Call native function via `FuncRef` - -```rust -// retrieve the function reference at the given index of the table instance -let value = table.get(3)?; -if let Val::FuncRef(Some(func_ref)) = value { - // get the function type by func_ref - let func_ty = func_ref.ty()?; - - // arguments - assert_eq!(func_ty.args_len(), 2); - let param_tys = func_ty.args().unwrap(); - assert_eq!(param_tys, [ValType::I32, ValType::I32]); - - // returns - assert_eq!(func_ty.returns_len(), 1); - let return_tys = func_ty.returns().unwrap(); - assert_eq!(return_tys, [ValType::I32]); - - // call the function by func_ref - let returns = func_ref.call(&mut executor, params!(1, 2))?; - assert_eq!(returns.len(), 1); - assert_eq!(returns[0].to_i32(), 3); -} -``` - -The complete code of this example can be found in [table_and_funcref.rs](https://github.com/WasmEdge/WasmEdge/blob/master/bindings/rust/wasmedge-sdk/examples/table_and_funcref.rs). diff --git a/docs/book/en/src/use_cases.md b/docs/book/en/src/use_cases.md deleted file mode 100644 index 67cca9d8ba11..000000000000 --- a/docs/book/en/src/use_cases.md +++ /dev/null @@ -1,3 +0,0 @@ -# WasmEdge Use Cases - -> This part has been moved to <https://wasmedge.org/docs/start/usage/use-cases>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/frameworks.md b/docs/book/en/src/use_cases/frameworks.md deleted file mode 100644 index 85d94803dafb..000000000000 --- a/docs/book/en/src/use_cases/frameworks.md +++ /dev/null @@ -1,9 +0,0 @@ -# App Frameworks and Platforms - -WasmEdge applications can be plugged into existing application frameworks or platforms. WasmEdge provides a safe and efficient extension mechanism for those frameworks. - -In this chapter, we will introduce several such frameworks and platforms. - -* [Service mesh and frameworks](frameworks/mesh.md) support WasmEdge to run as containers for microservices. We will cover distributed application framework [Dapr](frameworks/mesh/dapr.md), service mesh [MOSN](frameworks/mesh/mosn.md), and event mesh [Apache EventMesh](frameworks/mesh/eventmesh.md). -* [Application frameworks](frameworks/app.md) support WasmEdge as an embedded function or plug-in runtime. We will cover streaming data framework [YoMo](frameworks/app/yomo.md) and Go function schedulder / framework [Reactr](frameworks/app/reactr.md). -* [Serverless platforms](frameworks/serverless.md) allows WasmEdge programs to run as serverless functions in their infrastructure. We will cover [AWS Lambda](frameworks/serverless/aws.md), [Tencent Serverless Cloud Functions](frameworks/serverless/tencent.md), [Vercel Serverless Functions](frameworks/serverless/vercel.md), [Netlify Functions](frameworks/serverless/netlify.md), and [Second State Functions](frameworks/serverless/secondstate.md). diff --git a/docs/book/en/src/use_cases/frameworks/app.md b/docs/book/en/src/use_cases/frameworks/app.md deleted file mode 100644 index ff39bb30d92a..000000000000 --- a/docs/book/en/src/use_cases/frameworks/app.md +++ /dev/null @@ -1,3 +0,0 @@ -# App frameworks - -> This part has been moved to <https://wasmedge.org/docs/category/use-cases>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/frameworks/app/reactr.md b/docs/book/en/src/use_cases/frameworks/app/reactr.md deleted file mode 100644 index 288c82536842..000000000000 --- a/docs/book/en/src/use_cases/frameworks/app/reactr.md +++ /dev/null @@ -1,372 +0,0 @@ -# Reactr - -[Reactr](https://github.com/suborbital/reactr) is a fast, performant function scheduling library written in Go. Reactr is designed to be flexible, with the ability to run embedded in your Go applications and first-class support for WebAssembly. -Taking advantage of Go's superior concurrency capabilities, Reactr can manage and execute hundreds of WebAssembly runtime instances all at once, making a great framework for server-side applications. - -Reactr allows you to run WebAssembly functions in Go, so does the [WasmEdge Go SDK](../../../sdk/go.md). -The unique feature of Reactr is that it provides a rich set of host functions in Go, which support access to networks and databases etc. Reactr then provides Rust (and Swift / AssemblyScript) APIs to call those host functions from within the WebAssembly function. - -In this article, we will show you how to use WasmEdge together with Reactr to take advantage of the best of both worlds. WasmEdge is the [fastest and most extensible WebAssembly runtime](../../../features.md). -It is also the fastest in [Reactr's official test suite](https://github.com/suborbital/reactr/runs/4476074960?check_suite_focus=true). -We will show you how to run Rust functions compiled to WebAssembly as well as JavaScript programs in WasmEdge and Reactr. - -> WasmEdge provides [advanced support for JavaScript](../../../write_wasm/js.md) including [mixing Rust with JavaScript](../../../write_wasm/js/rust.md) for improved performance. - -* [Hello world](#hello-world) -* [Database query](#database-query) -* [Embed JavaScript in Go](#embed-javascript-in-go) - -## Prerequisites - -You need have [Rust](https://www.rust-lang.org/tools/install), [Go](https://go.dev/doc/install), and [WasmEdge](../../../quick_start/install.md) installed on your system. -The GCC compiler (installed via the `build-essential` package) is also needed for WasmEdge. - -```bash -sudo apt-get update -sudo apt-get -y upgrade -sudo apt install build-essential - -curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -source $HOME/.cargo/env -rustup target add wasm32-wasi - -curl -OL https://golang.org/dl/go1.17.5.linux-amd64.tar.gz -sudo tar -C /usr/local -xvf go1.17.5.linux-amd64.tar.gz -export PATH=$PATH:/usr/local/go/bin - -wget -qO- https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -source $HOME/.wasmedge/env -``` - -## Hello world - -A simple `hello world` example for Reactr is [available here](https://github.com/second-state/wasm-learning/tree/master/reactr/hello). - -### Hello world: Rust function compiled to WebAssembly - -Let's first create [a simple Rust function](https://github.com/second-state/wasm-learning/blob/master/reactr/hello/hello-echo/src/lib.rs) to echo hello. -The Rust function `HelloEcho::run()` is as follows. It will be exposed to the Go host application through Reactr. - -```rust -use suborbital::runnable::*; - -struct HelloEcho{} - -impl Runnable for HelloEcho { - fn run(&self, input: Vec<u8>) -> Result<Vec<u8>, RunErr> { - let in_string = String::from_utf8(input).unwrap(); - Ok(format!("hello {}", in_string).as_bytes().to_vec()) - } -} -``` - -Let's build the Rust function into a WebAssembly bytecode file. - -```bash -cd hello-echo -cargo build --target wasm32-wasi --release -cp target/wasm32-wasi/release/hello_echo.wasm .. -cd .. -``` - -### Hello world: Go host application - -Next, lets look into the [Go host app](https://github.com/second-state/wasm-learning/blob/master/reactr/hello/main.go) that executes the WebAssembly functions. -The `runBundle()` function executes the `run()` function in the `Runnable` struct once. - -```go -func runBundle() { - r := rt.New() - doWasm := r.Register("hello-echo", rwasm.NewRunner("./hello_echo.wasm")) - - res, err := doWasm([]byte("wasmWorker!")).Then() - if err != nil { - fmt.Println(err) - return - } - - fmt.Println(string(res.([]byte))) -} -``` - -The `runGroup()` function executes the Rust-compiled WebAssembly `run()` function multiple times asynchronously in a group, and receives the results as they come in. - -```go -func runGroup() { - r := rt.New() - - doWasm := r.Register("hello-echo", rwasm.NewRunner("./hello_echo.wasm")) - - grp := rt.NewGroup() - for i := 0; i < 100000; i++ { - grp.Add(doWasm([]byte(fmt.Sprintf("world %d", i)))) - } - - if err := grp.Wait(); err != nil { - fmt.Println(err) - } -} -``` - -Finally, let's run the Go host application and see the results printed to the console. - -> You must use the `-tags wasmedge` flag to take advantage of the performance and extended WebAssembly APIs provided by WasmEdge. - -```bash -go mod tidy -go run -tags wasmedge main.go -``` - -## Database query - -In [this example](https://github.com/second-state/wasm-learning/tree/master/reactr/db), we will demonstrate how to use Reactr host functions and APIs to query a PostgreSQL database from your WebAssembly function. - -### Database query: Install and set up a PostgreSQL database - -We will start a PostgreSQL instance through Docker. - -```bash -docker pull postgres -docker run --name reactr-postgres -p 5432:5432 -e POSTGRES_PASSWORD=12345 -d postgres -``` - -Next, let's create a database and populate it with some sample data. - -```bash -$ docker run -it --rm --network host postgres psql -h 127.0.0.1 -U postgres -postgres=# CREATE DATABASE reactr; -postgres=# \c reactr; - -# Create a table: -postgres=# CREATE TABLE users ( - uuid varchar(100) CONSTRAINT firstkey PRIMARY KEY, - email varchar(50) NOT NULL, - created_at date, - state char(1), - identifier integer -); -``` - -Leave this running and start another terminal window to interact with this PostgreSQL server. - -### Database query: Rust function compiled to WebAssembly - -Let's create [a Rust function](https://github.com/second-state/wasm-learning/blob/master/reactr/db/rs-db/src/lib.rs) to access the PostgreSQL database. -The Rust function `RsDbtest::run()` is as follows. It will be exposed to the Go host application through Reactr. It uses named queries such as `PGInsertUser` and `PGSelectUserWithUUID` to operate the database. Those queries are defined in the Go host application, and we will see them later. - -```rust -use suborbital::runnable::*; -use suborbital::db; -use suborbital::util; -use suborbital::db::query; -use suborbital::log; -use uuid::Uuid; - -struct RsDbtest{} - -impl Runnable for RsDbtest { - fn run(&self, _: Vec<u8>) -> Result<Vec<u8>, RunErr> { - let uuid = Uuid::new_v4().to_string(); - - let mut args: Vec<query::QueryArg> = Vec::new(); - args.push(query::QueryArg::new("uuid", uuid.as_str())); - args.push(query::QueryArg::new("email", "connor@suborbital.dev")); - - match db::insert("PGInsertUser", args) { - Ok(_) => log::info("insert successful"), - Err(e) => { - return Err(RunErr::new(500, e.message.as_str())) - } - }; - - let mut args2: Vec<query::QueryArg> = Vec::new(); - args2.push(query::QueryArg::new("uuid", uuid.as_str())); - - match db::update("PGUpdateUserWithUUID", args2.clone()) { - Ok(rows) => log::info(format!("update: {}", util::to_string(rows).as_str()).as_str()), - Err(e) => { - return Err(RunErr::new(500, e.message.as_str())) - } - } - - match db::select("PGSelectUserWithUUID", args2.clone()) { - Ok(result) => log::info(format!("select: {}", util::to_string(result).as_str()).as_str()), - Err(e) => { - return Err(RunErr::new(500, e.message.as_str())) - } - } - - match db::delete("PGDeleteUserWithUUID", args2.clone()) { - Ok(rows) => log::info(format!("delete: {}", util::to_string(rows).as_str()).as_str()), - Err(e) => { - return Err(RunErr::new(500, e.message.as_str())) - } - } - - ... ... - } -} -``` - -Let's build the Rust function into a WebAssembly bytecode file. - -```bash -cd rs-db -cargo build --target wasm32-wasi --release -cp target/wasm32-wasi/release/rs_db.wasm .. -cd .. -``` - -### Database query: Go host application - -The [Go host app](https://github.com/second-state/wasm-learning/blob/master/reactr/db/main.go) first defines the SQL queries and gives each of them a name. -We will then pass those queries to the Reactr runtime as a configuration. - -```go -func main() { - dbConnString, exists := os.LookupEnv("REACTR_DB_CONN_STRING") - if !exists { - fmt.Println("skipping as conn string env var not set") - return - } - - q1 := rcap.Query{ - Type: rcap.QueryTypeInsert, - Name: "PGInsertUser", - VarCount: 2, - Query: ` - INSERT INTO users (uuid, email, created_at, state, identifier) - VALUES ($1, $2, NOW(), 'A', 12345)`, - } - - q2 := rcap.Query{ - Type: rcap.QueryTypeSelect, - Name: "PGSelectUserWithUUID", - VarCount: 1, - Query: ` - SELECT * FROM users - WHERE uuid = $1`, - } - - q3 := rcap.Query{ - Type: rcap.QueryTypeUpdate, - Name: "PGUpdateUserWithUUID", - VarCount: 1, - Query: ` - UPDATE users SET state='B' WHERE uuid = $1`, - } - - q4 := rcap.Query{ - Type: rcap.QueryTypeDelete, - Name: "PGDeleteUserWithUUID", - VarCount: 1, - Query: ` - DELETE FROM users WHERE uuid = $1`, - } - - config := rcap.DefaultConfigWithDB(vlog.Default(), rcap.DBTypePostgres, dbConnString, []rcap.Query{q1, q2, q3, q4}) - - r, err := rt.NewWithConfig(config) - if err != nil { - fmt.Println(err) - return - } - - ... ... -} -``` - -Then, we can run the WebAssembly function from Reactr. - -```go -func main() { - ... ... - - doWasm := r.Register("rs-db", rwasm.NewRunner("./rs_db.wasm")) - - res, err := doWasm(nil).Then() - if err != nil { - fmt.Println(err) - return - } - - fmt.Println(string(res.([]byte))) -} -``` - -Finally, let's run the Go host application and see the results printed to the console. - -> You must use the `-tags wasmedge` flag to take advantage of the performance and extended WebAssembly APIs provided by WasmEdge. - -```bash -export REACTR_DB_CONN_STRING='postgresql://postgres:12345@127.0.0.1:5432/reactr' -go mod tidy -go run -tags wasmedge main.go -``` - -## Embed JavaScript in Go - -As we mentioned, a key feature of the WasmEdge Runtime is its advanced [JavaScript support](../../../write_wasm/js.md), which allows JavaScript programs to run in lightweight, high-performance, safe, multi-language, and [Kubernetes-managed WasmEdge containers](../../kubernetes.md). -A simple example of embedded JavaScript function in Reactr is [available here](https://github.com/second-state/wasm-learning/tree/master/reactr/quickjs). - -### JavaScript example - -The [JavaScript example function](https://github.com/second-state/wasm-learning/tree/master/reactr/quickjs/hello.js) is very simple. It just returns a string value. - -```javascript -let h = 'hello'; -let w = 'wasmedge'; -`${h} ${w}`; -``` - -### JavaScript example: Go host application - -The [Go host app](https://github.com/second-state/wasm-learning/tree/master/reactr/quickjs/main.go) uses the Reactr API to run WasmEdge's standard JavaScript interpreter [rs_embed_js.wasm](https://github.com/second-state/wasm-learning/blob/master/reactr/quickjs/rs_embed_js.wasm). You can build your own version of JavaScript interpreter by modifying [this Rust project](https://github.com/second-state/wasm-learning/tree/master/reactr/quickjs/rs-embed-js). - -> Learn more about how to embed [JavaScript code in Rust](https://github.com/second-state/wasmedge-quickjs/tree/main/examples/embed_js), and how to [use Rust to implement JavaScript APIs](../../../write_wasm/js/rust.md) in WasmEdge. - -The Go host application just need to start the job for `rs_embed_js.wasm` and pass the JavaScript content to it. The Go application can then capture and print the return value from JavaScript. - -```go -func main() { - r := rt.New() - doWasm := r.Register("hello-quickjs", rwasm.NewRunner("./rs_embed_js.wasm")) - - code, err := ioutil.ReadFile(os.Args[1]) - if err != nil { - fmt.Print(err) - } - res, err := doWasm(code).Then() - if err != nil { - fmt.Println(err) - return - } - - fmt.Println(string(res.([]byte))) -} -``` - -Run the Go host application as follows. - -```bash -$ cd quickjs -$ go mod tidy -$ go run -tags wasmedge main.go hello.js -String(JsString(hello wasmedge)) -``` - -The printed result shows the type information of the string in Rust and Go APIs. You can strip out this information by changing the Rust or Go applications. - -### JavaScript example: Feature examples - -WasmEdge supports many advanced JavaScript features. For the next step, you could try our [React SSR example](https://github.com/second-state/wasmedge-quickjs/tree/main/example_js/react_ssr) to generate an HTML UI from a Reactr function! -You can just build the `dist/main.js` from the React SSR example, and copy it over to this example folder to see it in action! - -```bash -$ cd quickjs -# copy over the dist/main.js file from the react ssr example -$ go mod tidy -$ go run -tags wasmedge main.go main.js -<div data-reactroot=""><div>This is home</div><div><div>This is page</div></div></div> -UnDefined -``` diff --git a/docs/book/en/src/use_cases/frameworks/app/yomo.md b/docs/book/en/src/use_cases/frameworks/app/yomo.md deleted file mode 100644 index 4bdd7d335c60..000000000000 --- a/docs/book/en/src/use_cases/frameworks/app/yomo.md +++ /dev/null @@ -1,282 +0,0 @@ -# YoMo - -[YoMo](https://yomo.run/) is a programming framework enabling developers to build a distributed cloud system (Geo-Distributed Cloud System). YoMo's communication layer is made on top of the QUIC protocol, which brings high-speed data transmission. In addition, it has a built-in Streaming Serverless "streaming function", which significantly improves the development experience of distributed cloud systems. The distributed cloud system built by YoMo provides an ultra-high-speed communication mechanism between near-field computing power and terminals. It has a wide range of use cases in Metaverse, VR/AR, IoT, etc. - -> YoMo is written in the Go language. For streaming Serverless, Golang plugins and shared libraries are used to load users' code dynamically, which also have certain limitations for developers. Coupled with Serverless architecture's rigid demand for isolation, this makes WebAssembly an excellent choice for running user-defined functions. - -For example, in the process of real-time AI inference in AR/VR devices or smart factories, the camera sends real-time unstructured data to the computing node in the near-field MEC (multi-access edge computing) device through YoMo. YoMo sends the AI computing result to the end device in real-time when the AI inference is completed. Thus, the hosted AI inference function will be automatically executed. - -However, a challenge for YoMo is to incorporate and manage handler functions written by multiple outside developers in an edge computing node. It requires runtime isolation for those functions without sacrificing performance. Traditional software container solutions, such as Docker, are not up to the task. They are too heavy and slow to handle real-time tasks. - -WebAssembly provides a lightweight and high-performance software container. It is ideally suited as a runtime for YoMo’s data processing handler functions. - -In this article, we will show you how to create a Rust function for Tensorflow-based image classification, compile it into WebAssembly, and then use YoMo to run it as a stream data handler. We use [WasmEdge](https://wasmedge.org/) as our WebAssembly runtime because it offers the highest performance and flexibility compared with other WebAssembly runtimes. It is the only WebAssembly VM that reliably supports Tensorflow. YoMo manages WasmEdge VM instances and the contained WebAssembly bytecode apps through [WasmEdge’s Golang API](../../../sdk/go.md). - -> Source code: <https://github.com/yomorun/yomo-wasmedge-tensorflow> - -Checkout [the WasmEdge image classification function in action in YoMo](https://www.youtube.com/watch?v=E0ltsn6cLIU) - -## Prerequisite - -Obviously, you will need to have [Golang installed](https://golang.org/doc/install), but I will assume you already did. - -> Golang version should be newer than 1.15 for our example to work. - -You also need to install the YoMo CLI application. It orchestrates and coordinates data streaming and handler function invocations. - -```bash -$ go install github.com/yomorun/cli/yomo@latest -$ yomo version -YoMo CLI version: v0.1.3 -``` - -Next, please install the WasmEdge and its Tensorflow shared libraries. [WasmEdge](https://wasmedge.org/) is a leading WebAssembly runtime hosted by the CNCF. We will use it to embed and run WebAssembly programs from YoMo. - -```bash -curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -``` - -Finally, since our demo WebAssembly functions are written in Rust, you will also need a [Rust compiler](https://www.rust-lang.org/tools/install). - -For the rest of the demo, fork and clone the [source code repository](https://github.com/yomorun/yomo-wasmedge-tensorflow). - -```bash -git clone https://github.com/yomorun/yomo-wasmedge-tensorflow.git -``` - -## The image classification function - -The [image classification function](https://github.com/yomorun/yomo-wasmedge-tensorflow/tree/main/flow/rust_mobilenet_food) to process the YoMo image stream is written in Rust. It utilizes the WasmEdge Tensorflow API to process an input image. - -```rust -#[wasmedge_bindgen] -pub fn infer(image_data: Vec<u8>) -> Result<Vec<u8>, String> { - let start = Instant::now(); - - // Load the TFLite model and its meta data (the text label for each recognized object number) - let model_data: &[u8] = include_bytes!("lite-model_aiy_vision_classifier_food_V1_1.tflite"); - let labels = include_str!("aiy_food_V1_labelmap.txt"); - - // Pre-process the image to a format that can be used by this model - let flat_img = wasmedge_tensorflow_interface::load_jpg_image_to_rgb8(&image_data[..], 192, 192); - println!("RUST: Loaded image in ... {:?}", start.elapsed()); - - // Run the TFLite model using the WasmEdge Tensorflow API - let mut session = wasmedge_tensorflow_interface::Session::new(&model_data, wasmedge_tensorflow_interface::ModelType::TensorFlowLite); - session.add_input("input", &flat_img, &[1, 192, 192, 3]) - .run(); - let res_vec: Vec<u8> = session.get_output("MobilenetV1/Predictions/Softmax"); - - // Find the object index in res_vec that has the greatest probability - // Translate the probability into a confidence level - // Translate the object index into a label from the model meta data food_name - let mut i = 0; - let mut max_index: i32 = -1; - let mut max_value: u8 = 0; - while i < res_vec.len() { - let cur = res_vec[i]; - if cur > max_value { - max_value = cur; - max_index = i as i32; - } - i += 1; - } - println!("RUST: index {}, prob {}", max_index, max_value); - - let confidence: String; - if max_value > 200 { - confidence = "is very likely".to_string(); - } else if max_value > 125 { - confidence = "is likely".to_string(); - } else { - confidence = "could be".to_string(); - } - - let ret_str: String; - if max_value > 50 { - let mut label_lines = labels.lines(); - for _i in 0..max_index { - label_lines.next(); - } - let food_name = label_lines.next().unwrap().to_string(); - ret_str = format!( - "It {} a <a href='https://www.google.com/search?q={}'>{}</a> in the picture", - confidence, food_name, food_name - ); - } else { - ret_str = "It does not appears to be a food item in the picture.".to_string(); - } - - println!( - "RUST: Finished post-processing in ... {:?}", - start.elapsed() - ); - return Ok(ret_str.as_bytes().to_vec()); -} -``` - -You should add `wasm32-wasi` target to rust to compile this function into WebAssembly bytecode. - -```bash -rustup target add wasm32-wasi - -cd flow/rust_mobilenet_food -cargo build --target wasm32-wasi --release -# The output WASM will be target/wasm32-wasi/release/rust_mobilenet_food_lib.wasm - -# Copy the wasm bytecode file to the flow/ directory -cp target/wasm32-wasi/release/rust_mobilenet_food_lib.wasm ../ -``` - -To release the best performance of WasmEdge, you should enable the AOT mode by compiling the `.wasm` file to the `.so`. - -```bash -wasmedge compile rust_mobilenet_food_lib.wasm rust_mobilenet_food_lib.so -``` - -## Integration with YoMo - -On the YoMo side, we use the WasmEdge Golang API to start and run WasmEdge VM for the image classification function. The [app.go](https://github.com/yomorun/yomo-wasmedge-tensorflow/blob/main/flow/app.go) file in the source code project is as follows. - -```go -package main - -import ( - "crypto/sha1" - "fmt" - "log" - "os" - "sync/atomic" - - "github.com/second-state/WasmEdge-go/wasmedge" - bindgen "github.com/second-state/wasmedge-bindgen/host/go" - "github.com/yomorun/yomo" -) - -var ( - counter uint64 -) - -const ImageDataKey = 0x10 - -func main() { - // Connect to Zipper service - sfn := yomo.NewStreamFunction("image-recognition", yomo.WithZipperAddr("localhost:9900")) - defer sfn.Close() - - // set only monitoring data - sfn.SetObserveDataID(ImageDataKey) - - // set handler - sfn.SetHandler(Handler) - - // start - err := sfn.Connect() - if err != nil { - log.Print("❌ Connect to zipper failure: ", err) - os.Exit(1) - } - - select {} -} - -// Handler process the data in the stream -func Handler(img []byte) (byte, []byte) { - // Initialize WasmEdge's VM - vmConf, vm := initVM() - bg := bindgen.Instantiate(vm) - defer bg.Release() - defer vm.Release() - defer vmConf.Release() - - // recognize the image - res, err := bg.Execute("infer", img) - if err == nil { - fmt.Println("GO: Run bindgen -- infer:", string(res)) - } else { - fmt.Println("GO: Run bindgen -- infer FAILED") - } - - // print logs - hash := genSha1(img) - log.Printf("✅ received image-%d hash %v, img_size=%d \n", atomic.AddUint64(&counter, 1), hash, len(img)) - - return 0x11, nil -} - -// genSha1 generate the hash value of the image -func genSha1(buf []byte) string { - h := sha1.New() - h.Write(buf) - return fmt.Sprintf("%x", h.Sum(nil)) -} - -// initVM initialize WasmEdge's VM -func initVM() (*wasmedge.Configure, *wasmedge.VM) { - wasmedge.SetLogErrorLevel() - // Set Tensorflow not to print debug info - os.Setenv("TF_CPP_MIN_LOG_LEVEL", "3") - os.Setenv("TF_CPP_MIN_VLOG_LEVEL", "3") - - // Create configure - vmConf := wasmedge.NewConfigure(wasmedge.WASI) - - // Create VM with configure - vm := wasmedge.NewVMWithConfig(vmConf) - - // Init WASI - var wasi = vm.GetImportObject(wasmedge.WASI) - wasi.InitWasi( - os.Args[1:], // The args - os.Environ(), // The envs - []string{".:."}, // The mapping directories - ) - - // Register WasmEdge-tensorflow and WasmEdge-image - var tfobj = wasmedge.NewTensorflowImportObject() - var tfliteobj = wasmedge.NewTensorflowLiteImportObject() - vm.RegisterImport(tfobj) - vm.RegisterImport(tfliteobj) - var imgobj = wasmedge.NewImageImportObject() - vm.RegisterImport(imgobj) - - // Instantiate wasm - vm.LoadWasmFile("rust_mobilenet_food_lib.so") - vm.Validate() - - return vmConf, vm -} -``` - -## In action - -Finally, we can start YoMo and see the entire data processing pipeline in action. Start the YoMo CLI application from the project folder. The [yaml file](https://github.com/yomorun/yomo-wasmedge-tensorflow/blob/main/zipper/workflow.yaml) defines port YoMo should listen on and the workflow handler to trigger for incoming data. Note that the flow name `image-recognition` matches the name in the aforementioned data handler [app.go](https://github.com/yomorun/yomo-wasmedge-tensorflow/blob/main/flow/app.go). - -```bash -yomo serve -c ./zipper/workflow.yaml -``` - -Start the handler function by running the aforementioned [app.go](https://github.com/yomorun/yomo-wasmedge-tensorflow/blob/main/flow/app.go) program. - -```bash -cd flow -go run --tags "tensorflow image" app.go -``` - -[Start a simulated data source](https://github.com/yomorun/yomo-wasmedge-tensorflow/blob/main/source/main.go) by sending a video to YoMo. The video is a series of image frames. The WasmEdge function in [app.go](https://github.com/yomorun/yomo-wasmedge-tensorflow/blob/main/flow/app.go) will be invoked against every image frame in the video. - -```bash -# Download a video file -wget -P source 'https://github.com/yomorun/yomo-wasmedge-tensorflow/releases/download/v0.1.0/hot-dog.mp4' - -# Stream the video to YoMo -go run ./source/main.go ./source/hot-dog.mp4 -``` - -You can see the output from the WasmEdge handler function in the console. It prints the names of the objects detected in each image frame in the video. - -## What's next - -In this article, we have seen how to use the WasmEdge Tensorflow API and Golang SDK in YoMo framework to process an image stream in near real-time. - -In collaboration with YoMo, we will soon deploy WasmEdge in production in smart factories for a variety of assembly line tasks. WasmEdge is the software runtime for edge computing! diff --git a/docs/book/en/src/use_cases/frameworks/mesh.md b/docs/book/en/src/use_cases/frameworks/mesh.md deleted file mode 100644 index 0e74de614db2..000000000000 --- a/docs/book/en/src/use_cases/frameworks/mesh.md +++ /dev/null @@ -1,3 +0,0 @@ -# Service mesh and distributed runtimes - -> This part has been moved to <https://wasmedge.org/docs/category/use-cases>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/frameworks/mesh/dapr.md b/docs/book/en/src/use_cases/frameworks/mesh/dapr.md deleted file mode 100644 index c221634794c8..000000000000 --- a/docs/book/en/src/use_cases/frameworks/mesh/dapr.md +++ /dev/null @@ -1,259 +0,0 @@ -# Dapr - -In this article, I will demonstrate how to use WasmEdge as a sidecar application runtime for Dapr. There are two ways to do this: - -* **Standalone WasmEdge** is the **recommended approach** is to write a microservice using [Rust](../../../write_wasm/rust/networking-nonblocking.md) or [JavaScript](../../../write_wasm/js/networking.md), and run it in WasmEdge. The WasmEdge application serves web requests and communicates with the sidecar via sockets using the Dapr API. In this case, we can [run WasmEdge as a managed container in k8s](../../kubernetes/quickstart.md). -* Alternatively, Embedded WasmEdge is to create a simple microservice in Rust or Go to listen for web requests and communicate with the Dapr sidecar. It passes the request data to a WasmEdge runtime for processing. The business logic of the microservice is a WebAssembly function created and deployed by an application developer. - -> While the first approach (running the entire microservice in WasmEdge) is much preferred, we are still working on a fully fledged Dapr SDKs for WasmEdge. You can track their progress in GitHub issues -- [Rust](https://github.com/WasmEdge/WasmEdge/issues/1571) and [JavaScript](https://github.com/WasmEdge/WasmEdge/issues/1572). - -## Quick start - -First you need to install [Dapr](https://docs.dapr.io/getting-started/install-dapr-cli) and [WasmEdge](../../../quick_start/install.md). [Go](https://golang.org/doc/install) and [Rust](https://www.rust-lang.org/tools/install) are optional for the standalone WasmEdge approach. However, they are required for the demo app since it showcases both standalone and embedded WasmEdge approaches. - -Fork or clone the demo application from Github. You can use this repo as your own application template. - -```bash -git clone https://github.com/second-state/dapr-wasm -```` - -The demo has 4 Dapr sidecar applications. The [web-port](https://github.com/second-state/dapr-wasm/tree/main/web-port) project provides a public web service for a static HTML page. This is the application’s UI. From the static HTML page, the user can select a microservice to turn an input image into grayscale. All 3 microsoervices below perform the same function. They are just implemented using different approaches. - -* **Standalone WasmEdge approach:** The [image-api-wasi-socket-rs](https://github.com/second-state/dapr-wasm/tree/main/image-api-wasi-socket-rs) project provides a standalone WasmEdge sidecar microservice that takes the input image and returns the grayscale image. The microservice is written in Rust and compiled into WebAssembly bytecode to run in WasmEdge. -* Embedded WasmEdge approach #1: The [image-api-rs](https://github.com/second-state/dapr-wasm/tree/main/image-api-rs) project provides a simple Rust-based microservice. It embeds a [WasmEdge function](https://github.com/second-state/dapr-wasm/tree/main/functions/grayscale) to turn an input image into a grayscale image. -* Embedded WasmEdge approach #2: The [image-api-go](https://github.com/second-state/dapr-wasm/tree/main/image-api-go) project provides a simple Go-based microservice. It embeds a [WasmEdge function](https://github.com/second-state/dapr-wasm/tree/main/functions/grayscale) to turn an input image into a grayscale image. - -You can follow the instructions in the [README](https://github.com/second-state/dapr-wasm/blob/main/README.md) to start the sidecar services. Here are commands to build the WebAssembly functions and start the sidecar services. The first set of commands deploy the static web page service and the standalone WasmEdge service written in Rust. It forms a complete application to turn an input image into grayscale. - -```bash -# Build and start the static HTML web page service for the UI and router for sending the uploaded image to the grayscale microservice -cd web-port -go build -./run_web.sh -cd ../ - -# Build the standalone image grayscale web service for WasmEdge -cd image-api-wasi-socket-rs -cargo build --target wasm32-wasi -cd ../ - -# Run the microservice as a Dapr sidecar app -cd image-api-wasi-socket-rs -./run_api_wasi_socket_rs.sh -cd ../ -``` - -The second set of commands create the alternative microservices for the embedded WasmEdge function. - -```bash -# Build the grayscale WebAssembly functions, and deploy them to the sidecar projects -cd functions/grayscale -./build.sh -cd ../../ - -# Build and start the Rust-based microservice for embedding the grayscale WasmEdge function -cd image-api-rs -cargo build --release -./run_api_rs.sh -cd ../ - -# Build and start the Go-based microservice for embedding the grayscale WasmEdge function -cd image-api-go -go build -./run_api_go.sh -cd ../ -``` - -Finally, you should be able to see the web UI in your browser. - -## Recommended: The standalone WasmEdge microservice in Rust - -The [standalone WasmEdge microservice](https://github.com/second-state/dapr-wasm/blob/main/image-api-wasi-socket-rs/src/main.rs) starts a non-blocking TCP server inside WasmEdge. The TCP server passes incoming requests to `handle_client()`, which passes HTTP requests to `handle_http()`, which calls `grayscale()` to process the image data in the request. - -```rust -fn main() -> std::io::Result<()> { - let port = std::env::var("PORT").unwrap_or(9005.to_string()); - println!("new connection at {}", port); - let listener = TcpListener::bind(format!("127.0.0.1:{}", port))?; - loop { - let _ = handle_client(listener.accept()?.0); - } -} - -fn handle_client(mut stream: TcpStream) -> std::io::Result<()> { - ... ... -} - -fn handle_http(req: Request<Vec<u8>>) -> bytecodec::Result<Response<String>> { - ... ... -} - -fn grayscale(image: &[u8]) -> Vec<u8> { - let detected = image::guess_format(&image); - let mut buf = vec![]; - if detected.is_err() { - return buf; - } - - let image_format_detected = detected.unwrap(); - let img = image::load_from_memory(&image).unwrap(); - let filtered = img.grayscale(); - match image_format_detected { - ImageFormat::Gif => { - filtered.write_to(&mut buf, ImageOutputFormat::Gif).unwrap(); - } - _ => { - filtered.write_to(&mut buf, ImageOutputFormat::Png).unwrap(); - } - }; - return buf; -} -``` - -> Work in progress: It will soon interact with the Dapr sidecar through the [WasmEdge Dapr SDK in Rust](https://github.com/WasmEdge/WasmEdge/issues/1571). - -Now, you can build the microservice. It is a simple matter of compiling from Rust to WebAssembly. - -```bash -cd image-api-wasi-socket-rs -cargo build --target wasm32-wasi -``` - -Deploy the WasmEdge microservice in Dapr as follows. - -```bash -dapr run --app-id image-api-wasi-socket-rs \ - --app-protocol http \ - --app-port 9005 \ - --dapr-http-port 3503 \ - --components-path ../config \ - --log-level debug \ - wasmedge ./target/wasm32-wasi/debug/image-api-wasi-socket-rs.wasm -``` - -## Alternative: The embedded WasmEdge microservices - -The embedded WasmEdge approach requires us to create a WebAssembly function for the business logic (image processing) first, and then embed it into simple Dapr microservices. - -### Rust function for image processing - -The [Rust function](https://github.com/second-state/dapr-wasm/blob/main/functions/grayscale/src/lib.rs) is simple. It uses the [wasmedge_bindgen](../../../write_wasm/rust/bindgen.md) macro to makes it easy to call the function from a Go or Rust host embedding the WebAssembly function. It takes and returns base64 encoded image data for the web. - -```rust -#[wasmedge_bindgen] -pub fn grayscale(image_data: String) -> String { - let image_bytes = image_data.split(",").map(|x| x.parse::<u8>().unwrap()).collect::<Vec<u8>>(); - return grayscale::grayscale_internal(&image_bytes); -} -``` - -The Rust function that actually performs the task is as follows. - -```rust -pub fn grayscale_internal(image_data: &[u8]) -> String { - let image_format_detected: ImageFormat = image::guess_format(&image_data).unwrap(); - let img = image::load_from_memory(&image_data).unwrap(); - let filtered = img.grayscale(); - let mut buf = vec![]; - match image_format_detected { - ImageFormat::Gif => { - filtered.write_to(&mut buf, ImageOutputFormat::Gif).unwrap(); - } - _ => { - filtered.write_to(&mut buf, ImageOutputFormat::Png).unwrap(); - } - }; - let mut base64_encoded = String::new(); - base64::encode_config_buf(&buf, base64::STANDARD, &mut base64_encoded); - return base64_encoded.to_string(); -} -``` - -### The Go host wrapper for microservice - -The [Go-based microservice](https://github.com/second-state/dapr-wasm/tree/main/image-api-go) embeds the above imaging processing function in WasmEdge. The [microservice itself](https://github.com/second-state/dapr-wasm/blob/main/image-api-go/image_api.go) is a web server and utilizes the Dapr Go SDK. - -```go -func main() { - s := daprd.NewService(":9003") - - if err := s.AddServiceInvocationHandler("/api/image", imageHandlerWASI); err != nil { - log.Fatalf("error adding invocation handler: %v", err) - } - - if err := s.Start(); err != nil && err != http.ErrServerClosed { - log.Fatalf("error listening: %v", err) - } -} -``` - -The `imageHandlerWASI()` function [starts a WasmEdge instance](../../../sdk/go/function.md) and calls the image processing (grayscale) function in it via [wasmedge_bindgen](../../../write_wasm/rust/bindgen.md). - -Build and deploy the Go microservice to Dapr as follows. - -```bash -cd image-api-go -go build -dapr run --app-id image-api-go \ - --app-protocol http \ - --app-port 9003 \ - --dapr-http-port 3501 \ - --log-level debug \ - --components-path ../config \ - ./image-api-go -``` - -### The Rust host wrapper for microservice - -The [Rust-based microservice](https://github.com/second-state/dapr-wasm/tree/main/image-api-rs) embeds the above imaging processing function in WasmEdge. The [microservice itself](https://github.com/second-state/dapr-wasm/blob/main/image-api-rs/src/main.rs) is a Tokio and Warp based web server. - -```rust -#[tokio::main] -pub async fn run_server(port: u16) { - pretty_env_logger::init(); - let home = warp::get().map(warp::reply); - - let image = warp::post() - .and(warp::path("api")) - .and(warp::path("image")) - .and(warp::body::bytes()) - .map(|bytes: bytes::Bytes| { - let v: Vec<u8> = bytes.iter().map(|&x| x).collect(); - let res = image_process_wasmedge_sys(&v); - let _encoded = base64::encode(&res); - Response::builder() - .header("content-type", "image/png") - .body(res) - }); - - let routes = home.or(image); - let routes = routes.with(warp::cors().allow_any_origin()); - - let log = warp::log("dapr_wasm"); - let routes = routes.with(log); - warp::serve(routes).run((Ipv4Addr::UNSPECIFIED, port)).await -} -``` - -The `image_process_wasmedge_sys()` function [starts a WasmEdge instance](../../../sdk/rust/sys_run_host_func.md) and calls the image processing (grayscale) function in it via [wasmedge_bindgen](../../../write_wasm/rust/bindgen.md). - -Build and deploy the Rust microservice to Dapr as follows. - -```bash -cd image-api-rs -cargo build --release -dapr stop image-api-rs - -# Change this to your own path for WasmEdge -export LD_LIBRARY_PATH=/home/coder/.wasmedge/lib64/ - -dapr run --app-id image-api-rs \ - --app-protocol http \ - --app-port 9004 \ - --dapr-http-port 3502 \ - --components-path ../config \ - --log-level debug \ - ./target/release/image-api-rs -``` - -That's it! [Let us know](https://github.com/WasmEdge/WasmEdge/discussions) your cool Dapr microservices in WebAssembly! diff --git a/docs/book/en/src/use_cases/frameworks/mesh/eventmesh.md b/docs/book/en/src/use_cases/frameworks/mesh/eventmesh.md deleted file mode 100644 index 7c49139dfd0b..000000000000 --- a/docs/book/en/src/use_cases/frameworks/mesh/eventmesh.md +++ /dev/null @@ -1,3 +0,0 @@ -# Apache EventMesh - -Coming soon, or you can [help out](https://github.com/WasmEdge/WasmEdge/issues/632) diff --git a/docs/book/en/src/use_cases/frameworks/mesh/mosn.md b/docs/book/en/src/use_cases/frameworks/mesh/mosn.md deleted file mode 100644 index a664f2bda2d3..000000000000 --- a/docs/book/en/src/use_cases/frameworks/mesh/mosn.md +++ /dev/null @@ -1,3 +0,0 @@ -# MOSN - -Coming soon. diff --git a/docs/book/en/src/use_cases/frameworks/mesh/wasm-nginx-module.md b/docs/book/en/src/use_cases/frameworks/mesh/wasm-nginx-module.md deleted file mode 100644 index 3e7d8c7b0c9b..000000000000 --- a/docs/book/en/src/use_cases/frameworks/mesh/wasm-nginx-module.md +++ /dev/null @@ -1,3 +0,0 @@ -# wasm-nginx-module - -> This part has been moved to <https://wasmedge.org/docs/embed/use-case/wasm-nginx>. Please use our new docs. \ No newline at end of file diff --git a/docs/book/en/src/use_cases/frameworks/serverless.md b/docs/book/en/src/use_cases/frameworks/serverless.md deleted file mode 100644 index f6028b544b56..000000000000 --- a/docs/book/en/src/use_cases/frameworks/serverless.md +++ /dev/null @@ -1,3 +0,0 @@ -# Serverless platforms - -> This part has been moved to <https://wasmedge.org/docs/category/use-cases>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/frameworks/serverless/aws.md b/docs/book/en/src/use_cases/frameworks/serverless/aws.md deleted file mode 100644 index 6973bf9f3af1..000000000000 --- a/docs/book/en/src/use_cases/frameworks/serverless/aws.md +++ /dev/null @@ -1,262 +0,0 @@ -# WebAssembly Serverless Functions in AWS Lambda - -In this article, we will show you two serverless functions in Rust and WasmEdge deployed on AWS Lambda. One is the image processing function, the other one is the TensorFlow inference function. - -> For the insight on why WasmEdge on AWS Lambda, please refer to the article [WebAssembly Serverless Functions in AWS Lambda](https://www.secondstate.io/articles/webassembly-serverless-functions-in-aws-lambda/) - -## Prerequisites - -Since our demo WebAssembly functions are written in Rust, you will need a [Rust compiler](https://www.rust-lang.org/tools/install). Make sure that you install the `wasm32-wasi` compiler target as follows, in order to generate WebAssembly bytecode. - -```bash -rustup target add wasm32-wasi -``` - -The demo application front end is written in [Next.js](https://nextjs.org/), and deployed on AWS Lambda. We will assume that you already have the basic knowledge of how to work with Next.js and Lambda. - -## Example 1: Image processing - -Our first demo application allows users to upload an image and then invoke a serverless function to turn it into black and white. A [live demo](https://second-state.github.io/aws-lambda-wasm-runtime/) deployed through GitHub Pages is available. - -Fork the [demo application’s GitHub repo](https://github.com/second-state/aws-lambda-wasm-runtime) to get started. To deploy the application on AWS Lambda, follow the guide in the repository [README](https://github.com/second-state/aws-lambda-wasm-runtime/blob/tensorflow/README.md). - -### Create the function - -This repo is a standard Next.js application. The backend serverless function is in the `api/functions/image_grayscale` folder. The `src/main.rs` file contains the Rust program’s source code. The Rust program reads image data from the `STDIN`, and then outputs the black-white image to the `STDOUT`. - -```rust -use hex; -use std::io::{self, Read}; -use image::{ImageOutputFormat, ImageFormat}; - -fn main() { - let mut buf = Vec::new(); - io::stdin().read_to_end(&mut buf).unwrap(); - - let image_format_detected: ImageFormat = image::guess_format(&buf).unwrap(); - let img = image::load_from_memory(&buf).unwrap(); - let filtered = img.grayscale(); - let mut buf = vec![]; - match image_format_detected { - ImageFormat::Gif => { - filtered.write_to(&mut buf, ImageOutputFormat::Gif).unwrap(); - }, - _ => { - filtered.write_to(&mut buf, ImageOutputFormat::Png).unwrap(); - }, - }; - io::stdout().write_all(&buf).unwrap(); - io::stdout().flush().unwrap(); -} -``` - -You can use Rust’s `cargo` tool to build the Rust program into WebAssembly bytecode or native code. - -```bash -cd api/functions/image-grayscale/ -cargo build --release --target wasm32-wasi -``` - -Copy the build artifacts to the `api` folder. - -```bash -cp target/wasm32-wasi/release/grayscale.wasm ../../ -``` - -> When we build the docker image, `api/pre.sh` is executed. `pre.sh` installs the WasmEdge runtime, and then compiles each WebAssembly bytecode program into a native `so` library for faster execution. - -### Create the service script to load the function - -The [`api/hello.js`](https://github.com/second-state/aws-lambda-wasm-runtime/blob/main/api/hello.js) script loads the WasmEdge runtime, starts the compiled WebAssembly program in WasmEdge, and passes the uploaded image data via `STDIN`. Notice that [`api/hello.js`](https://github.com/second-state/aws-lambda-wasm-runtime/blob/main/api/hello.js) runs the compiled `grayscale.so` file generated by [`api/pre.sh`](https://github.com/second-state/aws-lambda-wasm-runtime/blob/main/api/pre.sh) for better performance. - -```javascript -const { spawn } = require('child_process'); -const path = require('path'); - -function _runWasm(reqBody) { - return new Promise(resolve => { - const wasmedge = spawn(path.join(__dirname, 'wasmedge'), [path.join(__dirname, 'grayscale.so')]); - - let d = []; - wasmedge.stdout.on('data', (data) => { - d.push(data); - }); - - wasmedge.on('close', (code) => { - let buf = Buffer.concat(d); - resolve(buf); - }); - - wasmedge.stdin.write(reqBody); - wasmedge.stdin.end(''); - }); -} -``` - -The `exports.handler` part of `hello.js` exports an async function handler, used to handle different events every time the serverless function is called. In this example, we simply process the image by calling the function above and return the result, but more complicated event-handling behavior may be defined based on your need. We also need to return some `Access-Control-Allow` headers to avoid [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) errors when calling the serverless function from a browser. You can read more about CORS errors [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors) if you encounter them when replicating our example. - -```javascript -exports.handler = async function(event, context) { - var typedArray = new Uint8Array(event.body.match(/[\da-f]{2}/gi).map(function (h) { - return parseInt(h, 16); - })); - let buf = await _runWasm(typedArray); - return { - statusCode: 200, - headers: { - "Access-Control-Allow-Headers" : "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token", - "Access-Control-Allow-Origin": "*", - "Access-Control-Allow-Methods": "DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT" - }, - body: buf.toString('hex') - }; -} -``` - -### Build the Docker image for Lambda deployment - -Now we have the WebAssembly bytecode function and the script to load and connect to the web request. In order to deploy them as a function service on AWS Lambda, you still need to package the whole thing into a Docker image. - -We are not going to cover in detail about how to build the Docker image and deploy on AWS Lambda, as there are detailed steps in the [Deploy section of the repository README](https://github.com/second-state/aws-lambda-wasm-runtime/blob/tensorflow/README.md#deploy). However, we will highlight some lines in the [`Dockerfile`](https://github.com/second-state/aws-lambda-wasm-runtime/blob/tensorflow/api/Dockerfile) for you to avoid some pitfalls. - -```dockerfile -FROM public.ecr.aws/lambda/nodejs:14 - -# Change directory to /var/task -WORKDIR /var/task - -RUN yum update -y && yum install -y curl tar gzip - -# Bundle and pre-compile the wasm files -COPY *.wasm ./ -COPY pre.sh ./ -RUN chmod +x pre.sh -RUN ./pre.sh - -# Bundle the JS files -COPY *.js ./ - -CMD [ "hello.handler" ] -``` - -First, we are building the image from [AWS Lambda's Node.js base image](https://hub.docker.com/r/amazon/aws-lambda-nodejs). The advantage of using AWS Lambda's base image is that it includes the [Lambda Runtime Interface Client (RIC)](https://github.com/aws/aws-lambda-nodejs-runtime-interface-client), which we need to implement in our Docker image as it is required by AWS Lambda. The Amazon Linux uses `yum` as the package manager. - -> These base images contain the Amazon Linux Base operating system, the runtime for a given language, dependencies and the Lambda Runtime Interface Client (RIC), which implements the Lambda [Runtime API](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html). The Lambda Runtime Interface Client allows your runtime to receive requests from and send requests to the Lambda service. - -Second, we need to put our function and all its dependencies in the `/var/task` directory. Files in other folders will not be executed by AWS Lambda. - -Third, we need to define the default command when we start our container. `CMD [ "hello.handler" ]` means that we will call the `handler` function in `hello.js` whenever our serverless function is called. Recall that we have defined and exported the handler function in the previous steps through `exports.handler = ...` in `hello.js`. - -### Optional: test the Docker image locally - -Docker images built from AWS Lambda's base images can be tested locally following [this guide](https://docs.aws.amazon.com/lambda/latest/dg/images-test.html). Local testing requires [AWS Lambda Runtime Interface Emulator (RIE)](https://github.com/aws/aws-lambda-runtime-interface-emulator), which is already installed in all of AWS Lambda's base images. To test your image, first, start the Docker container by running: - -```bash -docker run -p 9000:8080 myfunction:latest -``` - -This command sets a function endpoint on your local machine at `http://localhost:9000/2015-03-31/functions/function/invocations`. - -Then, from a separate terminal window, run: - -```bash -curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}' -``` - -And you should get your expected output in the terminal. - -If you don't want to use a base image from AWS Lambda, you can also use your own base image and install RIC and/or RIE while building your Docker image. Just follow **Create an image from an alternative base image** section from [this guide](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html). - -That's it! After building your Docker image, you can deploy it to AWS Lambda following steps outlined in the repository [README](https://github.com/second-state/aws-lambda-wasm-runtime/blob/tensorflow/README.md#deploy). Now your serverless function is ready to rock! - -## Example 2: AI inference - -The [second demo](https://github.com/second-state/aws-lambda-wasm-runtime/tree/tensorflow) application allows users to upload an image and then invoke a serverless function to classify the main subject on the image. - -It is in [the same GitHub repo](https://github.com/second-state/aws-lambda-wasm-runtime/tree/tensorflow) as the previous example but in the `tensorflow` branch. The backend serverless function for image classification is in the `api/functions/image-classification` folder in the `tensorflow` branch. The `src/main.rs` file contains the Rust program’s source code. The Rust program reads image data from the `STDIN`, and then outputs the text output to the `STDOUT`. It utilizes the WasmEdge Tensorflow API to run the AI inference. - -```rust -pub fn main() { - // Step 1: Load the TFLite model - let model_data: &[u8] = include_bytes!("models/mobilenet_v1_1.0_224/mobilenet_v1_1.0_224_quant.tflite"); - let labels = include_str!("models/mobilenet_v1_1.0_224/labels_mobilenet_quant_v1_224.txt"); - - // Step 2: Read image from STDIN - let mut buf = Vec::new(); - io::stdin().read_to_end(&mut buf).unwrap(); - - // Step 3: Resize the input image for the tensorflow model - let flat_img = wasmedge_tensorflow_interface::load_jpg_image_to_rgb8(&buf, 224, 224); - - // Step 4: AI inference - let mut session = wasmedge_tensorflow_interface::Session::new(&model_data, wasmedge_tensorflow_interface::ModelType::TensorFlowLite); - session.add_input("input", &flat_img, &[1, 224, 224, 3]) - .run(); - let res_vec: Vec<u8> = session.get_output("MobilenetV1/Predictions/Reshape_1"); - - // Step 5: Find the food label that responds to the highest probability in res_vec - // ... ... - let mut label_lines = labels.lines(); - for _i in 0..max_index { - label_lines.next(); - } - - // Step 6: Generate the output text - let class_name = label_lines.next().unwrap().to_string(); - if max_value > 50 { - println!("It {} a <a href='https://www.google.com/search?q={}'>{}</a> in the picture", confidence.to_string(), class_name, class_name); - } else { - println!("It does not appears to be any food item in the picture."); - } -} -``` - -You can use the `cargo` tool to build the Rust program into WebAssembly bytecode or native code. - -```bash -cd api/functions/image-classification/ -cargo build --release --target wasm32-wasi -``` - -Copy the build artifacts to the `api` folder. - -```bash -cp target/wasm32-wasi/release/classify.wasm ../../ -``` - -Again, the `api/pre.sh` script installs WasmEdge runtime and its Tensorflow dependencies in this application. It also compiles the `classify.wasm` bytecode program to the `classify.so` native shared library at the time of deployment. - -The [`api/hello.js`](https://github.com/second-state/aws-lambda-wasm-runtime/blob/tensorflow/api/hello.js) script loads the WasmEdge runtime, starts the compiled WebAssembly program in WasmEdge, and passes the uploaded image data via `STDIN`. Notice [`api/hello.js`](https://github.com/second-state/aws-lambda-wasm-runtime/blob/tensorflow/api/hello.js) runs the compiled `classify.so` file generated by [`api/pre.sh`](https://github.com/second-state/aws-lambda-wasm-runtime/blob/tensorflow/api/pre.sh) for better performance. The handler function is similar to our previous example, and is omitted here. - -```javascript -const { spawn } = require('child_process'); -const path = require('path'); - -function _runWasm(reqBody) { - return new Promise(resolve => { - const wasmedge = spawn( - path.join(__dirname, 'wasmedge-tensorflow-lite'), - [path.join(__dirname, 'classify.so')], - {env: {'LD_LIBRARY_PATH': __dirname}} - ); - - let d = []; - wasmedge.stdout.on('data', (data) => { - d.push(data); - }); - - wasmedge.on('close', (code) => { - resolve(d.join('')); - }); - - wasmedge.stdin.write(reqBody); - wasmedge.stdin.end(''); - }); -} - -exports.handler = ... // _runWasm(reqBody) is called in the handler -``` - -You can build your Docker image and deploy the function in the same way as outlined in the previous example. Now you have created a web app for subject classification! - -Next, it's your turn to use the [aws-lambda-wasm-runtime repo](https://github.com/second-state/aws-lambda-wasm-runtime/tree/main) as a template to develop Rust serverless function on AWS Lambda. Looking forward to your great work. diff --git a/docs/book/en/src/use_cases/frameworks/serverless/netlify.md b/docs/book/en/src/use_cases/frameworks/serverless/netlify.md deleted file mode 100644 index 433b8b2af966..000000000000 --- a/docs/book/en/src/use_cases/frameworks/serverless/netlify.md +++ /dev/null @@ -1,185 +0,0 @@ -# WebAssembly Serverless Functions in Netlify - -In this article we will show you two serverless functions in Rust and WasmEdge deployed on Netlify. One is the image processing function, the other one is the TensorFlow inference function. - -> For more insights on why WasmEdge on Netlify, please refer to the article [WebAssembly Serverless Functions in Netlify](https://www.secondstate.io/articles/netlify-wasmedge-webassembly-rust-serverless/). - -## Prerequisite - -Since our demo WebAssembly functions are written in Rust, you will need a [Rust compiler](https://www.rust-lang.org/tools/install). Make sure that you install the `wasm32-wasi` compiler target as follows, in order to generate WebAssembly bytecode. - -```bash -rustup target add wasm32-wasi -``` - -The demo application front end is written in [Next.js](https://nextjs.org/), and deployed on Netlify. We will assume that you already have the basic knowledge of how to work with Next.js and Netlify. - -## Example 1: Image processing - -Our first demo application allows users to upload an image and then invoke a serverless function to turn it into black and white. A [live demo](https://60fe22f9ff623f0007656040--reverent-hodgkin-dc1f51.netlify.app/) deployed on Netlify is available. - -Fork the [demo application’s GitHub repo](https://github.com/second-state/netlify-wasm-runtime) to get started. To deploy the application on Netlify, just [add your github repo to Netlify](https://www.netlify.com/blog/2016/09/29/a-step-by-step-guide-deploying-on-netlify/). - -This repo is a standard Next.js application for the Netlify platform. The backend serverless function is in the [`api/functions/image_grayscale`](https://github.com/second-state/netlify-wasm-runtime/tree/main/api/functions/image-grayscale) folder. The [`src/main.rs`](https://github.com/second-state/netlify-wasm-runtime/blob/main/api/functions/image-grayscale/src/main.rs) file contains the Rust program’s source code. The Rust program reads image data from the `STDIN`, and then outputs the black-white image to the `STDOUT`. - -```rust -use hex; -use std::io::{self, Read}; -use image::{ImageOutputFormat, ImageFormat}; - -fn main() { - let mut buf = Vec::new(); - io::stdin().read_to_end(&mut buf).unwrap(); - - let image_format_detected: ImageFormat = image::guess_format(&buf).unwrap(); - let img = image::load_from_memory(&buf).unwrap(); - let filtered = img.grayscale(); - let mut buf = vec![]; - match image_format_detected { - ImageFormat::Gif => { - filtered.write_to(&mut buf, ImageOutputFormat::Gif).unwrap(); - }, - _ => { - filtered.write_to(&mut buf, ImageOutputFormat::Png).unwrap(); - }, - }; - io::stdout().write_all(&buf).unwrap(); - io::stdout().flush().unwrap(); -} -``` - -You can use Rust’s `cargo` tool to build the Rust program into WebAssembly bytecode or native code. - -```bash -cd api/functions/image-grayscale/ -cargo build --release --target wasm32-wasi -``` - -Copy the build artifacts to the `api` folder. - -```bash -cp target/wasm32-wasi/release/grayscale.wasm ../../ -``` - -> The Netlify function runs [`api/pre.sh`](https://github.com/second-state/netlify-wasm-runtime/blob/main/api/pre.sh) upon setting up the serverless environment. It installs the WasmEdge runtime, and then compiles each WebAssembly bytecode program into a native `so` library for faster execution. - -The [`api/hello.js`](https://github.com/second-state/netlify-wasm-runtime/blob/main/api/hello.js) script loads the WasmEdge runtime, starts the compiled WebAssembly program in WasmEdge, and passes the uploaded image data via `STDIN`. Notice [`api/hello.js`](https://github.com/second-state/netlify-wasm-runtime/blob/main/api/hello.js) runs the compiled `grayscale.so` file generated by [`api/pre.sh`](https://github.com/second-state/netlify-wasm-runtime/blob/main/api/pre.sh) for better performance. - -```javascript -const fs = require('fs'); -const { spawn } = require('child_process'); -const path = require('path'); - -module.exports = (req, res) => { - const wasmedge = spawn( - path.join(__dirname, 'wasmedge'), - [path.join(__dirname, 'grayscale.so')]); - - let d = []; - wasmedge.stdout.on('data', (data) => { - d.push(data); - }); - - wasmedge.on('close', (code) => { - let buf = Buffer.concat(d); - - res.setHeader('Content-Type', req.headers['image-type']); - res.send(buf); - }); - - wasmedge.stdin.write(req.body); - wasmedge.stdin.end(''); -} -``` - -That's it. [Deploy the repo to Netlify](https://www.netlify.com/blog/2016/09/29/a-step-by-step-guide-deploying-on-netlify/) and you now have a Netlify Jamstack app with a high-performance Rust and WebAssembly based serverless backend. - -## Example 2: AI inference - -The [second demo](https://60ff7e2d10fe590008db70a9--reverent-hodgkin-dc1f51.netlify.app/) application allows users to upload an image and then invoke a serverless function to classify the main subject on the image. - -It is in [the same GitHub repo](https://github.com/second-state/netlify-wasm-runtime/tree/tensorflow) as the previous example but in the `tensorflow` branch. The backend serverless function for image classification is in the [`api/functions/image-classification`](https://github.com/second-state/netlify-wasm-runtime/tree/tensorflow/api/functions/image-classification) folder in the `tensorflow` branch. The [`src/main.rs`](https://github.com/second-state/netlify-wasm-runtime/blob/tensorflow/api/functions/image-classification/src/main.rs) file contains the Rust program’s source code. The Rust program reads image data from the `STDIN`, and then outputs the text output to the `STDOUT`. It utilizes the WasmEdge Tensorflow API to run the AI inference. - -```rust -pub fn main() { - // Step 1: Load the TFLite model - let model_data: &[u8] = include_bytes!("models/mobilenet_v1_1.0_224/mobilenet_v1_1.0_224_quant.tflite"); - let labels = include_str!("models/mobilenet_v1_1.0_224/labels_mobilenet_quant_v1_224.txt"); - - // Step 2: Read image from STDIN - let mut buf = Vec::new(); - io::stdin().read_to_end(&mut buf).unwrap(); - - // Step 3: Resize the input image for the tensorflow model - let flat_img = wasmedge_tensorflow_interface::load_jpg_image_to_rgb8(&buf, 224, 224); - - // Step 4: AI inference - let mut session = wasmedge_tensorflow_interface::Session::new(&model_data, wasmedge_tensorflow_interface::ModelType::TensorFlowLite); - session.add_input("input", &flat_img, &[1, 224, 224, 3]) - .run(); - let res_vec: Vec<u8> = session.get_output("MobilenetV1/Predictions/Reshape_1"); - - // Step 5: Find the food label that responds to the highest probability in res_vec - // ... ... - let mut label_lines = labels.lines(); - for _i in 0..max_index { - label_lines.next(); - } - - // Step 6: Generate the output text - let class_name = label_lines.next().unwrap().to_string(); - if max_value > 50 { - println!("It {} a <a href='https://www.google.com/search?q={}'>{}</a> in the picture", confidence.to_string(), class_name, class_name); - } else { - println!("It does not appears to be any food item in the picture."); - } -} -``` - -You can use the `cargo` tool to build the Rust program into WebAssembly bytecode or native code. - -```bash -cd api/functions/image-classification/ -cargo build --release --target wasm32-wasi -``` - -Copy the build artifacts to the `api` folder. - -```bash -cp target/wasm32-wasi/release/classify.wasm ../../ -``` - -Again, the [`api/pre.sh`](https://github.com/second-state/netlify-wasm-runtime/blob/tensorflow/api/pre.sh) script installs WasmEdge runtime and its Tensorflow dependencies in this application. It also compiles the `classify.wasm` bytecode program to the `classify.so` native shared library at the time of deployment. - -The [`api/hello.js`](https://github.com/second-state/netlify-wasm-runtime/blob/tensorflow/api/hello.js) script loads the WasmEdge runtime, starts the compiled WebAssembly program in WasmEdge, and passes the uploaded image data via `STDIN`. Notice [`api/hello.js`](https://github.com/second-state/netlify-wasm-runtime/blob/tensorflow/api/hello.js) runs the compiled `classify.so` file generated by [`api/pre.sh`](https://github.com/second-state/netlify-wasm-runtime/blob/tensorflow/api/pre.sh) for better performance. - -```javascript -const fs = require('fs'); -const { spawn } = require('child_process'); -const path = require('path'); - -module.exports = (req, res) => { - const wasmedge = spawn( - path.join(__dirname, 'wasmedge-tensorflow-lite'), - [path.join(__dirname, 'classify.so')], - {env: {'LD_LIBRARY_PATH': __dirname}} - ); - - let d = []; - wasmedge.stdout.on('data', (data) => { - d.push(data); - }); - - wasmedge.on('close', (code) => { - res.setHeader('Content-Type', `text/plain`); - res.send(d.join('')); - }); - - wasmedge.stdin.write(req.body); - wasmedge.stdin.end(''); -} -``` - -You can now [deploy your forked repo to Netlify](https://www.netlify.com/blog/2016/09/29/a-step-by-step-guide-deploying-on-netlify/) and have a web app for subject classification. - -Next, it's your turn to develop Rust serverless functions in Netlify using the [netlify-wasm-runtime repo](https://github.com/second-state/netlify-wasm-runtime) as a template. Looking forward to your great work. diff --git a/docs/book/en/src/use_cases/frameworks/serverless/secondstate.md b/docs/book/en/src/use_cases/frameworks/serverless/secondstate.md deleted file mode 100644 index c2045004b1b1..000000000000 --- a/docs/book/en/src/use_cases/frameworks/serverless/secondstate.md +++ /dev/null @@ -1,14 +0,0 @@ -# Second State Functions - -Second State Functions, powered by WasmEdge, supports the Rust language as a first class citizen. - -It could - -* [Handle text-based input and output](https://www.secondstate.io/articles/getting-started-with-function-as-a-service-in-rust/) -* [Use Binary data as function input and output](https://www.secondstate.io/articles/use-binary-data-as-function-input-and-output/) -* [Mix bytes and strings in function argument and return value](https://www.secondstate.io/articles/use-binary-data-as-function-input-and-output/) -* [Use webhooks as function input and output](https://www.secondstate.io/articles/internet-of-functions-webhooks/) -* [Access internet resources via a `http_proxy` API](https://www.secondstate.io/articles/internet-of-functions-http-proxy/) -* [Running TensorFlow models at native speed via the WasmEdge TensorFlow API](https://www.secondstate.io/articles/wasi-tensorflow/) - -Check out the [Second State Functions](https://www.secondstate.io/faas/) website for more tutorials. diff --git a/docs/book/en/src/use_cases/frameworks/serverless/tencent.md b/docs/book/en/src/use_cases/frameworks/serverless/tencent.md deleted file mode 100644 index 4e2d4098902c..000000000000 --- a/docs/book/en/src/use_cases/frameworks/serverless/tencent.md +++ /dev/null @@ -1,7 +0,0 @@ -# WebAssembly serverless functions on Tencent Cloud - -As the main users of Tencent Cloud are from China, so the tutorial is [written in Chinese](https://my.oschina.net/u/4532842/blog/5172639). - -We also provide a code template for deploying serverless WebAssembly functions on Tencent Cloud, please check out [the tencent-scf-wasm-runtime repo](https://github.com/second-state/tencent-scf-wasm-runtime). - -Fork the repo and start writing your own rust functions. diff --git a/docs/book/en/src/use_cases/frameworks/serverless/vercel.md b/docs/book/en/src/use_cases/frameworks/serverless/vercel.md deleted file mode 100644 index 8c7e0dbe780f..000000000000 --- a/docs/book/en/src/use_cases/frameworks/serverless/vercel.md +++ /dev/null @@ -1,187 +0,0 @@ -# Rust and WebAssembly Serverless functions in Vercel - -In this article, we will show you two serverless functions in Rust and WasmEdge deployed on Vercel. One is the image processing function, the other one is the TensorFlow inference function. - -> For more insights on why WasmEdge on Vercel, please refer to the article [Rust and WebAssembly Serverless Functions in Vercel](https://www.secondstate.io/articles/vercel-wasmedge-webassembly-rust/). - -## Prerequisite - -Since our demo WebAssembly functions are written in Rust, you will need a [Rust compiler](https://www.rust-lang.org/tools/install). Make sure that you install the `wasm32-wasi` compiler target as follows, in order to generate WebAssembly bytecode. - -```bash -rustup target add wasm32-wasi -``` - -The demo application front end is written in [Next.js](https://nextjs.org/), and deployed on Vercel. We will assume that you already have the basic knowledge of how to work with Vercel. - -## Example 1: Image processing - -Our first demo application allows users to upload an image and then invoke a serverless function to turn it into black and white. A [live demo](https://vercel-wasm-runtime.vercel.app/) deployed on Vercel is available. - -Fork the [demo application’s GitHub repo](https://github.com/second-state/vercel-wasm-runtime) to get started. To deploy the application on Vercel, just [import the Github repo](https://vercel.com/docs/git#deploying-a-git-repository) from [Vercel for Github](https://vercel.com/docs/git/vercel-for-github) web page. - -This repo is a standard Next.js application for the Vercel platform. The backend serverless function is in the [`api/functions/image_grayscale`](https://github.com/second-state/vercel-wasm-runtime/tree/main/api/functions/image-grayscale) folder. The [`src/main.rs`](https://github.com/second-state/vercel-wasm-runtime/blob/main/api/functions/image-grayscale/src/main.rs) file contains the Rust program’s source code. The Rust program reads image data from the `STDIN`, and then outputs the black-white image to the `STDOUT`. - -```rust -use hex; -use std::io::{self, Read}; -use image::{ImageOutputFormat, ImageFormat}; - -fn main() { - let mut buf = Vec::new(); - io::stdin().read_to_end(&mut buf).unwrap(); - - let image_format_detected: ImageFormat = image::guess_format(&buf).unwrap(); - let img = image::load_from_memory(&buf).unwrap(); - let filtered = img.grayscale(); - let mut buf = vec![]; - match image_format_detected { - ImageFormat::Gif => { - filtered.write_to(&mut buf, ImageOutputFormat::Gif).unwrap(); - }, - _ => { - filtered.write_to(&mut buf, ImageOutputFormat::Png).unwrap(); - }, - }; - io::stdout().write_all(&buf).unwrap(); - io::stdout().flush().unwrap(); -} -``` - -You can use Rust’s `cargo` tool to build the Rust program into WebAssembly bytecode or native code. - -```bash -cd api/functions/image-grayscale/ -cargo build --release --target wasm32-wasi -``` - -Copy the build artifacts to the `api` folder. - -```bash -cp target/wasm32-wasi/release/grayscale.wasm ../../ -``` - -> Vercel runs [`api/pre.sh`](https://github.com/second-state/vercel-wasm-runtime/blob/main/api/pre.sh) upon setting up the serverless environment. It installs the WasmEdge runtime, and then compiles each WebAssembly bytecode program into a native `so` library for faster execution. - -The [`api/hello.js`](https://github.com/second-state/vercel-wasm-runtime/blob/main/api/hello.js) file conforms Vercel serverless specification. It loads the WasmEdge runtime, starts the compiled WebAssembly program in WasmEdge, and passes the uploaded image data via `STDIN`. Notice [`api/hello.js`](https://github.com/second-state/vercel-wasm-runtime/blob/main/api/hello.js) runs the compiled `grayscale.so` file generated by [`api/pre.sh`](https://github.com/second-state/vercel-wasm-runtime/blob/main/api/pre.sh) for better performance. - -```javascript -const fs = require('fs'); -const { spawn } = require('child_process'); -const path = require('path'); - -module.exports = (req, res) => { - const wasmedge = spawn( - path.join(__dirname, 'wasmedge'), - [path.join(__dirname, 'grayscale.so')]); - - let d = []; - wasmedge.stdout.on('data', (data) => { - d.push(data); - }); - - wasmedge.on('close', (code) => { - let buf = Buffer.concat(d); - - res.setHeader('Content-Type', req.headers['image-type']); - res.send(buf); - }); - - wasmedge.stdin.write(req.body); - wasmedge.stdin.end(''); -} -``` - -That's it. [Deploy the repo to Vercel](https://vercel.com/docs/git#deploying-a-git-repository) and you now have a Vercel Jamstack app with a high-performance Rust and WebAssembly based serverless backend. - -## Example 2: AI inference - -The [second demo](https://vercel-wasm-runtime.vercel.app/) application allows users to upload an image and then invoke a serverless function to classify the main subject on the image. - -It is in [the same GitHub repo](https://github.com/second-state/vercel-wasm-runtime) as the previous example but in the `tensorflow` branch. Note: when you [import this GitHub repo](https://vercel.com/docs/git#deploying-a-git-repository) on the Vercel website, it will create a [preview URL](https://vercel.com/docs/platform/deployments#preview) for each branch. The `tensorflow` branch would have its own deployment URL. - -The backend serverless function for image classification is in the [`api/functions/image-classification`](https://github.com/second-state/vercel-wasm-runtime/tree/tensorflow/api/functions/image-classification) folder in the `tensorflow` branch. The [`src/main.rs`](https://github.com/second-state/vercel-wasm-runtime/blob/tensorflow/api/functions/image-classification/src/main.rs) file contains the Rust program’s source code. The Rust program reads image data from the `STDIN`, and then outputs the text output to the `STDOUT`. It utilizes the WasmEdge Tensorflow API to run the AI inference. - -```rust -pub fn main() { - // Step 1: Load the TFLite model - let model_data: &[u8] = include_bytes!("models/mobilenet_v1_1.0_224/mobilenet_v1_1.0_224_quant.tflite"); - let labels = include_str!("models/mobilenet_v1_1.0_224/labels_mobilenet_quant_v1_224.txt"); - - // Step 2: Read image from STDIN - let mut buf = Vec::new(); - io::stdin().read_to_end(&mut buf).unwrap(); - - // Step 3: Resize the input image for the tensorflow model - let flat_img = wasmedge_tensorflow_interface::load_jpg_image_to_rgb8(&buf, 224, 224); - - // Step 4: AI inference - let mut session = wasmedge_tensorflow_interface::Session::new(&model_data, wasmedge_tensorflow_interface::ModelType::TensorFlowLite); - session.add_input("input", &flat_img, &[1, 224, 224, 3]) - .run(); - let res_vec: Vec<u8> = session.get_output("MobilenetV1/Predictions/Reshape_1"); - - // Step 5: Find the food label that responds to the highest probability in res_vec - // ... ... - let mut label_lines = labels.lines(); - for _i in 0..max_index { - label_lines.next(); - } - - // Step 6: Generate the output text - let class_name = label_lines.next().unwrap().to_string(); - if max_value > 50 { - println!("It {} a <a href='https://www.google.com/search?q={}'>{}</a> in the picture", confidence.to_string(), class_name, class_name); - } else { - println!("It does not appears to be any food item in the picture."); - } -} -``` - -You can use the `cargo` tool to build the Rust program into WebAssembly bytecode or native code. - -```bash -cd api/functions/image-classification/ -cargo build --release --target wasm32-wasi -``` - -Copy the build artifacts to the `api` folder. - -```bash -cp target/wasm32-wasi/release/classify.wasm ../../ -``` - -Again, the [`api/pre.sh`](https://github.com/second-state/vercel-wasm-runtime/blob/tensorflow/api/pre.sh) script installs WasmEdge runtime and its Tensorflow dependencies in this application. It also compiles the `classify.wasm` bytecode program to the `classify.so` native shared library at the time of deployment. - -The [`api/hello.js`](https://github.com/second-state/vercel-wasm-runtime/blob/tensorflow/api/hello.js) file conforms Vercel serverless specification. It loads the WasmEdge runtime, starts the compiled WebAssembly program in WasmEdge, and passes the uploaded image data via `STDIN`. Notice [`api/hello.js`](https://github.com/second-state/vercel-wasm-runtime/blob/tensorflow/api/hello.js) runs the compiled `classify.so` file generated by [`api/pre.sh`](https://github.com/second-state/vercel-wasm-runtime/blob/tensorflow/api/pre.sh) for better performance. - -```javascript -const fs = require('fs'); -const { spawn } = require('child_process'); -const path = require('path'); - -module.exports = (req, res) => { - const wasmedge = spawn( - path.join(__dirname, 'wasmedge-tensorflow-lite'), - [path.join(__dirname, 'classify.so')], - {env: {'LD_LIBRARY_PATH': __dirname}} - ); - - let d = []; - wasmedge.stdout.on('data', (data) => { - d.push(data); - }); - - wasmedge.on('close', (code) => { - res.setHeader('Content-Type', `text/plain`); - res.send(d.join('')); - }); - - wasmedge.stdin.write(req.body); - wasmedge.stdin.end(''); -} -``` - -You can now [deploy your forked repo to Vercel](https://vercel.com/docs/git#deploying-a-git-repository) and have a web app for subject classification. - -Next, it's your turn to use [the vercel-wasm-runtime repo](https://github.com/second-state/vercel-wasm-runtime) as a template to develop your own Rust serverless functions in Vercel. Looking forward to your great work. diff --git a/docs/book/en/src/use_cases/js_or_dsl_runtime.md b/docs/book/en/src/use_cases/js_or_dsl_runtime.md deleted file mode 100644 index 5d43a3c87be6..000000000000 --- a/docs/book/en/src/use_cases/js_or_dsl_runtime.md +++ /dev/null @@ -1,25 +0,0 @@ -# JavaScript or Domain Specific Language Runtime - -In order for WebAssembly to be widely adopted by developers as a runtime, it must support "easy" languages like JavaScript. Or, better yet, through its advanced compiler toolchain, WasmEdge could support high performance DSLs (Domain Specific Languages), which are low code solutions designed for specific tasks. - -## JavaScript - -WasmEdge can act as a cloud-native JavaScript runtime by embedding a JS execution engine or interpreter. It is faster and lighter than running a JS engine inside Docker. WasmEdge supports JS APIs to access native extension libraries such as network sockets, tensorflow, and user-defined shared libraries. It also allows embedding JS into other high-performance languages (eg, Rust) or using Rust / C to implement JS functions. - -* Tutorials - * [Run JavaScript](https://www.secondstate.io/articles/run-javascript-in-webassembly-with-wasmedge/) - * [Embed JavaScript in Rust](https://www.secondstate.io/articles/embed-javascript-in-rust/) - * [Create JavaScript API using Rust functions](https://www.secondstate.io/articles/embed-rust-in-javascript/) - * [Call C native shared library functions from JavaScript](https://www.secondstate.io/articles/call-native-functions-from-javascript/) -* [Examples](../write_wasm/js.md) -* [WasmEdge’s embedded QuickJS engine](https://github.com/second-state/wasmedge-quickjs) - -## DSL for image classification - -The image classification DSL is a YAML format that allows the user to specify a tensorflow model and its parameters. WasmEdge takes an image as the input of the DSL and outputs the detected item name / label. - -* Example: [Run a YAML to detect food items in an image](https://github.com/second-state/wasm-learning/blob/master/cli/classify_yml/config/food.yml) - -## DSL for chatbots - -A chatbot DSL function takes an input string and responds with a reply string. The DSL specifies the internal state transitions of the chatbot, as well as AI models for language understanding. This work is in progress. diff --git a/docs/book/en/src/use_cases/kubernetes.md b/docs/book/en/src/use_cases/kubernetes.md deleted file mode 100644 index 35cb8ade6d94..000000000000 --- a/docs/book/en/src/use_cases/kubernetes.md +++ /dev/null @@ -1,22 +0,0 @@ -# WasmEdge in Kubernetes - -Developers can leverage container tools such as Kubernetes, Docker and CRI-O to deploy, manage, and run lightweight WebAssembly applications. In this chapter, we will demonstrate how Kubernetes ecosystem tools work with WasmEdge WebAssembly applications. - -Compared with Linux containers, [WebAssembly could be 100x faster at startup](https://www.infoq.com/articles/arm-vs-x86-cloud-performance/), have a much smaller memory and disk footprint, and have a better-defined safety sandbox. However, the trade-off is that WebAssembly requires its own language SDKs, and compiler toolchains, making it a more constrained developer environment than Linux containers. WebAssembly is increasingly used in Edge Computing scenarios where it is difficult to deploy Linux containers or when the application performance is vital. - -One of the great advantages of Linux application containers is the rich ecosystem of tools. The good news is that you can use the exact same tools to manage WebAssembly applications, enabling Linux containers and WebAssembly apps to run side-by-side in the same system. - -![kubernetes](kubernetes.png) - -The contents of this chapter are organized by the approaches for integrating WasmEdge into container toolchains. - -* The [slimmed Linux container tailored for WasmEdge](kubernetes/docker/lxc.md) offers the easiest option (but with performance trade-offs) to integrate WasmEdge applications into any container tooling system. -* The most important integration approach is to replace the underlying OCI runtime of the toolchain stack with a WasmEdge-enabled `crun` runtime. - * [Quick start](kubernetes/quickstart.md) provides simple and scripted tutorials to run WasmEdge-based applications as container images in Kubernetes. - * [Demo apps](kubernetes/demo.md) discusses the two demo WasmEdge applications we will run in Kubernetes clusters. Those applications are compiled from Rust source code, packaged as OCI images, and uploaded to Docker Hub. - * [Container runtimes](kubernetes/container.md) covers how to configure low level container runtimes, such as crun, to load and run WebAssembly OCI images. - * [CRI runtimes](kubernetes/cri.md) covers how to configure and use high level container runtimes, such as CRI-O and containerd, to load and run WebAssembly OCI images on top of low level container runtimes. - * [Kubernetes](kubernetes/kubernetes.md) covers how to configure and use Kubernetes and Kubernetes variations, such as KubeEdge and SuperEdge, to load and run WebAssembly OCI images on top of CRI runtimes. -* If you cannot replace the OCI runtime in your toolchain with WasmEdge-enabled `crun`, you can use a [containerd shim](kubernetes/docker/containerd.md) to start and run a WasmEdge application without any intrusive change. - -The goal is to load and run WebAssembly OCI images side by side with Linux OCI images (e.g., today's Docker containers) across the entire Kubernetes stack. diff --git a/docs/book/en/src/use_cases/kubernetes.png b/docs/book/en/src/use_cases/kubernetes.png deleted file mode 100644 index df662c8f040fb7359e16c40dec8d844bc6a7096a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42780 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 F{s(ouox%VB diff --git a/docs/book/en/src/use_cases/kubernetes/container.md b/docs/book/en/src/use_cases/kubernetes/container.md deleted file mode 100644 index 9d526ba8e26f..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/container.md +++ /dev/null @@ -1,7 +0,0 @@ -# Container runtimes - -The container image can be started by any OCI-compliant container runtime, such as - -* [crun](container/crun.md): a high performance and lightweight container runtime written in C -* [runc](container/runc.md): a widely used container runtime written in Go -* [youki](container/youki.md): a OCI-compatible container runtime implementation written in Rust diff --git a/docs/book/en/src/use_cases/kubernetes/container/crun.md b/docs/book/en/src/use_cases/kubernetes/container/crun.md deleted file mode 100644 index 9bf8a9beaf70..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/container/crun.md +++ /dev/null @@ -1,3 +0,0 @@ -# crun - -> This part has been moved to <https://wasmedge.org/docs/develop/deploy/oci-runtime/crun>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/kubernetes/container/runc.md b/docs/book/en/src/use_cases/kubernetes/container/runc.md deleted file mode 100644 index 32da69bde828..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/container/runc.md +++ /dev/null @@ -1,3 +0,0 @@ -# runc - -Coming soon, or you can [help out](https://github.com/WasmEdge/WasmEdge/issues/639) diff --git a/docs/book/en/src/use_cases/kubernetes/container/youki.md b/docs/book/en/src/use_cases/kubernetes/container/youki.md deleted file mode 100644 index 32d2db37dcb6..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/container/youki.md +++ /dev/null @@ -1,3 +0,0 @@ -# youki - -> This part has been moved to <https://wasmedge.org/docs/develop/deploy/oci-runtime/youki>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/kubernetes/cri.md b/docs/book/en/src/use_cases/kubernetes/cri.md deleted file mode 100644 index 4ef67343d9c6..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/cri.md +++ /dev/null @@ -1,7 +0,0 @@ -# CRI runtimes - -The high-level container runtime, such as [CRI-O](https://cri-o.io/) and [containerd](https://containerd.io/), pulls container images from registries (e.g., Docker Hub), manages them on disk, and launches a lower-level runtime to run container processes. -From this chapter, you can check out specific tutorials for CRI-O and containerd. - -* [CRI-O](cri/crio.md) -* [containerd](cri/containerd.md) diff --git a/docs/book/en/src/use_cases/kubernetes/cri/containerd.md b/docs/book/en/src/use_cases/kubernetes/cri/containerd.md deleted file mode 100644 index c81b780c22df..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/cri/containerd.md +++ /dev/null @@ -1,3 +0,0 @@ -# containerd - -This docs has moved to <https://wasmedge.org/docs/develop/deploy/cri-runtime/containerd-crun>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/kubernetes/cri/crio.md b/docs/book/en/src/use_cases/kubernetes/cri/crio.md deleted file mode 100644 index 94c1687e5fe4..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/cri/crio.md +++ /dev/null @@ -1,3 +0,0 @@ -# CRI-O - -This docs has moved to <https://wasmedge.org/docs/develop/deploy/cri-runtime/cri-o-crun>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/kubernetes/demo.md b/docs/book/en/src/use_cases/kubernetes/demo.md deleted file mode 100644 index c20e0ea394eb..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/demo.md +++ /dev/null @@ -1,15 +0,0 @@ -# Demo apps - -In this chapter, we will cover two demo apps. We will build them from Rust source code, build OCI images around them, and then publish the images to Docker Hub. - -If you have not done so, please - -* [Install Rust](https://www.rust-lang.org/tools/install) -* [Register for Docker Hub](https://hub.docker.com/) - -Next, explore the examples - -* [A simple WASI example](demo/wasi.md) -* [A HTTP server example](demo/server.md) - -Since we have already built and published those demo apps on Docker Hub, you could also just go straight to the container runtime sections to use these images. diff --git a/docs/book/en/src/use_cases/kubernetes/demo/server.md b/docs/book/en/src/use_cases/kubernetes/demo/server.md deleted file mode 100644 index 90df48fa5fce..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/demo/server.md +++ /dev/null @@ -1,3 +0,0 @@ -# HTTP server example - -> This part has been moved to <https://github.com/second-state/wasmedge-containers-examples/blob/main/http_server_wasi_app.md>. Please use our new docs. \ No newline at end of file diff --git a/docs/book/en/src/use_cases/kubernetes/demo/wasi.md b/docs/book/en/src/use_cases/kubernetes/demo/wasi.md deleted file mode 100644 index 14758bb92270..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/demo/wasi.md +++ /dev/null @@ -1,97 +0,0 @@ -# A simple WebAssembly example - -In this article, I will show you how to build a container image for a WebAssembly application. It can then be started and managed by Kubernetes ecosystem tools, such as CRI-O, Docker, crun, and Kubernetes. - -## Prerequisites - -> If you simply want a wasm bytecode file to test as a container image, you can skip the building process and just [download the wasm file here](https://github.com/second-state/wasm-learning/blob/master/cli/wasi/wasi_example_main.wasm). - -If you have not done so already, follow these simple instructions to [install Rust](https://www.rust-lang.org/tools/install). - -## Download example code - -```bash -git clone https://github.com/second-state/wasm-learning -cd wasm-learning/cli/wasi -``` - -## Build the WASM bytecode - -```bash -rustup target add wasm32-wasi -cargo build --target wasm32-wasi --release -``` - -The wasm bytecode application is in the `target/wasm32-wasi/release/wasi_example_main.wasm` file. You can now publish and use it as a container image. - -## Apply executable permission on the Wasm bytecode - -```bash -chmod +x target/wasm32-wasi/release/wasi_example_main.wasm -``` - -## Create Dockerfile - -Create a file called `Dockerfile` in the `target/wasm32-wasi/release/` folder with the following content: - -```dockerfile -FROM scratch -ADD wasi_example_main.wasm / -CMD ["/wasi_example_main.wasm"] -``` - -## Create container image with annotations - -> Please note that adding self-defined annotation is still a new feature in buildah. - -The `crun` container runtime can start the above WebAssembly-based container image. But it requires the `module.wasm.image/variant=compat-smart` annotation on the container image to indicate that it is a WebAssembly application without a guest OS. You can find the details in [Official crun repo](https://github.com/containers/crun/blob/main/docs/wasm-wasi-example.md). - -To add `module.wasm.image/variant=compat-smart` annotation in the container image, you will need the latest [buildah](https://buildah.io/). Currently, Docker does not support this feature. Please follow [the install instructions of buildah](https://github.com/containers/buildah/blob/main/install.md) to build the latest buildah binary. - -### Build and install the latest buildah on Ubuntu - -On Ubuntu zesty and xenial, use these commands to prepare for buildah. - -```bash -sudo apt-get -y install software-properties-common - -export OS="xUbuntu_20.04" -sudo bash -c "echo \"deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /\" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list" -sudo bash -c "curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | apt-key add -" - -sudo add-apt-repository -y ppa:alexlarsson/flatpak -sudo apt-get -y -qq update -sudo apt-get -y install bats git libapparmor-dev libdevmapper-dev libglib2.0-dev libgpgme-dev libseccomp-dev libselinux1-dev skopeo-containers go-md2man containers-common -sudo apt-get -y install golang-1.16 make -``` - -Then, follow these steps to build and install buildah on Ubuntu. - -```bash -mkdir -p ~/buildah -cd ~/buildah -export GOPATH=`pwd` -git clone https://github.com/containers/buildah ./src/github.com/containers/buildah -cd ./src/github.com/containers/buildah -PATH=/usr/lib/go-1.16/bin:$PATH make -cp bin/buildah /usr/bin/buildah -buildah --help -``` - -### Create and publish a container image with buildah - -In the `target/wasm32-wasi/release/` folder, do the following. - -```bash -$ sudo buildah build --annotation "module.wasm.image/variant=compat-smart" -t wasm-wasi-example . -# make sure docker is install and running -# systemctl status docker -# to make sure regular user can use docker -# sudo usermod -aG docker $USER -# newgrp docker - -# You may need to use docker login to create the `~/.docker/config.json` for auth. -$ sudo buildah push --authfile ~/.docker/config.json wasm-wasi-example docker://docker.io/wasmedge/example-wasi:latest -``` - -That's it! Now you can try to run it in [CRI-O](../cri/crio.md#run-a-simple-webassembly-app) or [Kubernetes](../kubernetes/kubernetes-crio.md#a-simple-webassembly-app)! diff --git a/docs/book/en/src/use_cases/kubernetes/docker.md b/docs/book/en/src/use_cases/kubernetes/docker.md deleted file mode 100644 index 5e5972ae0a74..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/docker.md +++ /dev/null @@ -1,6 +0,0 @@ -# Running WasmEdge apps with the Docker CLI - -The Docker CLI is a very popular developer tool. However, it is not easy to replace Docker's underlying OCI runtime (`runc`) with the WasmEdge-enabled `crun`. In this section, we will discuss two ways to run WasmEdge applications in Docker. - -* [Wrap WasmEdge in a slim Linux container](docker/lxc.md) -* [Use containerd shim](docker/containerd.md) diff --git a/docs/book/en/src/use_cases/kubernetes/docker/containerd.md b/docs/book/en/src/use_cases/kubernetes/docker/containerd.md deleted file mode 100644 index a05295f9bc43..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/docker/containerd.md +++ /dev/null @@ -1,5 +0,0 @@ -# Use the containerd shim - -As we discussed, wrapping WebAssembly inside a Docker Linux container results in performance and security penalties. However, we cannot easily replace the OCI runtime (`runc`) in the Docker toolchain as well. In this chapter, we will discuss another approach to start and run WebAssembly bytecode applications directly from the Docker CLI. - -Coming soon diff --git a/docs/book/en/src/use_cases/kubernetes/docker/lxc.md b/docs/book/en/src/use_cases/kubernetes/docker/lxc.md deleted file mode 100644 index 5d45675f3515..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/docker/lxc.md +++ /dev/null @@ -1,3 +0,0 @@ -# Use the slim Linux container - -> This part has been moved to <https://wasmedge.org/docs/develop/deploy/using-wasmedge-in-docker>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/kubernetes/kubernetes.md b/docs/book/en/src/use_cases/kubernetes/kubernetes.md deleted file mode 100644 index d942a5ef0f93..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/kubernetes.md +++ /dev/null @@ -1,13 +0,0 @@ -# Kubernetes - -Most high-level container runtimes implement Kubernetes' CRI (Container Runtime Interface) spec so that they can be managed by Kubernetes tools. That means you can use Kubernetes tools to manage the WebAssembly app image in pods and namespaces. -Check out specific instructions for different flavors of Kubernetes setup in this chapter. - -* [Kubernetes + CRI-O](kubernetes/kubernetes-crio.md) -* [Kubernetes + containerd](kubernetes/kubernetes-containerd.md) -* [KinD](kubernetes/kind.md) -* [KubeEdge](kubernetes/kubeedge.md) -* [SuperEdge](kubernetes/superedge.md) -* [OpenYurt](kubernetes/openyurt.md) -* [Knative](kubernetes/knative.md) -* [Kwasm](kubernetes/kwasm.md) diff --git a/docs/book/en/src/use_cases/kubernetes/kubernetes/kind.md b/docs/book/en/src/use_cases/kubernetes/kubernetes/kind.md deleted file mode 100644 index e68d09a1ffb5..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/kubernetes/kind.md +++ /dev/null @@ -1,3 +0,0 @@ -# Kubernetes in Docker (KinD) - -> This part has been moved to <https://wasmedge.org/docs/develop/deploy/kubernetes/kind>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/kubernetes/kubernetes/knative.md b/docs/book/en/src/use_cases/kubernetes/kubernetes/knative.md deleted file mode 100644 index 611c2a08cd44..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/kubernetes/knative.md +++ /dev/null @@ -1,3 +0,0 @@ -# Knative - -> This part has been moved to <https://wasmedge.org/docs/develop/deploy/kubernetes/knative>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/kubernetes/kubernetes/kubeedge.md b/docs/book/en/src/use_cases/kubernetes/kubernetes/kubeedge.md deleted file mode 100644 index 6f54b9ac57d9..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/kubernetes/kubeedge.md +++ /dev/null @@ -1,3 +0,0 @@ -# Create a crun demo for KubeEdge - -This docs has moved to <https://wasmedge.org/docs/develop/deploy/kubernetes/kubedge>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/kubernetes/kubernetes/kubernetes-containerd.md b/docs/book/en/src/use_cases/kubernetes/kubernetes/kubernetes-containerd.md deleted file mode 100644 index 65e685fbbea5..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/kubernetes/kubernetes-containerd.md +++ /dev/null @@ -1,3 +0,0 @@ -# Kubernetes + containerd - -> This part has been moved to <https://wasmedge.org/docs/develop/deploy/kubernetes/kubernetes-containerd-crun>. Please use or new docs \ No newline at end of file diff --git a/docs/book/en/src/use_cases/kubernetes/kubernetes/kubernetes-crio.md b/docs/book/en/src/use_cases/kubernetes/kubernetes/kubernetes-crio.md deleted file mode 100644 index 395891f96811..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/kubernetes/kubernetes-crio.md +++ /dev/null @@ -1,3 +0,0 @@ -# Kubernetes + CRI-O - -This doc has move to <https://wasmedge.org/docs/develop/deploy/kubernetes/kubernetes-cri-o>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/kubernetes/kubernetes/kwasm.md b/docs/book/en/src/use_cases/kubernetes/kubernetes/kwasm.md deleted file mode 100644 index 6b5152256f5d..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/kubernetes/kwasm.md +++ /dev/null @@ -1,3 +0,0 @@ -# Kwasm - -This part has been moved to <https://wasmedge.org/docs/develop/deploy/kubernetes/kwasm>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/kubernetes/kubernetes/openyurt.md b/docs/book/en/src/use_cases/kubernetes/kubernetes/openyurt.md deleted file mode 100644 index 95e4a5899542..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/kubernetes/openyurt.md +++ /dev/null @@ -1,3 +0,0 @@ -# OpenYurt + containerd + crun - -This part has been moved to <https://wasmedge.org/docs/develop/deploy/kubernetes/openyurt>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/kubernetes/kubernetes/superedge.md b/docs/book/en/src/use_cases/kubernetes/kubernetes/superedge.md deleted file mode 100644 index 0906c701d940..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/kubernetes/superedge.md +++ /dev/null @@ -1,3 +0,0 @@ -# SuperEdge - -> This part has been moved to <https://wasmedge.org/docs/develop/deploy/kubernetes/superedge>. Please use our new docs. diff --git a/docs/book/en/src/use_cases/kubernetes/quickstart.md b/docs/book/en/src/use_cases/kubernetes/quickstart.md deleted file mode 100644 index bdf5bc2f8551..000000000000 --- a/docs/book/en/src/use_cases/kubernetes/quickstart.md +++ /dev/null @@ -1,54 +0,0 @@ -# Quick start - -We have created Ubuntu-based scripts for you to quickly get started with the following combination of runtimes in a standard Kubernetes setup. - -| CRI (high level) runtime | OCI (low level) runtime | | -| --- | --- | --- | -| CRI-O | crun + WasmEdge | [Script](https://github.com/second-state/wasmedge-containers-examples/blob/main/.github/workflows/kubernetes-crio.yml) | -| containerd | crun + WasmEdge | [Script](https://github.com/second-state/wasmedge-containers-examples/blob/main/.github/workflows/kubernetes-containerd.yml) | - -## CRI-O and crun - -You can use the CRI-O [install.sh](https://github.com/second-state/wasmedge-containers-examples/blob/main/crio/install.sh) script to install CRI-O and `crun` on Ubuntu 20.04. - -```bash -wget -qO- https://raw.githubusercontent.com/second-state/wasmedge-containers-examples/main/crio/install.sh | bash -``` - -Next, install Kubernetes using the [following script](https://github.com/second-state/wasmedge-containers-examples/blob/main/kubernetes_crio/install.sh). - -```bash -wget -qO- https://raw.githubusercontent.com/second-state/wasmedge-containers-examples/main/kubernetes_crio/install.sh | bash -``` - -The [simple_wasi_application.sh](https://github.com/second-state/wasmedge-containers-examples/blob/main/kubernetes_crio/simple_wasi_application.sh) script shows how to pull [a WebAssembly application](demo/wasi.md) from Docker Hub, and then run it as a containerized application in Kubernetes. - -```bash -wget -qO- https://raw.githubusercontent.com/second-state/wasmedge-containers-examples/main/kubernetes_crio/simple_wasi_application.sh | bash -``` - -You should see results from the WebAssembly program printed in the console log. [Here is an example](https://github.com/second-state/wasmedge-containers-examples/runs/4186005677?check_suite_focus=true#step:6:3007). - -## containerd and crun - -You can use the containerd [install.sh](https://github.com/second-state/wasmedge-containers-examples/blob/main/containerd/install.sh) script to install `containerd` and `crun` on Ubuntu 20.04. - -```bash -wget -qO- https://raw.githubusercontent.com/second-state/wasmedge-containers-examples/main/containerd/install.sh | bash -``` - -Next, install Kubernetes using the [following script](https://github.com/second-state/wasmedge-containers-examples/blob/main/kubernetes_containerd/install.sh). - -```bash -wget -qO- https://raw.githubusercontent.com/second-state/wasmedge-containers-examples/main/kubernetes_containerd/install.sh | bash -``` - -The [simple_wasi_application.sh](https://github.com/second-state/wasmedge-containers-examples/blob/main/kubernetes_containerd/simple_wasi_application.sh) script shows how to pull [a WebAssembly application](demo/wasi.md) from Docker Hub, and then run it as a containerized application in Kubernetes. - -```bash -wget -qO- https://raw.githubusercontent.com/second-state/wasmedge-containers-examples/main/kubernetes_containerd/simple_wasi_application.sh | bash -``` - -You should see results from the WebAssembly program printed in the console log. [Here is an example](https://github.com/second-state/wasmedge-containers-examples/runs/4577789181?check_suite_focus=true#step:6:3010). - -Read on to the rest of this chapter to learn how exactly those runtimes are configured. diff --git a/docs/book/en/src/use_cases/microservice.md b/docs/book/en/src/use_cases/microservice.md deleted file mode 100644 index 8bf56d9f0649..000000000000 --- a/docs/book/en/src/use_cases/microservice.md +++ /dev/null @@ -1,26 +0,0 @@ -# Microservices - -The edge cloud can run application logic microservices very close to the client device. - -* The microservices could be stateless computational tasks, such as [AI inference](../write_wasm/rust/tensorflow.md) and [stream data analysis](frameworks/app/yomo.md), which offload computation from the client. -* The microservices could also [interact with data cache services](https://github.com/second-state/wasmedge-anna-rs) that sync with backend databases. - -The edge cloud has advantages such as low latency, high security, and high performance. Operationally, WasmEdge can be embedded into cloud-native infrastructure via its SDKs in [C](../sdk/c.md), [Go](../sdk/go.md) and [Rust](../sdk/rust.md). It is also an OCI compliant runtime that can be directly [managed by container tools](kubernetes/cri.md) as a lightweight and high-performance alternative to Linux containers. The following application frameworks have been tested to work with WasmEdge-based microservices. - -## Dapr (Distributed Application Runtime) - -* [Tutorial](frameworks/mesh/dapr.md) -* [Code template](https://github.com/second-state/dapr-wasm) - -## Service mesh (work in progress) - -* Linkerd -* MOSN -* Envoy - -## Orchestration and management - -* [Kubernetes](kubernetes.md) -* [KubeEdge](kubernetes/kubernetes/kubeedge.md) -* [SuperEdge](kubernetes/kubernetes/superedge.md) -* [OpenYurt](kubernetes/kubernetes/openyurt.md) diff --git a/docs/book/en/src/use_cases/server_side_render.md b/docs/book/en/src/use_cases/server_side_render.md deleted file mode 100644 index e87dba18274d..000000000000 --- a/docs/book/en/src/use_cases/server_side_render.md +++ /dev/null @@ -1,19 +0,0 @@ -# Server Side Rendering Modern Web UI - -Traditional web applications follows the client-server model. In the past era of application servers, the entire UI is dynamically generated from the server. The browser is simply a thin client that displays the rendered web pages at real time. However, as the browser becomes more capable and sophisticated, the client can now take on more workload to improve application UX, performance, and security. - -That gives rise to the era of Jamstack. There is now a clear separation between frontend and backend services. The frontend is a static web site (HTML + JavaScript + WebAssembly) generated from UI frameworks such as React.js, Vue.js, Yew or Percy, and the backend consists of microservices. Yet, as Jamstack gains popularity, the diversity of clients (both browsers and apps) makes it very difficult to achieve great performance across all use cases. - -The solution is server-side rendering (SSR). That is to have edge servers run the "client side" UI code (ie the React generated JavaScript OR Percy generated WebAssembly), and send back the rendered HTML DOM objects to the browser. In this case, the edge server must execute the exact same code (i.e. [JavaScript](../write_wasm/js.md) and WebAssembly) as the browser to render the UI. That is called isomorphic Jamstack applications. The WasmEdge runtime provides a lightweight, high performance, OCI complaint, and polyglot container to run all kinds of SSR functions on edge servers. - -* [React JS SSR function](../write_wasm/js/ssr.md) -* Vue JS SSR function (coming soon) -* Yew Rust compiled to WebAssembly SSR function (coming soon) -* [Percy Rust compiled to WebAssembly SSR function](../write_wasm/rust/ssr.md) - -We also exploring ways to render more complex UI and interactions on WasmEdge-based edge servers, and then stream the rendered results to the client application. Potential examples include - -* Render Unity3D animations on the edge server (based on [WebAssembly rendering of Unity3D](https://docs.unity3d.com/2020.1/Documentation/Manual/webgl-gettingstarted.html)) -* Render interactive video (generated from AI) on the edge server - -Of course, the edge cloud could grow well beyond SSR for UI components. It could also host high-performance microservices for business logic and serverless functions. Read on to the next chapter. diff --git a/docs/book/en/src/use_cases/serverless_faas.md b/docs/book/en/src/use_cases/serverless_faas.md deleted file mode 100644 index eff07d7f6046..000000000000 --- a/docs/book/en/src/use_cases/serverless_faas.md +++ /dev/null @@ -1,27 +0,0 @@ -# Serverless Function-As-A-Service in Public Clouds - -WasmEdge works with existing serverless or Jamstack platforms to provide a high-performance, portable and secure runtime for functions. It offers significant benefits even when it runs inside Docker or microVMs on those platforms. - -## AWS Lambda - -* [Tutorial](https://www.cncf.io/blog/2021/08/25/webassembly-serverless-functions-in-aws-lambda/) -* [Code template](https://github.com/second-state/aws-lambda-wasm-runtime) - -## Tencent Serverless Functions - -* [Tutorial in Chinese](https://my.oschina.net/u/4532842/blog/5172639) -* [Code template](https://github.com/second-state/tencent-scf-wasm-runtime) - -## Vercel Serverless Functions - -* [Tutorial](https://www.secondstate.io/articles/vercel-wasmedge-webassembly-rust/) -* [Code template](https://github.com/second-state/vercel-wasm-runtime) - -## Netlify Functions - -* [Tutorial](https://www.secondstate.io/articles/netlify-wasmedge-webassembly-rust-serverless/) -* [Code template](https://github.com/second-state/netlify-wasm-runtime) - -## Second State Functions - -* [Tutorials](https://www.secondstate.io/faas/) diff --git a/docs/book/en/src/use_cases/serverless_saas.md b/docs/book/en/src/use_cases/serverless_saas.md deleted file mode 100644 index e5dce5554133..000000000000 --- a/docs/book/en/src/use_cases/serverless_saas.md +++ /dev/null @@ -1,18 +0,0 @@ -# Serverless Software-As-A-Service Functions - -WasmEdge can support customized SaaS extensions or applications using serverless functions instead of traditional network APIs. That dramatically improves SaaS users' and developers' productivity. - -* WasmEdge could be embedded into SaaS products to execute user-defined functions. In this scenario, the WasmEdge function API replaces the SaaS web API. The embedded WasmEdge functions are much faster, safer, and easier to use than RPC functions over the web. -* Edge servers could provide WasmEdge-based containers to interact with existing SaaS or PaaS APIs without requiring the user to run his own servers (eg callback servers). The serverless API services can be co-located in the same networks as the SaaS to provide optimal performance and security. - -The examples below showcase how WasmEdge-based serverless functions connect together SaaS APIs from different services, and process data flows across those SaaS APIs according each user's business logic. - -## Slack - -* [Build a serverless chatbot for Slack](http://reactor.secondstate.info/en/docs/user_guideline.html) - -## Lark - -It is also known as `飞书` aka the Chinese Slack. It is created by Byte Dance, the parent company of Tiktok. - -* [Build a serverless chatbot for Lark](http://reactor.secondstate.info/en/docs/user_guideline.html) diff --git a/docs/book/en/src/use_cases/smart_device.md b/docs/book/en/src/use_cases/smart_device.md deleted file mode 100644 index 4959adf33996..000000000000 --- a/docs/book/en/src/use_cases/smart_device.md +++ /dev/null @@ -1,10 +0,0 @@ -# WasmEdge On Smart Devices - -Smart device apps could embed WasmEdge as a middleware runtime to render interactive content on the UI, connect to native device drivers, and access specialized hardware features (i.e, the GPU for AI inference). The benefits of the WasmEdge runtime over native-compiled machine code include security, safety, portability, manageability, OTA upgradability, and developer productivity. WasmEdge runs on the following device OSes. - -* [Android](../contribute/build_from_src/android.md) -* [OpenHarmony](../contribute/build_from_src/openharmony.md) -* [Raspberry Pi](../contribute/build_from_src/raspberrypi.md) -* [The seL4 RTOS](../contribute/build_from_src/sel4.md) - -With WasmEdge on both the device and the edge server, we can support [isomorphic Server-Side Rendering (SSR)](server_side_render.md) and [microservices](microservice.md) for rich-client mobile applications that is both portable and upgradable. diff --git a/docs/book/en/src/write_wasm.md b/docs/book/en/src/write_wasm.md deleted file mode 100644 index 96f0ccaaad81..000000000000 --- a/docs/book/en/src/write_wasm.md +++ /dev/null @@ -1,3 +0,0 @@ -# Write a WebAssembly Application - -> This part has been moved to <https://wasmedge.org/docs/develop/overview>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/c.md b/docs/book/en/src/write_wasm/c.md deleted file mode 100644 index 01a24173cc90..000000000000 --- a/docs/book/en/src/write_wasm/c.md +++ /dev/null @@ -1,3 +0,0 @@ -# C - -> This part has been moved to <https://wasmedge.org/docs/develop/c/simd>. Please use our new docs diff --git a/docs/book/en/src/write_wasm/c/quickstart.md b/docs/book/en/src/write_wasm/c/quickstart.md deleted file mode 100644 index bac6edde96de..000000000000 --- a/docs/book/en/src/write_wasm/c/quickstart.md +++ /dev/null @@ -1,3 +0,0 @@ -# Getting Started - -> This part has been moved to <https://wasmedge.org/docs/develop/c/hello_world>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/c/simd.md b/docs/book/en/src/write_wasm/c/simd.md deleted file mode 100644 index 982377d360bc..000000000000 --- a/docs/book/en/src/write_wasm/c/simd.md +++ /dev/null @@ -1,3 +0,0 @@ -# WebAssembly SIMD Example in C - -> This part has been moved to <https://wasmedge.org/docs/develop/c/simd>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/go.md b/docs/book/en/src/write_wasm/go.md deleted file mode 100644 index 8d18f410ab02..000000000000 --- a/docs/book/en/src/write_wasm/go.md +++ /dev/null @@ -1,3 +0,0 @@ -# Go - -> This part has been moved to <https://wasmedge.org/docs/develop/go/hello_world>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/js.md b/docs/book/en/src/write_wasm/js.md deleted file mode 100644 index 063f289dc09a..000000000000 --- a/docs/book/en/src/write_wasm/js.md +++ /dev/null @@ -1,3 +0,0 @@ -# JavaScript - -> This part has been moved to <https://wasmedge.org/docs/develop/javascript/intro>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/js/es6.md b/docs/book/en/src/write_wasm/js/es6.md deleted file mode 100644 index 6fb1539d85c6..000000000000 --- a/docs/book/en/src/write_wasm/js/es6.md +++ /dev/null @@ -1,3 +0,0 @@ -# ES6 module support - -> This part has been moved to <https://wasmedge.org/docs/develop/javascript/es6>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/js/modules.md b/docs/book/en/src/write_wasm/js/modules.md deleted file mode 100644 index 08419dc30e35..000000000000 --- a/docs/book/en/src/write_wasm/js/modules.md +++ /dev/null @@ -1,3 +0,0 @@ -# System modules - -> This part has been moved to <https://wasmedge.org/docs/develop/javascript/modules>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/js/networking.md b/docs/book/en/src/write_wasm/js/networking.md deleted file mode 100644 index 44648e162f12..000000000000 --- a/docs/book/en/src/write_wasm/js/networking.md +++ /dev/null @@ -1,3 +0,0 @@ -# HTTP and networking apps - -> This part has been moved to <https://wasmedge.org/docs/develop/javascript/networking>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/js/nodejs.md b/docs/book/en/src/write_wasm/js/nodejs.md deleted file mode 100644 index a74938c270e1..000000000000 --- a/docs/book/en/src/write_wasm/js/nodejs.md +++ /dev/null @@ -1,3 +0,0 @@ -# Node.js support - -> This part has been moved to <https://wasmedge.org/docs/develop/javascript/nodejs>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/js/npm.md b/docs/book/en/src/write_wasm/js/npm.md deleted file mode 100644 index aa8885f1cc9b..000000000000 --- a/docs/book/en/src/write_wasm/js/npm.md +++ /dev/null @@ -1,3 +0,0 @@ -# NodeJS and NPM module - -> This part has been moved to <https://wasmedge.org/docs/develop/javascript/npm>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/js/quickstart.md b/docs/book/en/src/write_wasm/js/quickstart.md deleted file mode 100644 index 0d8e4496a9d8..000000000000 --- a/docs/book/en/src/write_wasm/js/quickstart.md +++ /dev/null @@ -1,3 +0,0 @@ -# Quick Start with JavaScript on WasmEdge - -> This part has been moved to <https://wasmedge.org/docs/develop/javascript/hello_world>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/js/rust.md b/docs/book/en/src/write_wasm/js/rust.md deleted file mode 100644 index c75d75f96565..000000000000 --- a/docs/book/en/src/write_wasm/js/rust.md +++ /dev/null @@ -1,3 +0,0 @@ -# Use Rust to implement JS API - -> This part has been moved to <https://wasmedge.org/docs/develop/javascript/rust>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/js/ssr.md b/docs/book/en/src/write_wasm/js/ssr.md deleted file mode 100644 index 8de70567b7dc..000000000000 --- a/docs/book/en/src/write_wasm/js/ssr.md +++ /dev/null @@ -1,3 +0,0 @@ -# React SSR - -> This part has been moved to <https://wasmedge.org/docs/develop/javascript/ssr>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/js/tensorflow.md b/docs/book/en/src/write_wasm/js/tensorflow.md deleted file mode 100644 index c25191aa499d..000000000000 --- a/docs/book/en/src/write_wasm/js/tensorflow.md +++ /dev/null @@ -1,3 +0,0 @@ -# TensorFlow - -> This part has been moved to <https://wasmedge.org/docs/develop/javascript/tensorflow>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/kotlin.md b/docs/book/en/src/write_wasm/kotlin.md deleted file mode 100644 index c60a8333b8dd..000000000000 --- a/docs/book/en/src/write_wasm/kotlin.md +++ /dev/null @@ -1,3 +0,0 @@ -# Kotlin - -Check out how to [compile Kotlin programs to WebAssembly](https://blog.jdriven.com/2021/04/running-kotlin-in-the-browser-with-wasm/) diff --git a/docs/book/en/src/write_wasm/python.md b/docs/book/en/src/write_wasm/python.md deleted file mode 100644 index 034efcba4005..000000000000 --- a/docs/book/en/src/write_wasm/python.md +++ /dev/null @@ -1,3 +0,0 @@ -# Python - -> This part has been moved to <https://wasmedge.org/docs/develop/python/hello_world>. Please use our new docs \ No newline at end of file diff --git a/docs/book/en/src/write_wasm/rust.md b/docs/book/en/src/write_wasm/rust.md deleted file mode 100644 index 859e5b478734..000000000000 --- a/docs/book/en/src/write_wasm/rust.md +++ /dev/null @@ -1,3 +0,0 @@ -# Rust - -> This part has been moved to <https://wasmedge.org/docs/develop/rust/hello_world>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/rust/bindgen.md b/docs/book/en/src/write_wasm/rust/bindgen.md deleted file mode 100644 index 318c4cae7742..000000000000 --- a/docs/book/en/src/write_wasm/rust/bindgen.md +++ /dev/null @@ -1,3 +0,0 @@ -# Bindgen of Rust Functions - -> This part has been moved to <https://wasmedge.org/docs/develop/rust/bindgen>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/rust/command.md b/docs/book/en/src/write_wasm/rust/command.md deleted file mode 100644 index d20752510c3d..000000000000 --- a/docs/book/en/src/write_wasm/rust/command.md +++ /dev/null @@ -1,3 +0,0 @@ -# Command interface - -This part part has moved to <https://wasmedge.org/docs/develop/rust/command>. Please use our docs. diff --git a/docs/book/en/src/write_wasm/rust/networking-nonblocking.md b/docs/book/en/src/write_wasm/rust/networking-nonblocking.md deleted file mode 100644 index 151ce90d12bd..000000000000 --- a/docs/book/en/src/write_wasm/rust/networking-nonblocking.md +++ /dev/null @@ -1,7 +0,0 @@ -# Non-blocking Networking Sockets - -> This part has been moved to - -1. Client example: <https://wasmedge.org/docs/develop/rust/socket_networking/client> - -2. Server example: <https://wasmedge.org/docs/develop/rust/socket_networking/server/> diff --git a/docs/book/en/src/write_wasm/rust/networking.md b/docs/book/en/src/write_wasm/rust/networking.md deleted file mode 100644 index a9909149b1ac..000000000000 --- a/docs/book/en/src/write_wasm/rust/networking.md +++ /dev/null @@ -1,6 +0,0 @@ -# Simple Networking Sockets - -> This part has been moved to - -1. Client example: <https://wasmedge.org/docs/develop/rust/socket_networking/client> -2. Server example: <https://wasmedge.org/docs/develop/rust/socket_networking/server/> diff --git a/docs/book/en/src/write_wasm/rust/ssr.md b/docs/book/en/src/write_wasm/rust/ssr.md deleted file mode 100644 index 3e9f6b48ab43..000000000000 --- a/docs/book/en/src/write_wasm/rust/ssr.md +++ /dev/null @@ -1,3 +0,0 @@ -# Server-side rendering - -> This part has been moved to <https://wasmedge.org/docs/develop/rust/ssr>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/rust/tensorflow.md b/docs/book/en/src/write_wasm/rust/tensorflow.md deleted file mode 100644 index 75d359b1f73f..000000000000 --- a/docs/book/en/src/write_wasm/rust/tensorflow.md +++ /dev/null @@ -1,3 +0,0 @@ -# Tensorflow - -> This part has been moved to <https://wasmedge.org/docs/develop/rust/ai_inference/tensorflow_lite>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/rust/wasi.md b/docs/book/en/src/write_wasm/rust/wasi.md deleted file mode 100644 index 403a3159da2d..000000000000 --- a/docs/book/en/src/write_wasm/rust/wasi.md +++ /dev/null @@ -1,3 +0,0 @@ -# Access OS services - -> This part has been moved to <https://wasmedge.org/docs/develop/rust/os>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/rust/wasicrypto.md b/docs/book/en/src/write_wasm/rust/wasicrypto.md deleted file mode 100644 index 8907ce7d5803..000000000000 --- a/docs/book/en/src/write_wasm/rust/wasicrypto.md +++ /dev/null @@ -1,3 +0,0 @@ -# Crypto for WASI - -> This part has been moved to <https://wasmedge.org/docs/develop/rust/wasicrypto>. Please use our new docs. diff --git a/docs/book/en/src/write_wasm/rust/wasinn.md b/docs/book/en/src/write_wasm/rust/wasinn.md deleted file mode 100644 index 77b940fd1704..000000000000 --- a/docs/book/en/src/write_wasm/rust/wasinn.md +++ /dev/null @@ -1,9 +0,0 @@ -# Neural Network for WASI - -This Part has been moved to - -1. Pytorch: <https://wasmedge.org/docs/develop/rust/wasinn/pytorch> -2. OpenVINO: <https://wasmedge.org/docs/develop/rust/wasinn/openvino> -3. TensorFlow-Lite: <https://wasmedge.org/docs/develop/rust/wasinn/tensorflow_lite> - -Please use our new docs. diff --git a/docs/book/en/src/write_wasm/swift.md b/docs/book/en/src/write_wasm/swift.md deleted file mode 100644 index 6c855546f1fc..000000000000 --- a/docs/book/en/src/write_wasm/swift.md +++ /dev/null @@ -1,3 +0,0 @@ -# Swift - -The [swiftwasm](https://swiftwasm.org/) project compiles Swift source code to WebAssembly. diff --git a/docs/book/en/theme/css/chrome.css b/docs/book/en/theme/css/chrome.css deleted file mode 100644 index b6247989a551..000000000000 --- a/docs/book/en/theme/css/chrome.css +++ /dev/null @@ -1,543 +0,0 @@ -/* CSS for UI elements (a.k.a. chrome) */ - -@import 'variables.css'; - -::-webkit-scrollbar { - background: var(--bg); -} -::-webkit-scrollbar-thumb { - background: var(--scrollbar); -} -html { - scrollbar-color: var(--scrollbar) var(--bg); -} -#searchresults a, -.content a:link, -a:visited, -a > .hljs { - color: var(--links); -} - -/* Menu Bar */ - -#menu-bar, -#menu-bar-hover-placeholder { - z-index: 101; - margin: auto calc(0px - var(--page-padding)); -} -#menu-bar { - position: relative; - display: flex; - flex-wrap: wrap; - background-color: var(--bg); - border-bottom-color: var(--bg); - border-bottom-width: 1px; - border-bottom-style: solid; -} -#menu-bar.sticky, -.js #menu-bar-hover-placeholder:hover + #menu-bar, -.js #menu-bar:hover, -.js.sidebar-visible #menu-bar { - position: -webkit-sticky; - position: sticky; - top: 0 !important; -} -#menu-bar-hover-placeholder { - position: sticky; - position: -webkit-sticky; - top: 0; - height: var(--menu-bar-height); -} -#menu-bar.bordered { - border-bottom-color: var(--table-border-color); -} -#menu-bar i, #menu-bar .icon-button { - position: relative; - padding: 0 8px; - z-index: 10; - line-height: var(--menu-bar-height); - cursor: pointer; - transition: color 0.5s; -} -@media only screen and (max-width: 420px) { - #menu-bar i, #menu-bar .icon-button { - padding: 0 5px; - } -} - -.icon-button { - border: none; - background: none; - padding: 0; - color: inherit; -} -.icon-button i { - margin: 0; -} - -.right-buttons { - margin: 0 15px; -} -.right-buttons a { - text-decoration: none; -} - -.left-buttons { - display: flex; - margin: 0 5px; -} -.no-js .left-buttons { - display: none; -} - -.menu-title { - display: inline-block; - font-weight: 200; - font-size: 2.4rem; - line-height: var(--menu-bar-height); - text-align: center; - margin: 0; - flex: 1; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.js .menu-title { - cursor: pointer; -} - -.menu-bar, -.menu-bar:visited, -.nav-chapters, -.nav-chapters:visited, -.mobile-nav-chapters, -.mobile-nav-chapters:visited, -.menu-bar .icon-button, -.menu-bar a i { - color: var(--icons); -} - -.menu-bar i:hover, -.menu-bar .icon-button:hover, -.nav-chapters:hover, -.mobile-nav-chapters i:hover { - color: var(--icons-hover); -} - -/* Nav Icons */ - -.nav-chapters { - font-size: 2.5em; - text-align: center; - text-decoration: none; - - position: fixed; - top: 0; - bottom: 0; - margin: 0; - max-width: 150px; - min-width: 90px; - - display: flex; - justify-content: center; - align-content: center; - flex-direction: column; - - transition: color 0.5s, background-color 0.5s; -} - -.nav-chapters:hover { - text-decoration: none; - background-color: var(--theme-hover); - transition: background-color 0.15s, color 0.15s; -} - -.nav-wrapper { - margin-top: 50px; - display: none; -} - -.mobile-nav-chapters { - font-size: 2.5em; - text-align: center; - text-decoration: none; - width: 90px; - border-radius: 5px; - background-color: var(--sidebar-bg); -} - -.previous { - float: left; -} - -.next { - float: right; - right: var(--page-padding); -} - -@media only screen and (max-width: 1080px) { - .nav-wide-wrapper { display: none; } - .nav-wrapper { display: block; } -} - -@media only screen and (max-width: 1380px) { - .sidebar-visible .nav-wide-wrapper { display: none; } - .sidebar-visible .nav-wrapper { display: block; } -} - -/* Inline code */ - -:not(pre) > .hljs { - display: inline; - padding: 0.1em 0.3em; - border-radius: 3px; -} - -:not(pre):not(a) > .hljs { - color: var(--inline-code-color); - overflow-x: initial; -} - -a:hover > .hljs { - text-decoration: underline; -} - -pre { - position: relative; -} -pre > .buttons { - position: absolute; - z-index: 100; - right: 0px; - top: 2px; - margin: 0px; - padding: 2px 0px; - - color: var(--sidebar-fg); - cursor: pointer; - visibility: hidden; - opacity: 0; - transition: visibility 0.1s linear, opacity 0.1s linear; -} -pre:hover > .buttons { - visibility: visible; - opacity: 1 -} -pre > .buttons :hover { - color: var(--sidebar-active); - border-color: var(--icons-hover); - background-color: var(--theme-hover); -} -pre > .buttons i { - margin-left: 8px; -} -pre > .buttons button { - cursor: inherit; - margin: 0px 5px; - padding: 3px 5px; - font-size: 14px; - - border-style: solid; - border-width: 1px; - border-radius: 4px; - border-color: var(--icons); - background-color: var(--theme-popup-bg); - transition: 100ms; - transition-property: color,border-color,background-color; - color: var(--icons); -} -@media (pointer: coarse) { - pre > .buttons button { - /* On mobile, make it easier to tap buttons. */ - padding: 0.3rem 1rem; - } -} -pre > code { - padding: 1rem; -} - -/* FIXME: ACE editors overlap their buttons because ACE does absolute - positioning within the code block which breaks padding. The only solution I - can think of is to move the padding to the outer pre tag (or insert a div - wrapper), but that would require fixing a whole bunch of CSS rules. -*/ -.hljs.ace_editor { - padding: 0rem 0rem; -} - -pre > .result { - margin-top: 10px; -} - -/* Search */ - -#searchresults a { - text-decoration: none; -} - -mark { - border-radius: 2px; - padding: 0 3px 1px 3px; - margin: 0 -3px -1px -3px; - background-color: var(--search-mark-bg); - transition: background-color 300ms linear; - cursor: pointer; -} - -mark.fade-out { - background-color: rgba(0,0,0,0) !important; - cursor: auto; -} - -.searchbar-outer { - margin-left: auto; - margin-right: auto; - max-width: var(--content-max-width); -} - -#searchbar { - width: 100%; - margin: 5px auto 0px auto; - padding: 10px 16px; - transition: box-shadow 300ms ease-in-out; - border: 1px solid var(--searchbar-border-color); - border-radius: 3px; - background-color: var(--searchbar-bg); - color: var(--searchbar-fg); -} -#searchbar:focus, -#searchbar.active { - box-shadow: 0 0 3px var(--searchbar-shadow-color); -} - -.searchresults-header { - font-weight: bold; - font-size: 1em; - padding: 18px 0 0 5px; - color: var(--searchresults-header-fg); -} - -.searchresults-outer { - margin-left: auto; - margin-right: auto; - max-width: var(--content-max-width); - border-bottom: 1px dashed var(--searchresults-border-color); -} - -ul#searchresults { - list-style: none; - padding-left: 20px; -} -ul#searchresults li { - margin: 10px 0px; - padding: 2px; - border-radius: 2px; -} -ul#searchresults li.focus { - background-color: var(--searchresults-li-bg); -} -ul#searchresults span.teaser { - display: block; - clear: both; - margin: 5px 0 0 20px; - font-size: 0.8em; -} -ul#searchresults span.teaser em { - font-weight: bold; - font-style: normal; -} - -/* Sidebar */ - -.sidebar { - position: fixed; - left: 0; - top: 0; - bottom: 0; - width: var(--sidebar-width); - font-size: 0.875em; - box-sizing: border-box; - -webkit-overflow-scrolling: touch; - overscroll-behavior-y: contain; - background-color: var(--sidebar-bg); - color: var(--sidebar-fg); -} -.sidebar-resizing { - -moz-user-select: none; - -webkit-user-select: none; - -ms-user-select: none; - user-select: none; -} -.js:not(.sidebar-resizing) .sidebar { - transition: transform 0.3s; /* Animation: slide away */ -} -.sidebar code { - line-height: 2em; -} -.sidebar .sidebar-scrollbox { - overflow-y: auto; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - padding: 10px 10px; -} -.sidebar .sidebar-resize-handle { - position: absolute; - cursor: col-resize; - width: 0; - right: 0; - top: 0; - bottom: 0; -} -.js .sidebar .sidebar-resize-handle { - cursor: col-resize; - width: 5px; -} -.sidebar-hidden .sidebar { - transform: translateX(calc(0px - var(--sidebar-width))); -} -.sidebar::-webkit-scrollbar { - background: var(--sidebar-bg); -} -.sidebar::-webkit-scrollbar-thumb { - background: var(--scrollbar); -} - -.sidebar-visible .page-wrapper { - transform: translateX(var(--sidebar-width)); -} -@media only screen and (min-width: 620px) { - #menu-bar i, #menu-bar .icon-button { - font-size: 2rem; - } - #menu-bar .right-buttons i { - font-size: 2.4rem; - } - .menu-title { - font-size: 3.4rem; - } - .sidebar-visible .page-wrapper { - transform: none; - margin-left: var(--sidebar-width); - } -} - -.chapter { - list-style: none outside none; - padding-left: 0; - line-height: 2.2em; -} - -.chapter ol { - width: 100%; -} - -.chapter li { - display: flex; - color: var(--sidebar-non-existant); -} -.chapter li a { - display: block; - padding: 0; - text-decoration: none; - color: var(--sidebar-fg); -} - -.chapter li a:hover { - color: var(--sidebar-active); -} - -.chapter li a.active { - color: var(--sidebar-active); -} - -.chapter li > a.toggle { - cursor: pointer; - display: block; - margin-left: auto; - padding: 0 10px; - user-select: none; - opacity: 0.68; -} - -.chapter li > a.toggle div { - transition: transform 0.5s; -} - -/* collapse the section */ -.chapter li:not(.expanded) + li > ol { - display: none; -} - -.chapter li.chapter-item { - line-height: 1.5em; - margin-top: 0.6em; -} - -.chapter li.expanded > a.toggle div { - transform: rotate(90deg); -} - -.spacer { - width: 100%; - height: 3px; - margin: 5px 0px; -} -.chapter .spacer { - background-color: var(--sidebar-spacer); -} - -@media (-moz-touch-enabled: 1), (pointer: coarse) { - .chapter li a { padding: 5px 0; } - .spacer { margin: 10px 0; } -} - -.section { - list-style: none outside none; - padding-left: 20px; - line-height: 1.9em; -} - -/* Theme Menu Popup */ - -.theme-popup { - position: absolute; - left: 10px; - top: var(--menu-bar-height); - z-index: 1000; - border-radius: 4px; - font-size: 0.7em; - color: var(--fg); - background: var(--theme-popup-bg); - border: 1px solid var(--theme-popup-border); - margin: 0; - padding: 0; - list-style: none; - display: none; -} -.theme-popup .default { - color: var(--icons); -} -.theme-popup .theme { - width: 100%; - border: 0; - margin: 0; - padding: 2px 10px; - line-height: 25px; - white-space: nowrap; - text-align: left; - cursor: pointer; - color: inherit; - background: inherit; - font-size: inherit; -} -.theme-popup .theme:hover { - background-color: var(--theme-hover); -} -.theme-popup .theme:hover:first-child, -.theme-popup .theme:hover:last-child { - border-top-left-radius: inherit; - border-top-right-radius: inherit; -} diff --git a/docs/book/en/theme/css/general.css b/docs/book/en/theme/css/general.css deleted file mode 100644 index cf8f99fcb00f..000000000000 --- a/docs/book/en/theme/css/general.css +++ /dev/null @@ -1,200 +0,0 @@ -/* Base styles and content styles */ - -@import 'variables.css'; - -:root { - /* Browser default font-size is 16px, this way 1 rem = 10px */ - font-size: 62.5%; -} - -html { - font-family: "Open Sans", sans-serif; - color: var(--fg); - background-color: var(--bg); - text-size-adjust: none; - -webkit-text-size-adjust: none; -} - -body { - margin: 0; - font-size: 1.6rem; - overflow-x: hidden; -} - -code { - font-family: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace !important; - font-size: 0.875em; /* please adjust the ace font size accordingly in editor.js */ -} - -/* make long words/inline code not x overflow */ -main { - overflow-wrap: break-word; -} - -/* make wide tables scroll if they overflow */ -.table-wrapper { - overflow-x: auto; -} - -/* Don't change font size in headers. */ -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - font-size: unset; -} - -.left { float: left; } -.right { float: right; } -.boring { opacity: 0.6; } -.hide-boring .boring { display: none; } -.hidden { display: none !important; } - -h2, h3 { margin-top: 2.5em; } -h4, h5 { margin-top: 2em; } - -.header + .header h3, -.header + .header h4, -.header + .header h5 { - margin-top: 1em; -} - -h1:target::before, -h2:target::before, -h3:target::before, -h4:target::before, -h5:target::before, -h6:target::before { - display: inline-block; - content: "»"; - margin-left: -30px; - width: 30px; -} - -/* This is broken on Safari as of version 14, but is fixed - in Safari Technology Preview 117 which I think will be Safari 14.2. - https://bugs.webkit.org/show_bug.cgi?id=218076 -*/ -:target { - scroll-margin-top: calc(var(--menu-bar-height) + 0.5em); -} - -.page { - outline: 0; - padding: 0 var(--page-padding); - margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */ -} -.page-wrapper { - box-sizing: border-box; -} -.js:not(.sidebar-resizing) .page-wrapper { - transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */ -} - -@media only screen and (max-width: 1080px) { - .content { - padding: 0 5px 50px 5px; - } -} -@media only screen and (min-width: 1080px) { - .content { - padding: 0 95px 50px 95px; - } -} -.content { - overflow-y: auto; -} -.content main { - margin-left: auto; - margin-right: auto; - max-width: var(--content-max-width); -} -.content p { line-height: 1.45em; } -.content ol { line-height: 1.45em; } -.content ul { line-height: 1.45em; } -.content a { text-decoration: none; } -.content a:hover { text-decoration: underline; } -.content img, .content video { max-width: 100%; } -.content .header:link, -.content .header:visited { - color: var(--fg); -} -.content .header:link, -.content .header:visited:hover { - text-decoration: none; -} - -table { - margin: 0 auto; - border-collapse: collapse; -} -table td { - padding: 3px 20px; - border: 1px var(--table-border-color) solid; -} -table thead { - background: var(--table-header-bg); -} -table thead td { - font-weight: 700; - border: none; -} -table thead th { - padding: 3px 20px; -} -table thead tr { - border: 1px var(--table-header-bg) solid; -} -/* Alternate background colors for rows */ -table tbody tr:nth-child(2n) { - background: var(--table-alternate-bg); -} - - -blockquote { - margin: 20px 0; - padding: 0 20px; - color: var(--fg); - background-color: var(--quote-bg); - border-top: .1em solid var(--quote-border); - border-bottom: .1em solid var(--quote-border); -} - - -:not(.footnote-definition) + .footnote-definition, -.footnote-definition + :not(.footnote-definition) { - margin-top: 2em; -} -.footnote-definition { - font-size: 0.9em; - margin: 0.5em 0; -} -.footnote-definition p { - display: inline; -} - -.tooltiptext { - position: absolute; - visibility: hidden; - color: #fff; - background-color: #333; - transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */ - left: -8px; /* Half of the width of the icon */ - top: -35px; - font-size: 0.8em; - text-align: center; - border-radius: 6px; - padding: 5px 8px; - margin: 5px; - z-index: 1000; -} -.tooltipped .tooltiptext { - visibility: visible; -} - -.chapter li.part-title { - color: var(--sidebar-fg); - margin: 5px 0px; - font-weight: bold; -} - -.result-no-output { - font-style: italic; -} diff --git a/docs/book/en/theme/css/variables.css b/docs/book/en/theme/css/variables.css deleted file mode 100644 index 8682b4f6c0e2..000000000000 --- a/docs/book/en/theme/css/variables.css +++ /dev/null @@ -1,252 +0,0 @@ -/* Globals */ - -:root { - --sidebar-width: 300px; - --page-padding: 15px; - --content-max-width: 1500px; - --menu-bar-height: 50px; -} - -/* Themes */ - -.ayu { - --bg: hsl(210, 25%, 8%); - --fg: #c5c5c5; - - --sidebar-bg: #14191f; - --sidebar-fg: #c8c9db; - --sidebar-non-existant: #5c6773; - --sidebar-active: #ffb454; - --sidebar-spacer: #2d334f; - - --scrollbar: var(--sidebar-fg); - - --icons: #737480; - --icons-hover: #b7b9cc; - - --links: #0096cf; - - --inline-code-color: #ffb454; - - --theme-popup-bg: #14191f; - --theme-popup-border: #5c6773; - --theme-hover: #191f26; - - --quote-bg: hsl(226, 15%, 17%); - --quote-border: hsl(226, 15%, 22%); - - --table-border-color: hsl(210, 25%, 13%); - --table-header-bg: hsl(210, 25%, 28%); - --table-alternate-bg: hsl(210, 25%, 11%); - - --searchbar-border-color: #848484; - --searchbar-bg: #424242; - --searchbar-fg: #fff; - --searchbar-shadow-color: #d4c89f; - --searchresults-header-fg: #666; - --searchresults-border-color: #888; - --searchresults-li-bg: #252932; - --search-mark-bg: #e3b171; -} - -.coal { - --bg: hsl(200, 7%, 8%); - --fg: #98a3ad; - - --sidebar-bg: #292c2f; - --sidebar-fg: #a1adb8; - --sidebar-non-existant: #505254; - --sidebar-active: #3473ad; - --sidebar-spacer: #393939; - - --scrollbar: var(--sidebar-fg); - - --icons: #43484d; - --icons-hover: #b3c0cc; - - --links: #2b79a2; - - --inline-code-color: #c5c8c6; - - --theme-popup-bg: #141617; - --theme-popup-border: #43484d; - --theme-hover: #1f2124; - - --quote-bg: hsl(234, 21%, 18%); - --quote-border: hsl(234, 21%, 23%); - - --table-border-color: hsl(200, 7%, 13%); - --table-header-bg: hsl(200, 7%, 28%); - --table-alternate-bg: hsl(200, 7%, 11%); - - --searchbar-border-color: #aaa; - --searchbar-bg: #b7b7b7; - --searchbar-fg: #000; - --searchbar-shadow-color: #aaa; - --searchresults-header-fg: #666; - --searchresults-border-color: #98a3ad; - --searchresults-li-bg: #2b2b2f; - --search-mark-bg: #355c7d; -} - -.light { - --bg: hsl(0, 0%, 100%); - --fg: hsl(0, 0%, 0%); - - --sidebar-bg: #fafafa; - --sidebar-fg: hsl(0, 0%, 0%); - --sidebar-non-existant: #aaaaaa; - --sidebar-active: #1f1fff; - --sidebar-spacer: #f4f4f4; - - --scrollbar: #8F8F8F; - - --icons: #747474; - --icons-hover: #000000; - - --links: #20609f; - - --inline-code-color: #301900; - - --theme-popup-bg: #fafafa; - --theme-popup-border: #cccccc; - --theme-hover: #e6e6e6; - - --quote-bg: hsl(197, 37%, 96%); - --quote-border: hsl(197, 37%, 91%); - - --table-border-color: hsl(0, 0%, 95%); - --table-header-bg: hsl(0, 0%, 80%); - --table-alternate-bg: hsl(0, 0%, 97%); - - --searchbar-border-color: #aaa; - --searchbar-bg: #fafafa; - --searchbar-fg: #000; - --searchbar-shadow-color: #aaa; - --searchresults-header-fg: #666; - --searchresults-border-color: #888; - --searchresults-li-bg: #e4f2fe; - --search-mark-bg: #a2cff5; -} - -.navy { - --bg: hsl(226, 23%, 11%); - --fg: #bcbdd0; - - --sidebar-bg: #282d3f; - --sidebar-fg: #c8c9db; - --sidebar-non-existant: #505274; - --sidebar-active: #2b79a2; - --sidebar-spacer: #2d334f; - - --scrollbar: var(--sidebar-fg); - - --icons: #737480; - --icons-hover: #b7b9cc; - - --links: #2b79a2; - - --inline-code-color: #c5c8c6; - - --theme-popup-bg: #161923; - --theme-popup-border: #737480; - --theme-hover: #282e40; - - --quote-bg: hsl(226, 15%, 17%); - --quote-border: hsl(226, 15%, 22%); - - --table-border-color: hsl(226, 23%, 16%); - --table-header-bg: hsl(226, 23%, 31%); - --table-alternate-bg: hsl(226, 23%, 14%); - - --searchbar-border-color: #aaa; - --searchbar-bg: #aeaec6; - --searchbar-fg: #000; - --searchbar-shadow-color: #aaa; - --searchresults-header-fg: #5f5f71; - --searchresults-border-color: #5c5c68; - --searchresults-li-bg: #242430; - --search-mark-bg: #a2cff5; -} - -.rust { - --bg: hsl(60, 9%, 87%); - --fg: #262625; - - --sidebar-bg: #3b2e2a; - --sidebar-fg: #c8c9db; - --sidebar-non-existant: #505254; - --sidebar-active: #e69f67; - --sidebar-spacer: #45373a; - - --scrollbar: var(--sidebar-fg); - - --icons: #737480; - --icons-hover: #262625; - - --links: #2b79a2; - - --inline-code-color: #6e6b5e; - - --theme-popup-bg: #e1e1db; - --theme-popup-border: #b38f6b; - --theme-hover: #99908a; - - --quote-bg: hsl(60, 5%, 75%); - --quote-border: hsl(60, 5%, 70%); - - --table-border-color: hsl(60, 9%, 82%); - --table-header-bg: #b3a497; - --table-alternate-bg: hsl(60, 9%, 84%); - - --searchbar-border-color: #aaa; - --searchbar-bg: #fafafa; - --searchbar-fg: #000; - --searchbar-shadow-color: #aaa; - --searchresults-header-fg: #666; - --searchresults-border-color: #888; - --searchresults-li-bg: #dec2a2; - --search-mark-bg: #e69f67; -} - -@media (prefers-color-scheme: dark) { - .light.no-js { - --bg: hsl(200, 7%, 8%); - --fg: #98a3ad; - - --sidebar-bg: #292c2f; - --sidebar-fg: #a1adb8; - --sidebar-non-existant: #505254; - --sidebar-active: #3473ad; - --sidebar-spacer: #393939; - - --scrollbar: var(--sidebar-fg); - - --icons: #43484d; - --icons-hover: #b3c0cc; - - --links: #2b79a2; - - --inline-code-color: #c5c8c6; - - --theme-popup-bg: #141617; - --theme-popup-border: #43484d; - --theme-hover: #1f2124; - - --quote-bg: hsl(234, 21%, 18%); - --quote-border: hsl(234, 21%, 23%); - - --table-border-color: hsl(200, 7%, 13%); - --table-header-bg: hsl(200, 7%, 28%); - --table-alternate-bg: hsl(200, 7%, 11%); - - --searchbar-border-color: #aaa; - --searchbar-bg: #b7b7b7; - --searchbar-fg: #000; - --searchbar-shadow-color: #aaa; - --searchresults-header-fg: #666; - --searchresults-border-color: #98a3ad; - --searchresults-li-bg: #2b2b2f; - --search-mark-bg: #355c7d; - } -} \ No newline at end of file diff --git a/docs/book/en/theme/head.hbs b/docs/book/en/theme/head.hbs deleted file mode 100644 index f71b44d6aac3..000000000000 --- a/docs/book/en/theme/head.hbs +++ /dev/null @@ -1,9 +0,0 @@ -<!-- Global site tag (gtag.js) - Google Analytics --> -<script async src="https://www.googletagmanager.com/gtag/js?id=G-NGPCK7VF2L"></script> -<script> - window.dataLayer = window.dataLayer || []; - function gtag(){dataLayer.push(arguments);} - gtag('js', new Date()); - - gtag('config', 'G-NGPCK7VF2L'); -</script> diff --git a/docs/embargo-policy.md b/docs/embargo-policy.md new file mode 100644 index 000000000000..49446ac09dfc --- /dev/null +++ b/docs/embargo-policy.md @@ -0,0 +1,30 @@ +# Embargo Policy + +This policy forbids members of WasmEdge's [security contacts](./SECURITY_CONTACTS.md) and others +defined below from sharing information outside of the security contacts and this +listing without need-to-know and advance notice. + +The information members and others receive from the list defined below must: + +* not be made public, +* not be shared, +* not be hinted at +* must be kept confidential and close held + +Except with the list's explicit approval. This holds true until the public +disclosure date/time that was agreed upon by the list. + +If information is inadvertently shared beyond what is allowed by this policy, +you are REQUIRED to inform the [security contacts](./SECURITY_CONTACTS.md) of exactly what +information leaked and to whom. A retrospective will take place after the leak +so we can assess how to not make this mistake in the future. + +Violation of this policy will result in the immediate removal and subsequent +replacement of you from this list or the Security Contacts. + +## Disclosure Timeline + +WasmEdge sustains a **`90 days` disclosure timeline** to ensure we provide a +quality, tested release. On some occasions, we may need to extend this timeline +due to complexity of the problem, lack of expertise available, or other reasons. +Submitters will be notified if an extension occurs. diff --git a/docs/self-assessment.md b/docs/self-assessment.md new file mode 100644 index 000000000000..093a309c057b --- /dev/null +++ b/docs/self-assessment.md @@ -0,0 +1,257 @@ +# Self-assessment + +## Self-assessment outline + +### Table of contents + +* [Metadata](#metadata) + * [Security links](#security-links) +* [Overview](#overview) + * [Actors](#actors) + * [Actions](#actions) + * [Background](#background) + * [Goals](#goals) + * [Non-goals](#non-goals) +* [Self-assessment use](#self-assessment-use) +* [Security functions and features](#security-functions-and-features) +* [Project compliance](#project-compliance) +* [Secure development practices](#secure-development-practices) +* [Security issue resolution](#security-issue-resolution) +* [Appendix](#appendix) + +### Metadata + +A table at the top for quick reference information, later used for indexing. + +| Title | Detail | +| -- | -- | +| Assessment Stage | Incomplete. | +| Software | https://github.com/WasmEdge/WasmEdge | +| Security Provider | No. | +| Languages | C++ | +| SBOM | The software bill of materials for WasmEdge can be found at [LICENSE.spdx](https://github.com/WasmEdge/WasmEdge/blob/master/LICENSE.spdx) | + +#### Security links + +| Doc | URL | +| -- | -- | +| Security file | https://github.com/WasmEdge/WasmEdge/blob/master/SECURITY.md | +| Embargo policy | https://github.com/WasmEdge/WasmEdge/blob/master/docs/embargo-policy.md | +| Security contacts | https://github.com/WasmEdge/WasmEdge/blob/master/docs/SECURITY_CONTACTS.md | + +### Overview + +WasmEdge is a lightweight, high-performance, and extensible WebAssembly runtime. +It is the fastest Wasm VM today. Its use cases include modern web application +architectures (Isomorphic & Jamstack applications), microservices on the edge +cloud, serverless SaaS APIs, embedded functions, smart contracts, and smart +devices. + +#### Background + +The WasmEdge Runtime provides a well-defined execution sandbox for its contained +WebAssembly bytecode program. The runtime offers isolation and protection for +operating system resources (e.g., file system, sockets, environment variables, +processes) and memory space. The most important use case for WasmEdge is to +safely execute user-defined or community-contributed code as plug-ins in a +software product (e.g., SaaS, software-defined vehicles, edge nodes, or even +blockchain nodes). It enables third-party developers, vendors, suppliers, and +community members to extend and customize the software product. + +#### Actors + +- WasmEdge Tool + - Provides CLI tools for users. + - The CLI tools offer a user-friendly interface to interact with WasmEdge + functionalities. + - Includes commands for compiling, running, and debugging WebAssembly + applications. +- WasmEdge Loader + - Loads the WebAssembly bytecode file. + - Parses the loaded bytecode to Abstract Syntax Tree (AST). + - Ensures that the bytecode is correctly structured for further processing. +- WasmEdge Validator + - Validates the parsed bytecode AST to ensure it complies with WebAssembly + specifications. + - Checks for semantic correctness and security constraints. + - Ensures that the bytecode does not contain any invalid or malicious + instructions. +- WasmEdge Engine + - The actual WebAssembly runtime that executes the bytecode. + - Interprets the bytecode and performs the corresponding operations. + - Manages the execution environment, including memory, stack, and system + resources. + - Ensures efficient and secure execution of WebAssembly modules. + +#### Actions + +To execute WebAssembly code, WasmEdge follows a series of steps involving +multiple components, each with specific responsibilities. Here is a detailed +description of the process, focusing on data flow and interactions between +components: + +1. Interacting with Users (WasmEdge Tool) + - Data Input: The WasmEdge Tool provides a Command-Line Interface (CLI) for + users to interact with the WasmEdge functionalities. + - Action: Users can issue commands to compile, run, and debug WebAssembly + applications. These commands are processed by the CLI tools, which + internally utilize the Loader, Validator, and Engine components to carry + out the requested actions. + - Output: The CLI tools offer feedback to the users, such as execution + results, debug information, and error messages. + +2. Loading the WebAssembly Bytecode (WasmEdge Loader) + - Data Input: The process begins with the WasmEdge Loader component, which + receives a WebAssembly bytecode file as input. + - Action: The Loader reads and parses this bytecode file, converting it into + an Abstract Syntax Tree (AST). + - Output: The AST, which represents the structured form of the bytecode, is + produced as output for further processing. + +3. Validating the Bytecode (WasmEdge Validator) + - Data Input: The AST generated by the Loader is passed to the WasmEdge + Validator. + - Action: The Validator component checks the AST to ensure that it complies + with WebAssembly specifications. This involves verifying semantic + correctness and security constraints, ensuring there are no invalid or + malicious instructions. + - Output: If the bytecode is valid, the Validator produces a validated AST. + If invalid, it generates error messages indicating the issues found. + +4. Executing the Bytecode (WasmEdge Engine) + - Data Input: The validated AST is passed to the WasmEdge Engine, which is + the core component responsible for executing the WebAssembly code. + - Action: The Engine interprets the bytecode and performs the corresponding + operations. It manages the execution environment, including memory, stack, + and system resources. This ensures efficient and secure execution of the + WebAssembly modules. + - Output: The execution results, which could include changes in memory, + generated outputs, or responses from invoked functions. + +The interaction between these components ensures a smooth and secure execution +flow for WebAssembly programs in WasmEdge. The Loader initiates the process by +parsing the bytecode, the Validator ensures its compliance with standards, the +Engine executes the validated code, and the Tool provides a user-friendly +interface for these operations. This modular approach allows for efficient +handling and execution of WebAssembly code, making WasmEdge a robust and +high-performance WebAssembly runtime. + +#### Goals + +- Provides a well-defined execution sandbox for its contained WebAssembly + bytecode program. +- Offers isolation and protection for operating system resources and memory + space. +- Execute user-defined or community-contributed code as plugins. + +#### Non-goals + +- Compile the C++ code into WebAssembly bytecode. + +### Self-assessment use + +This self-assessment is created by the WasmEdge team to perform an internal +analysis of the project's security. It is not intended to provide a security +audit of WasmEdge, or function as an independent assessment or attestation of +WasmEdge's security health. + +This document serves to provide WasmEdge users with an initial understanding of +WasmEdge's security, where to find existing security documentation, WasmEdge +plans for security, and general overview of WasmEdge security practices, both +for development of WasmEdge as well as security of WasmEdge. + +This document provides the CNCF TAG-Security with an initial understanding of +WasmEdge to assist in a joint-assessment, necessary for projects under +incubation. Taken together, this document and the joint-assessment serve as a +cornerstone for if and when WasmEdge seeks graduation and is preparing for a +security audit. + +### Security functions and features + +- WasmEdge is a standalone WebAssembly runtime where all WebAssembly bytecode + runs independently within this execution sandbox, rather than being managed by + the OS. Access to system resources, whether files, hardware, or internet + connections, can only be achieved through the WebAssembly system interfaces + provided by this virtual machine. +- If users want to access the host OS's filesystem within the WasmEdge runtime, + they can add the `--dir guest_path:host_path:readonly` option in the WasmEdge + CLI to assign the read-only configuration. + +### Project compliance + +* Currently, WasmEdge does not meet any security standards or sub-sections. + +### Secure development practices + +- Development Pipeline + - WasmEdge Require contributors to sign off on web-based commits. + - The pull request must be approved by WasmEdge maintainer, committer or + reviewers before merge. + - The pull request must pass the CI jobs before merge. + - WasmEdge also participates in OSS-Fuzz + https://github.com/google/oss-fuzz/tree/master/projects/wasmedge. OSS-Fuzz + aims to make common open-source software more secure and stable by + combining modern fuzzing techniques with scalable, distributed execution. + Participating in OSS-Fuzz allows us to better identify potential issues in + WasmEdge through fuzzing. +- Communication Channels + - Internal + - Direct message on [WasmEdge Discord + server](https://discord.gg/h4KDyB8XTt). + - Inbound + - [WasmEdge Discord server](https://discord.gg/h4KDyB8XTt). + - **#wasmedge** channel on the [CNCF Slack](https://slack.cncf.io/). + - Outbound + - [WasmEdge Discord server](https://discord.gg/h4KDyB8XTt). + - **#wasmedge** channel on the [CNCF Slack](https://slack.cncf.io/). + - Mailing list <wasmedge@googlegroup.com>. + - We host a monthly community meeting to showcase new features, demo new + use cases, and a Q&A part. + - The first Tuesday of each month at 11PM Hong Kong Time/ 7AM PST. + +### Security issue resolution + +As stated in the [WasmEdge security +document](https://github.com/WasmEdge/WasmEdge/blob/master/SECURITY.md), the +process for handling security reports is as follows: + +Users can use the below process to report a vulnerability to WasmEdge: + +Email: + +1. Send email to <wasmedge-security@lists.cncf.io> + * Emails should contain: + * description of the problem + * precise and detailed steps (include screenshots) that created the + problem + * the affected version(s) + * any possible mitigations, if known +1. You will receive a reply from one of the maintainers within 24 hours + acknowledging receipt of the email. After that, we will give a detailed + response about the subsequent process within 48 hours. +1. Please do not submit security vulnerabilities directly as Github Issues. + +Web: + +1. Please visit [GitHub Seuciry Advisory of + WasmEdge](https://github.com/WasmEdge/WasmEdge/security/advisories/new) + * You will receive a confirmation email upon submission + +WasmEdge follows a **`90 days` disclosure timeline**. For known public security +vulnerabilities, we will disclose the disclosure as soon as possible after +receiving the report. Vulnerabilities discovered for the first time will be +disclosed in accordance with the following process: + +* The received security vulnerability report shall be handed over to the + security team for follow-up coordination and repair work. +* After the vulnerability is confirmed, we will create a draft Security Advisory + on Github that lists the details of the vulnerability. +* Invite related personnel to discuss about the fix. +* Fork the temporary private repository on Github, and collaborate to fix the + vulnerability. +* After the fix code is merged into all supported versions, the vulnerability + will be publicly posted in the GitHub Advisory Database. + +### Appendix + +- TBA. diff --git a/examples/capi/host_functions/parse_json/host_function.c b/examples/capi/host_functions/parse_json/host_function.c index 48cafd996202..986ba54bdda0 100644 --- a/examples/capi/host_functions/parse_json/host_function.c +++ b/examples/capi/host_functions/parse_json/host_function.c @@ -28,8 +28,8 @@ int main() { WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern"); WasmEdge_ModuleInstanceContext *ImpObj = WasmEdge_ModuleInstanceCreate(ExportName); - enum WasmEdge_ValType ParamList[1] = {WasmEdge_ValType_ExternRef}; - enum WasmEdge_ValType ReturnList[1] = {WasmEdge_ValType_ExternRef}; + WasmEdge_ValType ParamList[1] = {WasmEdge_ValTypeGenExternRef()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenExternRef()}; WasmEdge_FunctionTypeContext *HostFType = WasmEdge_FunctionTypeCreate(ParamList, 1, ReturnList, 1); WasmEdge_FunctionInstanceContext *HostFunc = diff --git a/examples/capi/host_functions/parse_json/parse-json.wat b/examples/capi/host_functions/parse_json/parse-json.wat index bdb8f8a60c5a..b0d8fb212de7 100644 --- a/examples/capi/host_functions/parse_json/parse-json.wat +++ b/examples/capi/host_functions/parse_json/parse-json.wat @@ -4,4 +4,4 @@ local.get 0 call $i ) -) \ No newline at end of file +) diff --git a/examples/capi/host_functions/parse_json/test.json b/examples/capi/host_functions/parse_json/test.json index 3c86d5b6e1cd..be36d18d71f9 100644 --- a/examples/capi/host_functions/parse_json/test.json +++ b/examples/capi/host_functions/parse_json/test.json @@ -1,3 +1,3 @@ { "testValue": "Success" -} \ No newline at end of file +} diff --git a/examples/capi/mandelbrot-set-in-threads/Makefile b/examples/capi/mandelbrot-set-in-threads/Makefile index 4224291708d1..3cb74d021416 100644 --- a/examples/capi/mandelbrot-set-in-threads/Makefile +++ b/examples/capi/mandelbrot-set-in-threads/Makefile @@ -18,4 +18,3 @@ main: main.cc clean: rm -f main mandelbrot.wasm mandelbrot.so mandelbrot.o mandelbrot.wat output-*.bin - diff --git a/examples/capi/mandelbrot-set-in-threads/README.md b/examples/capi/mandelbrot-set-in-threads/README.md index f4b31f7d790d..deb2d539829d 100644 --- a/examples/capi/mandelbrot-set-in-threads/README.md +++ b/examples/capi/mandelbrot-set-in-threads/README.md @@ -26,7 +26,7 @@ Please follows the [installation step](https://wasmedge.org/book/en/quick_start/ Colin Eberhardt wrote a [blog - Exploring different approaches to building WebAssembly modules](https://blog.scottlogic.com/2017/10/17/wasm-mandelbrot.html) that demonstrate how to compile Mandelbrot set rendering C code into WASM. Please refer to his blog for more information. We use `LLVM-12` to compile the code into WASM. Furthermore, We adopted it into a multi-worker version that parallelly renders the image. We split the image into multiple strides in the y-direction, and assign each thread a stride. As illustrated in the figure below, the image is split into 4 strides and assigned to 4 threads. -![](https://i.imgur.com/hd0pUAF.jpg) +![Mandelbrot picture](https://i.imgur.com/hd0pUAF.jpg) #### Mandelbrot in Multi-Thread diff --git a/examples/capi/mandelbrot-set-in-threads/main.cc b/examples/capi/mandelbrot-set-in-threads/main.cc index 33a64c5228b7..623e8b5be37b 100644 --- a/examples/capi/mandelbrot-set-in-threads/main.cc +++ b/examples/capi/mandelbrot-set-in-threads/main.cc @@ -120,4 +120,4 @@ int main(int argc, char **argv) { WasmEdge_MemoryTypeDelete(MemTypeCxt); WasmEdge_ConfigureDelete(ConfCxt); return 0; -} \ No newline at end of file +} diff --git a/examples/capi/mandelbrot-set-in-threads/mandelbrot.c b/examples/capi/mandelbrot-set-in-threads/mandelbrot.c index 709022f425e6..23fa9c1bead9 100644 --- a/examples/capi/mandelbrot-set-in-threads/mandelbrot.c +++ b/examples/capi/mandelbrot-set-in-threads/mandelbrot.c @@ -78,4 +78,4 @@ void mandelbrotThread(int MaxIterations, int NumThreads, int Rank, double Cx, } } -unsigned char *getImage() { return &Image[0]; } \ No newline at end of file +unsigned char *getImage() { return &Image[0]; } diff --git a/examples/capi/unix_domain_socket/Makefile b/examples/capi/unix_domain_socket/Makefile index 0a7f371f7838..124565a20f92 100644 --- a/examples/capi/unix_domain_socket/Makefile +++ b/examples/capi/unix_domain_socket/Makefile @@ -10,4 +10,3 @@ test: clean: rm server.wasm client.wasm - diff --git a/examples/capi/unix_domain_socket/README.md b/examples/capi/unix_domain_socket/README.md index 98aee2a501b5..e384e239d212 100644 --- a/examples/capi/unix_domain_socket/README.md +++ b/examples/capi/unix_domain_socket/README.md @@ -11,7 +11,7 @@ Please follows the [installation step](https://wasmedge.org/book/en/quick_start/install.html) to install WasmEdge. -### WasmEdge Installation +### Emscripten Installation Please follow the [installation step](https://emscripten.org/docs/getting_started/index.html) to install Emscripten Compiler Frontend (emcc) @@ -21,7 +21,7 @@ A example signal thread server and a simple client are provided. The header file The Unix Domain Socket use file path as input address, therefore the address format V2 are required. Unlike the address V1 has only 4 or 8 bytes. The address has fixed 128 bytes storage and make it large enough to store the unix path. -``` +```bash address V2 format |01 |23456789...127| |address family |address buffer| @@ -38,20 +38,22 @@ emcc client.cpp -o client.wasm -sERROR_ON_UNDEFINED_SYMBOLS=0 -sSTANDALONE_WASM ## Results and Evaluation -Try to input an string in client. The example server will return a reversed string to client. +Try to input an string in client. The example server will return a reversed string to client. ### Client -``` -> Wasmedge + +```bash +$ Wasmedge Server: egdemsaW -> egdemsaW +$ egdemsaW Server: Wasmedge -> Was it a car or a cat I saw? +$ Was it a car or a cat I saw? Server: ?was I tac a ro rac a ti saW ``` ### Server -``` + +```bash Client: Wasmedge Client: egdemsaW Client: Was it a car or a cat I saw? diff --git a/examples/embed_cxx/CMakeLists.txt b/examples/embed_cxx/CMakeLists.txt index 8bd184f8d0c0..e9851eddf6b2 100644 --- a/examples/embed_cxx/CMakeLists.txt +++ b/examples/embed_cxx/CMakeLists.txt @@ -5,7 +5,7 @@ project(embed_cxx CXX) set(CMAKE_CXX_STANDARD 17) set(WASMEDGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..) -set(WASMEDGE_BUILD_AOT_RUNTIME OFF) +set(WASMEDGE_USE_LLVM OFF) if (CMAKE_GENERATOR STREQUAL Ninja) set(CMAKE_JOB_POOLS "link=2") set(CMAKE_JOB_POOL_LINK link) diff --git a/examples/embed_cxx/README.md b/examples/embed_cxx/README.md index 1157c078fdda..3d10e7f20e60 100644 --- a/examples/embed_cxx/README.md +++ b/examples/embed_cxx/README.md @@ -7,7 +7,7 @@ First, download and extract [wasi-sdk](https://github.com/WebAssembly/wasi-sdk/r Build with cmake ```bash -cmake -Bbuild -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_AOT_RUNTIME=OFF; cmake --build build +cmake -Bbuild -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_USE_LLVM=OFF; cmake --build build ``` Run `embed_cxx` diff --git a/examples/js/hello.js b/examples/js/hello.js index d134574b989a..c245c06c38ea 100644 --- a/examples/js/hello.js +++ b/examples/js/hello.js @@ -1,2 +1,2 @@ args = args.slice(1) -print("Hello",...args) \ No newline at end of file +print("Hello",...args) diff --git a/examples/js/repl.js b/examples/js/repl.js index 10f788b23487..2140041493ad 100644 --- a/examples/js/repl.js +++ b/examples/js/repl.js @@ -1565,4 +1565,4 @@ import * as os from "os"; cmd_start(); -})(globalThis); \ No newline at end of file +})(globalThis); diff --git a/examples/plugin/get-string/CMakeLists.txt b/examples/plugin/get-string/CMakeLists.txt index c074638aa046..dd3577fbbbe3 100644 --- a/examples/plugin/get-string/CMakeLists.txt +++ b/examples/plugin/get-string/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC add_library(GetString SHARED diff --git a/examples/plugin/get-string/getstring.cpp b/examples/plugin/get-string/getstring.cpp index 8dcc274ac870..d088fc899e6b 100644 --- a/examples/plugin/get-string/getstring.cpp +++ b/examples/plugin/get-string/getstring.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "plugin/plugin.h" #include "po/helper.h" @@ -78,22 +78,22 @@ create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { } Plugin::Plugin::PluginDescriptor Descriptor{ - .Name = "plugin_name", - .Description = "Example plugin", - .APIVersion = Plugin::Plugin::CurrentAPIVersion, - .Version = {0, 13, 4, 0}, - .ModuleCount = 1, - .ModuleDescriptions = - (Plugin::PluginModule::ModuleDescriptor[]){ - { - .Name = "module_name", - .Description = "Example module", - .Create = create, - }, + /* Name */ "plugin_name", + /* Description */ "Example plugin", + /* APIVersion */ Plugin::Plugin::CurrentAPIVersion, + /* Version */ {0, 13, 5, 0}, + /* ModuleCount */ 1, + /* ModuleDescriptions */ + (Plugin::PluginModule::ModuleDescriptor[]){ + { + /* Name */ "module_name", + /* Description */ "Example module", + /* Create */ create, }, - .AddOptions = addOptions, + }, + /* AddOptions */ addOptions, }; -Plugin::PluginRegister Register(&Descriptor); +EXPORT_GET_DESCRIPTOR(Descriptor) } // namespace diff --git a/examples/plugin/get-string/test.wat b/examples/plugin/get-string/test.wat index f0e0be0c2212..5194f3c8f495 100644 --- a/examples/plugin/get-string/test.wat +++ b/examples/plugin/get-string/test.wat @@ -1,5 +1,5 @@ ;; SPDX-License-Identifier: Apache-2.0 -;; SPDX-FileCopyrightText: 2019-2022 Second State INC +;; SPDX-FileCopyrightText: 2019-2024 Second State INC (module (import "module_wasm_name" "get_string" (func $get_string (param i32 i32 i32))) diff --git a/examples/plugin/wasi-crypto-signature/.gitignore b/examples/plugin/wasi-crypto-signature/.gitignore index a077cc8b7e8a..e5eeecd4af07 100644 --- a/examples/plugin/wasi-crypto-signature/.gitignore +++ b/examples/plugin/wasi-crypto-signature/.gitignore @@ -1,2 +1,2 @@ target/ -.cargo/ \ No newline at end of file +.cargo/ diff --git a/examples/plugin/wasi-crypto-signature/README.md b/examples/plugin/wasi-crypto-signature/README.md index e5c0009f8f09..9780c90eea33 100644 --- a/examples/plugin/wasi-crypto-signature/README.md +++ b/examples/plugin/wasi-crypto-signature/README.md @@ -1,10 +1,10 @@ -# WasmEdge WASI-Crypto example. +# WasmEdge WASI-Crypto example This is a example for demonstrate how to use wasi-crypto plugin of WasmEdge in Rust which is adopted from wasi-crypto tests. ## Prerequisites -### Install Rust. +### Install Rust Follow the instructions below to install rust and wasm32-wasi target. @@ -13,13 +13,13 @@ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustup target add wasm32-wasi ``` -### Install WasmEdge and WASI-crypto plugin. +### Install WasmEdge and WASI-crypto plugin Note that if you install WasmEdge using install script, you need to download `wasi-crypto` plugin from [release page](https://github.com/WasmEdge/WasmEdge/releases/) and put it into `$HOME/.wasmedge/plugin/`. Or you can build wasmedge from scratch with wasi-crypto plugin enabled. -```sh +```bash git clone https://github.com/WasmEdge/WasmEdge.git --depth 1 cd WasmEdge mkdir build; cd build @@ -32,7 +32,7 @@ export WASMEDGE_PLUGIN_PATH=$PWD/plugins/wasi_crypto ## Build the example -```sh +```bash cargo b --target wasm32-wasi ``` @@ -42,13 +42,13 @@ Then we get `target/wasm32-wasi/debug/wasi-crypto-example.wasm`. We can run this example with `wasmedge` like -```sh +```bash wasmedge target/wasm32-wasi/debug/wasi-crypto-example.wasm ``` This example should run successfully and print out the signatures as follows. -``` +```bash [src/main.rs:20] decode(encoded) = "9D92E9FDCA3DDF2E1DDCA1E3B7A79A25B6E4AFFCABF5F9FF4D960B152AB830E9EB978BD3DA89C42BBFE5A2C2AEB0AF1DD178FB4BCD833B587D118F59BBB4D" [src/main.rs:21] decode(export_sig) = "9D92E9FDCA3DDF2E1DDCA1E3B7A79A25B6E4AFFCABF5F9FF4D960B152AB830E9EB978BD3DA89C42BBFE5A2C2AEB0AF1DD178FB4BCD833B587D118F59BBB4D" -``` \ No newline at end of file +``` diff --git a/examples/plugin/wasi-logging/.gitignore b/examples/plugin/wasi-logging/.gitignore index a077cc8b7e8a..e5eeecd4af07 100644 --- a/examples/plugin/wasi-logging/.gitignore +++ b/examples/plugin/wasi-logging/.gitignore @@ -1,2 +1,2 @@ target/ -.cargo/ \ No newline at end of file +.cargo/ diff --git a/examples/plugin/wasi-logging/Cargo.toml b/examples/plugin/wasi-logging/Cargo.toml index caaa5b40caae..b86184556d15 100644 --- a/examples/plugin/wasi-logging/Cargo.toml +++ b/examples/plugin/wasi-logging/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] -wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev="2ec8e3e256f493b62c561a68300ec09c03d040c4" } +wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "9b50b8e78940af080ed3b7c0238e11b04a4bd17b" } diff --git a/examples/plugin/wasi-logging/README.md b/examples/plugin/wasi-logging/README.md index a64889aa6a04..34ede79f728c 100644 --- a/examples/plugin/wasi-logging/README.md +++ b/examples/plugin/wasi-logging/README.md @@ -1,10 +1,10 @@ -# WasmEdge WASI-Logging example. +# WasmEdge WASI-Logging example This is an example of using the WASI-Logging plugin of WasmEdge in Rust. ## Prerequisites -### Install Rust. +### Install Rust Follow the instructions below to install Rust and wasm32-wasi target. @@ -13,7 +13,7 @@ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustup target add wasm32-wasi ``` -### Install WasmEdge and WASI-Logging plugin. +### Install WasmEdge and WASI-Logging plugin Build wasmedge from scratch with the WASI-Logging plugin enabled. @@ -21,22 +21,19 @@ Build wasmedge from scratch with the WASI-Logging plugin enabled. git clone https://github.com/WasmEdge/WasmEdge.git --depth 1 cd WasmEdge mkdir build; cd build -cmake -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_PLUGIN_WASI_LOGGING=ON .. +cmake -DCMAKE_BUILD_TYPE=Release .. make -j -# to tell wasmedge where to find the WASI-Logging plugin. -export WASMEDGE_PLUGIN_PATH=$PWD/plugins/wasi_logging +# WASI-Logging plug-in is a built-in plug-in in WasmEdge library. ``` -If you install WasmEdge using the install script, you can copy library `wasmedge/build/plugins/wasi_logging/libwasmedgePluginWasiLogging.so` to `$HOME/.wasmedge/plugin/` - -### (Optional) Download WASI-Logging WIT files +### (Optional) Download WASI-Logging WIT files In the example, we already prepare the WIT files in `wit` directory. The WIT files are from [wasi-logging](https://github.com/WebAssembly/wasi-logging) repo. You can get the same WIT files by doing the following steps. -``` +```sh git clone https://github.com/WebAssembly/wasi-logging.git cd wasi-logging -git checkout 0a6225ba5f3e90cf72fb75a9796e3e92ff006a65 +git checkout 3293e84de91a1ead98a1b4362f95ac8af5a16ddd cp -r wit /path/to/wasmedge/examples/plugin/wasi-logging ``` @@ -48,6 +45,10 @@ cargo build --target wasm32-wasi Then we get `target/wasm32-wasi/debug/wasi-logging-example.wasm`. +## Logging context + +For the logging context of the `log` function in Rust, developers can use the `""` or `"stdout"` to log to the console, use the `"stderr"` to log to standard error output, or use the file name to log into the target file. + ## Run the example We can run this example with `wasmedge` like @@ -58,32 +59,60 @@ wasmedge target/wasm32-wasi/debug/wasi-logging-example.wasm This example should run successfully and print out the log as follow. +```sh +[2024-05-21 13:43:53.240] [info] =================================== +[2024-05-21 13:43:53.240] [info] Stdout Message Demo +[2024-05-21 13:43:53.240] [info] ----------------------------------- +[2024-05-21 13:43:53.240] [trace] Trace Level Message +[2024-05-21 13:43:53.240] [debug] Debug Level Message +[2024-05-21 13:43:53.240] [info] Info Level Message +[2024-05-21 13:43:53.240] [warning] Warn Level Message +[2024-05-21 13:43:53.240] [error] Error Level Message +[2024-05-21 13:43:53.240] [critical] Critical Level Message +[2024-05-21 13:43:53.240] [info] =================================== +[2024-05-21 13:43:53.240] [info] Stderr Message Demo +[2024-05-21 13:43:53.240] [info] ----------------------------------- +[2024-05-21 13:43:53.240] [trace] Trace Level Message +[2024-05-21 13:43:53.240] [debug] Debug Level Message +[2024-05-21 13:43:53.240] [info] Info Level Message +[2024-05-21 13:43:53.240] [warning] Warn Level Message +[2024-05-21 13:43:53.240] [error] Error Level Message +[2024-05-21 13:43:53.240] [critical] Critical Level Message +[2024-05-21 13:43:53.240] [info] =================================== +[2024-05-21 13:43:53.240] [info] File Message Demo: log/output.log +[2024-05-21 13:43:53.240] [info] ----------------------------------- +[2024-05-21 13:43:53.240] [info] =================================== +[2024-05-21 13:43:53.240] [info] File Message Demo: log/output2.log +[2024-05-21 13:43:53.240] [info] ----------------------------------- +[2024-05-21 13:43:53.240] [info] =================================== +[2024-05-21 13:43:53.240] [info] File Message Demo: continue to log/output.log +[2024-05-21 13:43:53.240] [info] ----------------------------------- +``` + +The log file `log/output.log` will be generated: + +```text +[2024-05-21 13:44:50.966] [trace] Trace Level Message +[2024-05-21 13:44:50.966] [debug] Debug Level Message +[2024-05-21 13:44:50.966] [info] Info Level Message +[2024-05-21 13:44:50.966] [warning] Warn Level Message +[2024-05-21 13:44:50.966] [error] Error Level Message +[2024-05-21 13:44:50.966] [critical] Critical Level Message +[2024-05-21 13:44:50.966] [trace] Trace Level Message +[2024-05-21 13:44:50.966] [debug] Debug Level Message +[2024-05-21 13:44:50.966] [info] Info Level Message +[2024-05-21 13:44:50.966] [warning] Warn Level Message +[2024-05-21 13:44:50.966] [error] Error Level Message +[2024-05-21 13:44:50.966] [critical] Critical Level Message +``` + +The log file `log/output2.log` will be generated: + +```text +[2024-05-21 13:44:50.966] [trace] Trace Level Message +[2024-05-21 13:44:50.966] [debug] Debug Level Message +[2024-05-21 13:44:50.966] [info] Info Level Message +[2024-05-21 13:44:50.966] [warning] Warn Level Message +[2024-05-21 13:44:50.966] [error] Error Level Message +[2024-05-21 13:44:50.966] [critical] Critical Level Message ``` -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [info] =================================== -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [info] Demo 1: Stdout Message Demo -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [info] ----------------------------------- -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [trace] Context: Trace Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [debug] Context: Debug Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [info] Context: Info Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [warning] Context: Warn Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [error] Context: Error Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [critical] Context: Critical Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [info] =================================== -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [info] Demo 2: Stdout Message Without Context -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [info] ----------------------------------- -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [trace] Trace Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [debug] Debug Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [info] Info Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [warning] Warn Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [error] Error Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [critical] Critical Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [info] =================================== -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [info] Demo 3: Stderr Message Demo -[2023-06-08 05:33:55.950] [wasi_logging_stdout] [info] ----------------------------------- -[2023-06-08 05:33:55.950] [wasi_logging_stderr] [trace] stderr: Trace Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stderr] [debug] stderr: Debug Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stderr] [info] stderr: Info Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stderr] [warning] stderr: Warn Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stderr] [error] stderr: Error Level Message -[2023-06-08 05:33:55.950] [wasi_logging_stderr] [critical] stderr: Critical Level Message -``` \ No newline at end of file diff --git a/examples/plugin/wasi-logging/src/lib.rs b/examples/plugin/wasi-logging/src/lib.rs index 3359a7df90c3..82a5eb23a378 100644 --- a/examples/plugin/wasi-logging/src/lib.rs +++ b/examples/plugin/wasi-logging/src/lib.rs @@ -5,10 +5,10 @@ use wasi::logging::logging::{ log, }; -fn title_bar(context: &str, message: &str) { - log(Level::Info, "", "==================================="); - log(Level::Info, context, message); - log(Level::Info, "", "-----------------------------------"); +fn title_bar(message: &str) { + log(Level::Info, "stdout", "==================================="); + log(Level::Info, "stdout", message); + log(Level::Info, "stdout", "-----------------------------------"); } fn demo_template(context: &str) { @@ -21,10 +21,14 @@ fn demo_template(context: &str) { } pub fn wasi_logging_demo() { - title_bar("Demo 1", "Stdout Message Demo"); - demo_template("Context"); - title_bar("Demo 2", "Stdout Message Without Context"); - demo_template(""); - title_bar("Demo 3", "Stderr Message Demo"); + title_bar("Stdout Message Demo"); + demo_template("stdout"); + title_bar("Stderr Message Demo"); demo_template("stderr"); -} \ No newline at end of file + title_bar("File Message Demo: log/output.log"); + demo_template("log/output.log"); + title_bar("File Message Demo: log/output2.log"); + demo_template("log/output2.log"); + title_bar("File Message Demo: continue to log/output.log"); + demo_template("log/output.log"); +} diff --git a/examples/plugin/wasi-logging/src/main.rs b/examples/plugin/wasi-logging/src/main.rs index e495808ca7fa..c47ae87738f5 100644 --- a/examples/plugin/wasi-logging/src/main.rs +++ b/examples/plugin/wasi-logging/src/main.rs @@ -4,4 +4,4 @@ use wasi_logging_example::{ fn main() { wasi_logging_demo(); -} \ No newline at end of file +} diff --git a/examples/plugin/wasi-logging/wit/logging.wit b/examples/plugin/wasi-logging/wit/logging.wit index 1711576367c2..8c0bdf821ef2 100644 --- a/examples/plugin/wasi-logging/wit/logging.wit +++ b/examples/plugin/wasi-logging/wit/logging.wit @@ -31,5 +31,5 @@ interface logging { /// sent, a context, which is an uninterpreted string meant to help /// consumers group similar messages, and a string containing the message /// text. - log: func(level: level, context: string, message: string) + log: func(level: level, context: string, message: string); } diff --git a/examples/plugin/wasi-logging/wit/world.wit b/examples/plugin/wasi-logging/wit/world.wit index c873010734a2..ede6286430b6 100644 --- a/examples/plugin/wasi-logging/wit/world.wit +++ b/examples/plugin/wasi-logging/wit/world.wit @@ -1,5 +1,5 @@ -package wasi:logging +package wasi:logging; -world example-world { - import logging +world imports { + import logging; } diff --git a/examples/plugin/wasmedge-zlib/README.md b/examples/plugin/wasmedge-zlib/README.md index 687cfbda5376..8ae2dcfd1b98 100644 --- a/examples/plugin/wasmedge-zlib/README.md +++ b/examples/plugin/wasmedge-zlib/README.md @@ -1,10 +1,10 @@ -# WasmEdge WASMEDGE-Zlib example. +# WasmEdge WASMEDGE-Zlib example This is an example to demonstrate how to use the `wasmedge-zlib` plugin of WasmEdge with C++. ## Prerequisites -### Install Emscripten SDK (C++ Compiler Toolkit for wasm targets). +### Install Emscripten SDK (C++ Compiler Toolkit for wasm targets) ```bash cd ~/ @@ -16,13 +16,13 @@ cd emsdk source ./emsdk_env.sh # Only this shell will be able to use emscripten. ``` -### Install WasmEdge and WASMEDGE-zlib plugin. +### Install WasmEdge and WASMEDGE-zlib plugin Note that if you install WasmEdge using the install script, you need to download `wasmedge-zlib` plugin from the [release page](https://github.com/WasmEdge/WasmEdge/releases/) and put it into `$HOME/.wasmedge/plugin/`. Or you can build Wasmedge from scratch with `wasmedge-zlib` plugin enabled. -```sh +```bash git clone https://github.com/WasmEdge/WasmEdge.git --depth 1 cd WasmEdge export WASMEDGE_PATH=$PWD @@ -31,14 +31,14 @@ export WASMEDGE_PLUGIN_PATH=$WASMEDGE_PATH/build/plugins/wasmedge_zlib mkdir build; cd build cmake .. -DWASMEDGE_PLUGIN_WASMEDGE_ZLIB=ON # In case you don't want `AOT` support, try the variant below -# cmake .. -DWASMEDGE_PLUGIN_ZLIB=ON -DWASMEDGE_BUILD_AOT_RUNTIME=OFF +# cmake .. -DWASMEDGE_PLUGIN_ZLIB=ON -DWASMEDGE_USE_LLVM=OFF cmake --build . -j # Compiled Wasmedge is located in ./tools/wasmedge/wasmedge ``` ## Build and Run the example as a WASM Module -```sh +```bash cd ../examples/plugin/wasmedge-zlib/ mkdir build em++ main.cpp -O2 -o build/main.wasm -sSTANDALONE_WASM -sWARN_ON_UNDEFINED_SYMBOLS=0 @@ -48,13 +48,13 @@ Then we get `build/main.wasm`. We can run this example with `Wasmedge` with the following command -```sh +```bash ../../../build/tools/wasmedge/wasmedge build/main.wasm ``` ## Build and Run the example as a Native executable -```sh +```bash apt install zlib1g-dev # For Ubuntu / Debian distros | Try zlib-devel for fedora cd ../examples/plugin/wasmedge-zlib/ mkdir build @@ -66,7 +66,7 @@ g++ main.cpp -o build/main -lz The WASM example should run successfully and print out the following messages. -``` +```bash Compressing Buffer of size : 1048576B Decompressing Buffer of size : 785071B Success diff --git a/examples/wasm/README.md b/examples/wasm/README.md index 790198d8e33b..d2648b1aa790 100644 --- a/examples/wasm/README.md +++ b/examples/wasm/README.md @@ -40,6 +40,7 @@ $ wasmedge --reactor factorial.wasm fac 12 ``` ## Hello World + The `hello.wasm` example is a WebAssembly which compiled from a Rust application called `hello`, you can find it under the `hello` folder.. ### Build from source diff --git a/flake.lock b/flake.lock index e5400ecdb5b4..db9323333fcf 100644 --- a/flake.lock +++ b/flake.lock @@ -5,29 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1681202837, - "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "cfacdce06f30d2b68473a46042957675eebb3401", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_2": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1681202837, - "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "cfacdce06f30d2b68473a46042957675eebb3401", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { @@ -38,31 +20,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1684393889, - "narHash": "sha256-X4EP3TdpskELgOKGfm7UcLLGheqxYJZuNEEc0HkmrO0=", + "lastModified": 1723938990, + "narHash": "sha256-9tUadhnZQbWIiYVXH8ncfGXGvkNq3Hag4RCBEMUk7MI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9f7d9a55cc9960c029b006444e64e8dfa54a578e", + "rev": "c42fcfbdfeae23e68fc520f9182dde9f38ad1890", "type": "github" }, "original": { - "id": "nixpkgs", - "ref": "nixpkgs-unstable", - "type": "indirect" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1681358109, - "narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=", "owner": "NixOS", - "repo": "nixpkgs", - "rev": "96ba1c52e54e74c3197f4d43026b3f3d92e83ff9", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", + "ref": "nixos-24.05", "repo": "nixpkgs", "type": "github" } @@ -70,27 +37,7 @@ "root": { "inputs": { "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs", - "rust-overlay": "rust-overlay" - } - }, - "rust-overlay": { - "inputs": { - "flake-utils": "flake-utils_2", - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "lastModified": 1684376381, - "narHash": "sha256-XVFTXADfvBXKwo4boqfg80awUbT+JgQvlQ8uZ+Xgo1s=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "7c9a265c2eaa5783bc18593b1aec39a85653c076", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" + "nixpkgs": "nixpkgs" } }, "systems": { @@ -107,21 +54,6 @@ "repo": "default", "type": "github" } - }, - "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 071564ca2233..03aa6413c401 100644 --- a/flake.nix +++ b/flake.nix @@ -1,68 +1,39 @@ { inputs = { - nixpkgs.url = "nixpkgs/nixpkgs-unstable"; - rust-overlay.url = "github:oxalica/rust-overlay"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; flake-utils.url = "github:numtide/flake-utils"; }; - outputs = { self, rust-overlay, nixpkgs, flake-utils }: + outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem (system: let - overlays = [ (import rust-overlay) ]; - pkgs = import nixpkgs { inherit system overlays; }; - rust = pkgs.rust-bin.stable.latest.default.override { - extensions = [ "rust-src" ]; - targets = [ "wasm32-wasi" "wasm32-unknown-unknown" ]; - }; - llvmPackages = pkgs.llvmPackages_16; - - runRustSysTest = pkgs.writeShellScriptBin "run-rust-sys-test" '' - cd bindings/rust/ - export WASMEDGE_DIR="$(pwd)/../../" - export WASMEDGE_BUILD_DIR="$(pwd)/../../build" - export LD_LIBRARY_PATH="$(pwd)/../../build/lib/api" - cargo test -p wasmedge-sys --examples -- --nocapture - ''; - runRustSysExample = pkgs.writeShellScriptBin "run-rust-sys-example" '' - cd bindings/rust/ - export WASMEDGE_DIR="$(pwd)/../../" - export WASMEDGE_BUILD_DIR="$(pwd)/../../build" - export LD_LIBRARY_PATH="$(pwd)/../../build/lib/api" - cargo run -p wasmedge-sys --example $1 - ''; + pkgs = import nixpkgs { inherit system; }; + llvmPackages = pkgs.llvmPackages_17; + wasmedge_buildInputs = with pkgs; [ + cmake + llvmPackages.clang-unwrapped + llvmPackages.lld + llvmPackages.llvm + openssl + pkg-config + libxml2 + spdlog + ] ++ pkgs.lib.optionals (system == "x86_64-darwin" || system == "aarch64-darwin") [ + pkgs.darwin.apple_sdk.frameworks.Foundation + ]; wasmedge = pkgs.stdenv.mkDerivation { name = "wasmedge"; - version = "0.12.1"; + version = "0.14.0"; src = ./.; - buildInputs = with pkgs; [ - cmake - llvmPackages.clang-unwrapped - llvmPackages.lld - llvmPackages.llvm - openssl - pkg-config - libxml2 - spdlog - ] ++ pkgs.lib.optionals (system == "x86_64-darwin" || system == "aarch64-darwin") [ - pkgs.darwin.apple_sdk.frameworks.Foundation + buildInputs = wasmedge_buildInputs; + cmakeFlags = [ + "-DCMAKE_BUILD_TYPE=Debug" + "-DWASMEDGE_BUILD_PLUGINS=OFF" + "-DWASMEDGE_BUILD_TESTS=OFF" + "-DWASMEDGE_USE_LLVM=ON" ]; - configurePhase = '' - cmake -Bbuild \ - -DCMAKE_BUILD_TYPE=Debug \ - -DWASMEDGE_BUILD_PLUGINS=OFF \ - -DWASMEDGE_BUILD_TESTS=OFF \ - -DWASMEDGE_BUILD_AOT_RUNTIME=ON \ - . - ''; - buildPhase = '' - cmake --build build -j - ''; - installPhase = '' - cd build - cmake --install . --prefix $out - ''; }; in with pkgs; rec { packages = { wasmedge = wasmedge; }; @@ -70,14 +41,9 @@ devShells.default = mkShell { buildInputs = [ wasmedge - ninja - rust gcovr - - runRustSysTest - runRustSysExample - ]; + ] ++ wasmedge_buildInputs; LIBCLANG_PATH = "${llvmPackages.libclang.lib}/lib"; }; diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 705e65279e01..1fa6c1fe5786 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC string(REGEX MATCH "^([0-9]+)[.]([0-9]+)[.]([0-9]+)*" WASMEDGE_VERSION_STRING @@ -9,7 +9,7 @@ string(REPLACE "." ";" WASMEDGE_VERSION_LIST ${WASMEDGE_VERSION_STRING}) list(GET WASMEDGE_VERSION_LIST 0 WASMEDGE_VERSION_MAJOR) list(GET WASMEDGE_VERSION_LIST 1 WASMEDGE_VERSION_MINOR) list(GET WASMEDGE_VERSION_LIST 2 WASMEDGE_VERSION_PATCH) -set(WASMEDGE_API_VERSION "3") +set(WASMEDGE_API_VERSION "4") # Check the MMAP and PWD exists. include(CheckCXXSymbolExists) diff --git a/include/aot/blake3.h b/include/aot/blake3.h index a84f9267d28e..c0ef310b822e 100644 --- a/include/aot/blake3.h +++ b/include/aot/blake3.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/aot/blake3.h - Blake3 hash class definition --------------===// // diff --git a/include/aot/cache.h b/include/aot/cache.h index e453853c21fa..bf61a1e0f7e6 100644 --- a/include/aot/cache.h +++ b/include/aot/cache.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/aot/cache.h - Cache class definition ---------------------===// // diff --git a/include/aot/version.h b/include/aot/version.h index 913018bbecb1..3e4fea6df190 100644 --- a/include/aot/version.h +++ b/include/aot/version.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/aot/version.h - version definition -----------------------===// // diff --git a/include/api/wasmedge/int128.h b/include/api/wasmedge/int128.h index b5247b8d6c81..c4706fb22b41 100644 --- a/include/api/wasmedge/int128.h +++ b/include/api/wasmedge/int128.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/int128.h - WasmEdge C API --------------------------------===// // diff --git a/include/api/wasmedge/version.h.in b/include/api/wasmedge/version.h.in index 4274ba8aeeb2..1552d5bf084d 100644 --- a/include/api/wasmedge/version.h.in +++ b/include/api/wasmedge/version.h.in @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/version.h - WasmEdge C API -------------------------------===// // diff --git a/include/api/wasmedge/wasmedge.h b/include/api/wasmedge/wasmedge.h index caa01edbc761..78a3d431b326 100644 --- a/include/api/wasmedge/wasmedge.h +++ b/include/api/wasmedge/wasmedge.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/wasmedge.h - WasmEdge C API ------------------------------===// // @@ -114,6 +114,9 @@ typedef struct WasmEdge_MemoryTypeContext WasmEdge_MemoryTypeContext; /// Opaque struct of WasmEdge table type. typedef struct WasmEdge_TableTypeContext WasmEdge_TableTypeContext; +/// Opaque struct of WasmEdge tag type. +typedef struct WasmEdge_TagTypeContext WasmEdge_TagTypeContext; + /// Opaque struct of WasmEdge global type. typedef struct WasmEdge_GlobalTypeContext WasmEdge_GlobalTypeContext; @@ -151,6 +154,9 @@ typedef struct WasmEdge_TableInstanceContext WasmEdge_TableInstanceContext; /// Opaque struct of WasmEdge memory instance. typedef struct WasmEdge_MemoryInstanceContext WasmEdge_MemoryInstanceContext; +/// Opaque struct of WasmEdge tag instance. +typedef struct WasmEdge_TagInstanceContext WasmEdge_TagInstanceContext; + /// Opaque struct of WasmEdge global instance. typedef struct WasmEdge_GlobalInstanceContext WasmEdge_GlobalInstanceContext; @@ -1340,6 +1346,18 @@ WasmEdge_MemoryTypeDelete(WasmEdge_MemoryTypeContext *Cxt); // <<<<<<<< WasmEdge memory type functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +// >>>>>>>> WasmEdge tag type functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +/// Get the function type from a tag type. +/// +/// \param Cxt the WasmEdge_TagTypeContext. +/// +/// \returns pointer to function type context of the tag type, NULL if failed. +WASMEDGE_CAPI_EXPORT extern const WasmEdge_FunctionTypeContext * +WasmEdge_TagTypeGetFunctionType(const WasmEdge_TagTypeContext *Cxt); + +// <<<<<<<< WasmEdge tag type functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + // >>>>>>>> WasmEdge global type functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> /// Creation of the WasmEdge_GlobalTypeContext. @@ -1465,6 +1483,22 @@ WASMEDGE_CAPI_EXPORT extern const WasmEdge_MemoryTypeContext * WasmEdge_ImportTypeGetMemoryType(const WasmEdge_ASTModuleContext *ASTCxt, const WasmEdge_ImportTypeContext *Cxt); +/// Get the external value (which is tag type) from an import type. +/// +/// The import type context should be the one queried from the AST module +/// context, or this function will cause unexpected error. +/// The tag type context links to the tag type in the import type context +/// and the AST module context. +/// +/// \param ASTCxt the WasmEdge_ASTModuleContext. +/// \param Cxt the WasmEdge_ImportTypeContext which queried from the `ASTCxt`. +/// +/// \returns the tag type. NULL if failed or the external type of the import +/// type is not `WasmEdge_ExternalType_TagType`. +WASMEDGE_CAPI_EXPORT extern const WasmEdge_TagTypeContext * +WasmEdge_ImportTypeGetTagType(const WasmEdge_ASTModuleContext *ASTCxt, + const WasmEdge_ImportTypeContext *Cxt); + /// Get the external value (which is global type) from an import type. /// /// The import type context should be the one queried from the AST module @@ -1556,6 +1590,22 @@ WASMEDGE_CAPI_EXPORT extern const WasmEdge_MemoryTypeContext * WasmEdge_ExportTypeGetMemoryType(const WasmEdge_ASTModuleContext *ASTCxt, const WasmEdge_ExportTypeContext *Cxt); +/// Get the external value (which is tag type) from an export type. +/// +/// The export type context should be the one queried from the AST module +/// context, or this function will cause unexpected error. +/// The tag type context links to the tag type in the export type context +/// and the AST module context. +/// +/// \param ASTCxt the WasmEdge_ASTModuleContext. +/// \param Cxt the WasmEdge_ExportTypeContext which queried from the `ASTCxt`. +/// +/// \returns the tag type. NULL if failed or the external type of the export +/// type is not `WasmEdge_ExternalType_Tag`. +WASMEDGE_CAPI_EXPORT extern const WasmEdge_TagTypeContext * +WasmEdge_ExportTypeGetTagType(const WasmEdge_ASTModuleContext *ASTCxt, + const WasmEdge_ExportTypeContext *Cxt); + /// Get the external value (which is global type) from an export type. /// /// The export type context should be the one queried from the AST module @@ -1740,6 +1790,11 @@ WasmEdge_LoaderSerializeASTModule(WasmEdge_LoaderContext *Cxt, const WasmEdge_ASTModuleContext *ASTCxt, WasmEdge_Bytes *Buf); +WASMEDGE_CAPI_EXPORT extern WasmEdge_Result +WasmEdge_LoaderPrepareForJIT(WasmEdge_LoaderContext *Ctx, + WasmEdge_ASTModuleContext *ASTCxt, + const WasmEdge_ConfigureContext *ConfCxt); + /// Deletion of the WasmEdge_LoaderContext. /// /// After calling this function, the context will be destroyed and should @@ -2012,7 +2067,7 @@ WasmEdge_StoreDelete(WasmEdge_StoreContext *Cxt); /// /// Create a module instance context with exported module name for host /// instances. Developer can use this API to create a module instance for -/// collecting host functions, tables, memories, and globals. +/// collecting host functions, tables, memories, tags, and globals. /// The caller owns the object and should call `WasmEdge_ModuleInstanceDelete` /// to destroy it. /// @@ -2208,6 +2263,21 @@ WASMEDGE_CAPI_EXPORT extern WasmEdge_MemoryInstanceContext * WasmEdge_ModuleInstanceFindMemory(const WasmEdge_ModuleInstanceContext *Cxt, const WasmEdge_String Name); +/// Get the exported tag instance context of a module instance. +/// +/// The result tag instance context links to the tag instance in the +/// module instance context and owned by the module instance context. +/// +/// This function is thread-safe. +/// +/// \param Cxt the WasmEdge_ModuleInstanceContext. +/// \param Name the tag name WasmEdge_String. +/// +/// \returns pointer to the tag instance context. NULL if not found. +WASMEDGE_CAPI_EXPORT extern WasmEdge_TagInstanceContext * +WasmEdge_ModuleInstanceFindTag(const WasmEdge_ModuleInstanceContext *Cxt, + const WasmEdge_String Name); + /// Get the exported global instance context of a module instance. /// /// The result global instance context links to the global instance in the @@ -2311,6 +2381,35 @@ WASMEDGE_CAPI_EXPORT extern uint32_t WasmEdge_ModuleInstanceListMemory(const WasmEdge_ModuleInstanceContext *Cxt, WasmEdge_String *Names, const uint32_t Len); +/// Get the length of exported tag list of a module instance. +/// +/// This function is thread-safe. +/// +/// \param Cxt the WasmEdge_ModuleInstanceContext. +/// +/// \returns length of the exported tag list. +WASMEDGE_CAPI_EXPORT extern uint32_t +WasmEdge_ModuleInstanceListTagLength(const WasmEdge_ModuleInstanceContext *Cxt); + +/// List the exported tag names of a module instance. +/// +/// The returned tag names filled into the `Names` array are linked to the +/// exported names of tags of the module instance context, and the caller +/// should __NOT__ call the `WasmEdge_StringDelete`. +/// If the `Names` buffer length is smaller than the result of the exported +/// tag list size, the overflowed return values will be discarded. +/// +/// This function is thread-safe. +/// +/// \param Cxt the WasmEdge_ModuleInstanceContext. +/// \param [out] Names the output WasmEdge_String buffer of the tag names. +/// \param Len the buffer length. +/// +/// \returns actual exported tag list size. +WASMEDGE_CAPI_EXPORT extern uint32_t +WasmEdge_ModuleInstanceListTag(const WasmEdge_ModuleInstanceContext *Cxt, + WasmEdge_String *Names, const uint32_t Len); + /// Get the length of exported global list of a module instance. /// /// This function is thread-safe. @@ -2814,6 +2913,21 @@ WasmEdge_MemoryInstanceDelete(WasmEdge_MemoryInstanceContext *Cxt); // <<<<<<<< WasmEdge memory instance functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +// >>>>>>>> WasmEdge tag instance functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +/// Get the tag type context from a tag instance. +/// +/// The tag type context links to the tag type in the tag instance +/// context and owned by the context. +/// +/// \param Cxt the WasmEdge_TagInstanceContext. +/// +/// \returns pointer to context, NULL if failed. +WASMEDGE_CAPI_EXPORT extern const WasmEdge_TagTypeContext * +WasmEdge_TagInstanceGetTagType(const WasmEdge_TagInstanceContext *Cxt); + +// <<<<<<<< WasmEdge tag instance functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + // >>>>>>>> WasmEdge global instance functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> /// Creation of the WasmEdge_GlobalInstanceContext. @@ -3874,9 +3988,9 @@ WASMEDGE_CAPI_EXPORT extern int WasmEdge_Driver_Tool(int Argc, const char *Argv[]); #ifdef WASMEDGE_BUILD_WASI_NN_RPC -/// Entrypoint for the Wasi-NN RPC server tool. +/// Entrypoint for the WASI-NN RPC server tool. /// -/// This function provides an entrypoint to the WasmEdge Wasi-NN RPC server tool +/// This function provides an entrypoint to the WasmEdge WASI-NN RPC server tool /// with the command line arguments. /// /// \param Argc the argument count. @@ -4087,9 +4201,10 @@ typedef struct WasmEdge_DataSegment { /// \param Len the buffer length. /// /// \returns actual data segment list size. -WASMEDGE_CAPI_EXPORT extern uint32_t WasmEdge_ASTModuleListDataSegments( - const WasmEdge_ASTModuleContext *Cxt, WasmEdge_DataSegment *Segments, - const uint32_t Len); +WASMEDGE_CAPI_EXPORT extern uint32_t +WasmEdge_ASTModuleListDataSegments(const WasmEdge_ASTModuleContext *Cxt, + WasmEdge_DataSegment *Segments, + const uint32_t Len); // <<<<<<<< [qdrvm] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< diff --git a/include/ast/component/alias.h b/include/ast/component/alias.h index 8389e32871f9..805cfdf8cb76 100644 --- a/include/ast/component/alias.h +++ b/include/ast/component/alias.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/ast/component/alias.h - alias class definitions ----------===// // diff --git a/include/ast/component/canonical.h b/include/ast/component/canonical.h index 5f924c1ec58b..422866d2ce98 100644 --- a/include/ast/component/canonical.h +++ b/include/ast/component/canonical.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/ast/component/type.h - type class definitions ----===// // diff --git a/include/ast/component/import_export.h b/include/ast/component/import_export.h index 716d7b000c53..c971ebd9d58d 100644 --- a/include/ast/component/import_export.h +++ b/include/ast/component/import_export.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/ast/component/instance.h - instance class definitions ----===// // @@ -32,7 +32,7 @@ class Import { std::string &getName() noexcept { return Name; } std::string_view getName() const noexcept { return Name; } ExternDesc &getDesc() noexcept { return Desc; } - const ExternDesc getDesc() const noexcept { return Desc; } + const ExternDesc &getDesc() const noexcept { return Desc; } }; class Export { std::string Name; @@ -43,7 +43,7 @@ class Export { std::string &getName() noexcept { return Name; } std::string_view getName() const noexcept { return Name; } SortIndex<Sort> &getSortIndex() noexcept { return Idx; } - const SortIndex<Sort> getSortIndex() const noexcept { return Idx; } + const SortIndex<Sort> &getSortIndex() const noexcept { return Idx; } std::optional<ExternDesc> &getDesc() noexcept { return Desc; } const std::optional<ExternDesc> getDesc() const noexcept { return Desc; } }; diff --git a/include/ast/component/instance.h b/include/ast/component/instance.h index 07742f6b847b..123597aef888 100644 --- a/include/ast/component/instance.h +++ b/include/ast/component/instance.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/ast/component/instance.h - instance class definitions ----===// // diff --git a/include/ast/component/sort.h b/include/ast/component/sort.h index b55deff74dbe..a6465d85c087 100644 --- a/include/ast/component/sort.h +++ b/include/ast/component/sort.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/ast/component/sort.h - sort class definitions ------------===// // @@ -32,7 +32,6 @@ enum class CoreSort : Byte { Instance = 0x12, }; enum class SortCase : Byte { - CoreInstance, Func = 0x01, Value = 0x02, Type = 0x03, diff --git a/include/ast/component/start.h b/include/ast/component/start.h index 96188ff0237d..a6fc7cebd2a8 100644 --- a/include/ast/component/start.h +++ b/include/ast/component/start.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once #include "ast/component/type.h" diff --git a/include/ast/component/type.h b/include/ast/component/type.h index 93b15e606d9f..606be43021be 100644 --- a/include/ast/component/type.h +++ b/include/ast/component/type.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/ast/component/type.h - type class definitions ----===// // @@ -43,7 +43,7 @@ enum class PrimValType : Byte { }; using TypeIndex = uint32_t; -using ValueType = std::variant<PrimValType, TypeIndex>; +using ValueType = std::variant<TypeIndex, PrimValType>; class LabelValType { public: @@ -167,10 +167,13 @@ class Borrow { using DefValType = std::variant<PrimValType, Record, VariantTy, List, Tuple, Flags, Enum, Option, Result, Own, Borrow>; - using ResultList = std::variant<ValueType, std::vector<LabelValType>>; class FuncType { public: + FuncType() : ParamList{}, ResList{} {} + FuncType(std::vector<LabelValType> P, ResultList R) + : ParamList{P}, ResList{R} {} + Span<const LabelValType> getParamList() const noexcept { return ParamList; } std::vector<LabelValType> &getParamList() noexcept { return ParamList; } ResultList getResultList() const noexcept { return ResList; } @@ -290,3 +293,278 @@ class Type { } // namespace Component } // namespace AST } // namespace WasmEdge + +template <class... Ts> struct Overloaded : Ts... { + using Ts::operator()...; +}; +template <class... Ts> Overloaded(Ts...) -> Overloaded<Ts...>; + +template <> +struct fmt::formatter<WasmEdge::AST::Component::PrimValType> + : fmt::formatter<std::string_view> { + fmt::format_context::iterator + format(const WasmEdge::AST::Component::PrimValType &Type, + fmt::format_context &Ctx) const noexcept { + using namespace WasmEdge::AST::Component; + using namespace std::literals; + switch (Type) { + case PrimValType::Bool: + return formatter<std::string_view>::format("bool"sv, Ctx); + case PrimValType::S8: + return formatter<std::string_view>::format("s8"sv, Ctx); + case PrimValType::U8: + return formatter<std::string_view>::format("u8"sv, Ctx); + case PrimValType::S16: + return formatter<std::string_view>::format("s16"sv, Ctx); + case PrimValType::U16: + return formatter<std::string_view>::format("u16"sv, Ctx); + case PrimValType::S32: + return formatter<std::string_view>::format("s32"sv, Ctx); + case PrimValType::U32: + return formatter<std::string_view>::format("u32"sv, Ctx); + case PrimValType::S64: + return formatter<std::string_view>::format("s64"sv, Ctx); + case PrimValType::U64: + return formatter<std::string_view>::format("u64"sv, Ctx); + case PrimValType::Float32: + return formatter<std::string_view>::format("float32"sv, Ctx); + case PrimValType::Float64: + return formatter<std::string_view>::format("float64"sv, Ctx); + case PrimValType::Char: + return formatter<std::string_view>::format("char"sv, Ctx); + case PrimValType::String: + return formatter<std::string_view>::format("string"sv, Ctx); + default: + return formatter<std::string_view>::format("unknown primvaltype"sv, Ctx); + } + } +}; + +template <> +struct fmt::formatter<WasmEdge::AST::Component::ValueType> + : fmt::formatter<std::string_view> { + fmt::format_context::iterator + format(const WasmEdge::AST::Component::ValueType &Type, + fmt::format_context &Ctx) const noexcept { + using namespace WasmEdge::AST::Component; + using namespace std::literals; + + if (std::holds_alternative<PrimValType>(Type)) { + return formatter<std::string_view>::format( + fmt::format("{}", std::get<PrimValType>(Type)), Ctx); + } + // or it's an type index + const auto Idx = std::get<TypeIndex>(Type); + return formatter<std::string_view>::format(fmt::format("!({})", Idx), Ctx); + } +}; + +template <> +struct fmt::formatter<WasmEdge::AST::Component::DefValType> + : fmt::formatter<std::string_view> { + fmt::format_context::iterator + format(const WasmEdge::AST::Component::DefValType &Type, + fmt::format_context &Ctx) const noexcept { + using namespace WasmEdge::AST::Component; + using namespace std::literals; + return formatter<std::string_view>::format( + std::visit( + Overloaded{ + [](const PrimValType &Arg) { + fmt::memory_buffer Buffer; + fmt::format_to(std::back_inserter(Buffer), "{}"sv, Arg); + return std::string_view(Buffer.data(), Buffer.size()); + }, + [](const Record &Arg) { + fmt::memory_buffer Buffer; + fmt::format_to(std::back_inserter(Buffer), "record <"sv); + for (const auto &LabelTyp : Arg.getLabelTypes()) { + fmt::format_to(std::back_inserter(Buffer), "| {} : {} "sv, + LabelTyp.getLabel(), LabelTyp.getValType()); + } + fmt::format_to(std::back_inserter(Buffer), ">"sv); + return std::string_view(Buffer.data(), Buffer.size()); + }, + [](const VariantTy &Arg) { + fmt::memory_buffer Buffer; + fmt::format_to(std::back_inserter(Buffer), "variant <"sv); + for (const auto &Case : Arg.getCases()) { + if (Case.getValType().has_value()) { + fmt::format_to(std::back_inserter(Buffer), "| {} : {} "sv, + Case.getLabel(), + Case.getValType().value()); + } else { + fmt::format_to(std::back_inserter(Buffer), "| {} "sv, + Case.getLabel()); + } + } + fmt::format_to(std::back_inserter(Buffer), ">"sv); + return std::string_view(Buffer.data(), Buffer.size()); + }, + [](const List &Arg) { + fmt::memory_buffer Buffer; + fmt::format_to(std::back_inserter(Buffer), "list<{}>"sv, + Arg.getValType()); + return std::string_view(Buffer.data(), Buffer.size()); + }, + [](const Tuple &Arg) { + fmt::memory_buffer Buffer; + fmt::format_to(std::back_inserter(Buffer), "tuple <"sv); + for (const auto &Ty : Arg.getTypes()) { + fmt::format_to(std::back_inserter(Buffer), "| {} "sv, Ty); + } + fmt::format_to(std::back_inserter(Buffer), ">"sv); + return std::string_view(Buffer.data(), Buffer.size()); + }, + [](const Flags &) { + fmt::memory_buffer Buffer; + fmt::format_to(std::back_inserter(Buffer), "flags"sv); + return std::string_view(Buffer.data(), Buffer.size()); + }, + [](const Enum &) { + fmt::memory_buffer Buffer; + fmt::format_to(std::back_inserter(Buffer), "enum"sv); + return std::string_view(Buffer.data(), Buffer.size()); + }, + [](const Option &Arg) { + fmt::memory_buffer Buffer; + fmt::format_to(std::back_inserter(Buffer), "option<{}>"sv, + Arg.getValType()); + return std::string_view(Buffer.data(), Buffer.size()); + }, + [](const Result &Arg) { + fmt::memory_buffer Buffer; + if (Arg.getValType().has_value()) { + fmt::format_to(std::back_inserter(Buffer), "result<{}>"sv, + Arg.getValType().value()); + } else { + fmt::format_to(std::back_inserter(Buffer), "result<>"sv); + } + return std::string_view(Buffer.data(), Buffer.size()); + }, + [](const Own &Arg) { + fmt::memory_buffer Buffer; + fmt::format_to(std::back_inserter(Buffer), "own<!({})>"sv, + Arg.getIndex()); + return std::string_view(Buffer.data(), Buffer.size()); + }, + [](const Borrow &Arg) { + fmt::memory_buffer Buffer; + fmt::format_to(std::back_inserter(Buffer), "borrow<!({})>"sv, + Arg.getIndex()); + return std::string_view(Buffer.data(), Buffer.size()); + }, + }, + Type), + Ctx); + } +}; + +template <> +struct fmt::formatter<WasmEdge::AST::Component::FuncType> + : fmt::formatter<std::string_view> { + fmt::format_context::iterator + format(const WasmEdge::AST::Component::FuncType &Type, + fmt::format_context &Ctx) const noexcept { + using namespace WasmEdge::AST::Component; + using namespace std::literals; + + fmt::memory_buffer Buffer; + + fmt::format_to(std::back_inserter(Buffer), "[ "sv); + for (const auto &PL : Type.getParamList()) { + fmt::format_to(std::back_inserter(Buffer), "({} : {}) "sv, PL.getLabel(), + PL.getValType()); + } + fmt::format_to(std::back_inserter(Buffer), "] -> "sv); + + const auto &ResList = Type.getResultList(); + if (std::holds_alternative<ValueType>(ResList)) { + fmt::format_to(std::back_inserter(Buffer), "{}"sv, + std::get<ValueType>(ResList)); + } else { + fmt::format_to(std::back_inserter(Buffer), "[ "sv); + for (const auto &RL : std::get<std::vector<LabelValType>>(ResList)) { + fmt::format_to(std::back_inserter(Buffer), "({} : {}) "sv, + RL.getLabel(), RL.getValType()); + } + fmt::format_to(std::back_inserter(Buffer), "]"sv); + } + + return formatter<std::string_view>::format( + std::string_view(Buffer.data(), Buffer.size()), Ctx); + } +}; + +template <> +struct fmt::formatter<WasmEdge::AST::Component::ComponentType> + : fmt::formatter<std::string_view> { + fmt::format_context::iterator + format(const WasmEdge::AST::Component::ComponentType &, + fmt::format_context &Ctx) const noexcept { + using namespace std::literals; + return formatter<std::string_view>::format("component type"sv, Ctx); + } +}; + +template <> +struct fmt::formatter<WasmEdge::AST::Component::InstanceType> + : fmt::formatter<std::string_view> { + fmt::format_context::iterator + format(const WasmEdge::AST::Component::InstanceType &Type, + fmt::format_context &Ctx) const noexcept { + using namespace WasmEdge::AST::Component; + using namespace std::literals; + + fmt::memory_buffer Buffer; + + fmt::format_to(std::back_inserter(Buffer), "instance <"sv); + for (const auto &T : Type.getContent()) { + fmt::format_to(std::back_inserter(Buffer), "|"sv); + std::visit( + Overloaded{ + [&](const CoreType &) { + fmt::format_to(std::back_inserter(Buffer), "core type"sv); + }, + [&](const Alias &) { + fmt::format_to(std::back_inserter(Buffer), "alias type"sv); + }, + [&](const std::shared_ptr<WasmEdge::AST::Component::Type> &) { + fmt::format_to(std::back_inserter(Buffer), "type"sv); + }, + [&](const ExportDecl &) { + fmt::format_to(std::back_inserter(Buffer), + "export decl type"sv); + }}, + T); + } + fmt::format_to(std::back_inserter(Buffer), ">"sv); + return formatter<std::string_view>::format( + std::string_view(Buffer.data(), Buffer.size()), Ctx); + } +}; + +template <> +struct fmt::formatter<WasmEdge::AST::Component::DefType> + : fmt::formatter<std::string_view> { + fmt::format_context::iterator + format(const WasmEdge::AST::Component::DefType &Type, + fmt::format_context &Ctx) const noexcept { + using namespace WasmEdge::AST::Component; + using namespace std::literals; + + return formatter<std::string_view>::format( + std::visit( + Overloaded{ + [](const DefValType &Arg) { return fmt::format("{}"sv, Arg); }, + [](const FuncType &Arg) { return fmt::format("{}"sv, Arg); }, + [](const ComponentType &Arg) { + return fmt::format("{}"sv, Arg); + }, + [](const InstanceType &Arg) { + return fmt::format("{}"sv, Arg); + }}, + Type), + Ctx); + } +}; diff --git a/include/ast/description.h b/include/ast/description.h index 08b7679d9cfd..291eec115964 100644 --- a/include/ast/description.h +++ b/include/ast/description.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/ast/description.h - Desc classes definitions -------------===// // @@ -59,6 +59,8 @@ class ImportDesc : public Desc { MemoryType &getExternalMemoryType() noexcept { return MemType; } const GlobalType &getExternalGlobalType() const noexcept { return GlobType; } GlobalType &getExternalGlobalType() noexcept { return GlobType; } + const TagType &getExternalTagType() const noexcept { return TgType; } + TagType &getExternalTagType() noexcept { return TgType; } private: /// \name Data of ImportDesc: Module name, External name, and content node. @@ -68,6 +70,7 @@ class ImportDesc : public Desc { TableType TabType; MemoryType MemType; GlobalType GlobType; + TagType TgType; /// @} }; diff --git a/include/ast/expression.h b/include/ast/expression.h index f384e538a492..d19c826ffc17 100644 --- a/include/ast/expression.h +++ b/include/ast/expression.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/ast/expression.h - Expression class definition -----------===// // diff --git a/include/ast/instruction.h b/include/ast/instruction.h index 04e1d354680a..209f098b21b6 100644 --- a/include/ast/instruction.h +++ b/include/ast/instruction.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/ast/instruction.h - Instruction class definition ---------===// // @@ -32,6 +32,32 @@ class Instruction { uint32_t StackEraseEnd; int32_t PCOffset; }; + struct BrCastDescriptor { + struct JumpDescriptor Jump; + ValType RType1, RType2; + }; + struct CatchDescriptor { + // LEGACY-EH: remove this flag after deprecating legacy EH. + bool IsLegacy : 1; + bool IsAll : 1; + bool IsRef : 1; + uint32_t TagIndex; + uint32_t LabelIndex; + struct JumpDescriptor Jump; + }; + struct TryDescriptor { + BlockType ResType; + uint32_t BlockParamNum; + uint32_t JumpEnd; + std::vector<CatchDescriptor> Catch; + }; + // LEGACY-EH: remove this struct after deprecating legacy EH. + struct CatchDescriptorLegacy { + uint32_t TagIndex; + uint32_t LabelIndex; + uint32_t CatchIndex; + uint32_t CatchPCOffset; + }; public: /// Constructor assigns the OpCode and the Offset. @@ -46,10 +72,12 @@ class Instruction { #endif Flags.IsAllocLabelList = false; Flags.IsAllocValTypeList = false; + Flags.IsAllocBrCast = false; + Flags.IsAllocTryCatch = false; } /// Copy constructor. - Instruction(const Instruction &Instr) + Instruction(const Instruction &Instr) noexcept : Data(Instr.Data), Offset(Instr.Offset), Code(Instr.Code), Flags(Instr.Flags) { if (Flags.IsAllocLabelList) { @@ -60,15 +88,21 @@ class Instruction { Data.SelectT.ValTypeList = new ValType[Data.SelectT.ValTypeListSize]; std::copy_n(Instr.Data.SelectT.ValTypeList, Data.SelectT.ValTypeListSize, Data.SelectT.ValTypeList); + } else if (Flags.IsAllocBrCast) { + Data.BrCast = new BrCastDescriptor(*Instr.Data.BrCast); + } else if (Flags.IsAllocTryCatch) { + Data.TryCatch = new TryDescriptor(*Instr.Data.TryCatch); } } /// Move constructor. - Instruction(Instruction &&Instr) + Instruction(Instruction &&Instr) noexcept : Data(Instr.Data), Offset(Instr.Offset), Code(Instr.Code), Flags(Instr.Flags) { Instr.Flags.IsAllocLabelList = false; Instr.Flags.IsAllocValTypeList = false; + Instr.Flags.IsAllocBrCast = false; + Instr.Flags.IsAllocTryCatch = false; } /// Destructor. @@ -91,11 +125,7 @@ class Instruction { /// Getter and setter of block type. const BlockType &getBlockType() const noexcept { return Data.Blocks.ResType; } - void setBlockType(const ValType &VType) noexcept { - Data.Blocks.ResType.setData(VType); - } - void setBlockType(uint32_t Idx) noexcept { Data.Blocks.ResType.setData(Idx); } - void setEmptyBlockType() noexcept { Data.Blocks.ResType.setEmpty(); } + BlockType &getBlockType() noexcept { return Data.Blocks.ResType; } /// Getter and setter of jump count to End instruction. uint32_t getJumpEnd() const noexcept { return Data.Blocks.JumpEnd; } @@ -129,9 +159,26 @@ class Instruction { Flags.IsAllocLabelList ? Data.BrTable.LabelListSize : 0); } - /// Getter and setter of IsLast for End instruction. - bool isLast() const noexcept { return Data.IsLast; } - void setLast(bool Last = true) noexcept { Data.IsLast = Last; } + /// Getter and setter of expression end for End instruction. + bool isExprLast() const noexcept { return Data.EndFlags.IsExprLast; } + void setExprLast(bool Last = true) noexcept { + Data.EndFlags.IsExprLast = Last; + } + + /// Getter and setter of try block end for End instruction. + bool isTryBlockLast() const noexcept { return Data.EndFlags.IsTryBlockLast; } + void setTryBlockLast(bool Last = true) noexcept { + Data.EndFlags.IsTryBlockLast = Last; + } + + // LEGACY-EH: remove these functions after deprecating legacy EH. + /// Getter and setter of try block end for End instruction. + bool isLegacyTryBlockLast() const noexcept { + return Data.EndFlags.IsLegacyTryBlockLast; + } + void setLegacyTryBlockLast(bool Last = true) noexcept { + Data.EndFlags.IsLegacyTryBlockLast = Last; + } /// Getter and setter of Jump for Br* instruction. const JumpDescriptor &getJump() const noexcept { return Data.Jump; } @@ -179,13 +226,20 @@ class Instruction { uint8_t getMemoryLane() const noexcept { return Data.Memories.MemLane; } uint8_t &getMemoryLane() noexcept { return Data.Memories.MemLane; } + // LEGACY-EH: remove these functions after deprecating legacy EH. + /// Getter and setter of legacy Catch for Catch* instructions. + const CatchDescriptorLegacy &getCatchLegacy() const noexcept { + return Data.CatchLegacy; + } + CatchDescriptorLegacy &getCatchLegacy() noexcept { return Data.CatchLegacy; } + /// Getter and setter of the constant value. ValVariant getNum() const noexcept { #if defined(__x86_64__) || defined(__aarch64__) || \ (defined(__riscv) && __riscv_xlen == 64) return ValVariant(Data.Num); #else - uint128_t N(Data.Num.High, Data.Num.Low); + uint128_t N{Data.Num.High, Data.Num.Low}; return ValVariant(N); #endif } @@ -194,22 +248,49 @@ class Instruction { (defined(__riscv) && __riscv_xlen == 64) Data.Num = N.get<uint128_t>(); #else - std::memcpy(&Data.Num, &N.get<uint128_t>(), sizeof(uint128_t)); + uint128_t V = N.get<uint128_t>(); + Data.Num.Low = V.low(); + Data.Num.High = V.high(); #endif } + /// Getter and setter of BrCast info for Br_cast instructions. + void setBrCast(uint32_t LabelIdx) { + reset(); + Data.BrCast = new BrCastDescriptor(); + Data.BrCast->Jump.TargetIndex = LabelIdx; + Flags.IsAllocBrCast = true; + } + const BrCastDescriptor &getBrCast() const noexcept { return *Data.BrCast; } + BrCastDescriptor &getBrCast() noexcept { return *Data.BrCast; } + + /// Getter and setter of try block info for try_table instruction. + void setTryCatch() { + reset(); + Data.TryCatch = new TryDescriptor(); + Flags.IsAllocTryCatch = true; + } + const TryDescriptor &getTryCatch() const noexcept { return *Data.TryCatch; } + TryDescriptor &getTryCatch() noexcept { return *Data.TryCatch; } + private: /// Release allocated resources. - void reset() { + void reset() noexcept { if (Flags.IsAllocLabelList) { Data.BrTable.LabelListSize = 0; delete[] Data.BrTable.LabelList; } else if (Flags.IsAllocValTypeList) { Data.SelectT.ValTypeListSize = 0; delete[] Data.SelectT.ValTypeList; + } else if (Flags.IsAllocBrCast) { + delete Data.BrCast; + } else if (Flags.IsAllocTryCatch) { + delete Data.TryCatch; } Flags.IsAllocLabelList = false; Flags.IsAllocValTypeList = false; + Flags.IsAllocBrCast = false; + Flags.IsAllocTryCatch = false; } /// Swap function. @@ -266,14 +347,28 @@ class Instruction { uint64_t High; } Num; #endif - // Type 9: IsLast. - bool IsLast; + // Type 9: End flags. + struct { + bool IsExprLast : 1; + bool IsTryBlockLast : 1; + // LEGACY-EH: remove this flag after deprecating legacy EH. + bool IsLegacyTryBlockLast : 1; + } EndFlags; + // Type 10: TypeCastBranch. + BrCastDescriptor *BrCast; + // Type 11: Try Block. + TryDescriptor *TryCatch; + // LEGACY-EH: remove this case after deprecating legacy EH. + // Type 12: Legacy Catch descriptor. + CatchDescriptorLegacy CatchLegacy; } Data; uint32_t Offset = 0; OpCode Code = OpCode::End; struct { bool IsAllocLabelList : 1; bool IsAllocValTypeList : 1; + bool IsAllocBrCast : 1; + bool IsAllocTryCatch : 1; } Flags; /// @} }; diff --git a/include/ast/module.h b/include/ast/module.h index 7f74f77ed058..3c992ed17fdb 100644 --- a/include/ast/module.h +++ b/include/ast/module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/ast/module.h - Module class definition -------------------===// // @@ -63,40 +63,14 @@ class Module { DataSection &getDataSection() { return DataSec; } const DataCountSection &getDataCountSection() const { return DataCountSec; } DataCountSection &getDataCountSection() { return DataCountSec; } + const TagSection &getTagSection() const { return TagSec; } + TagSection &getTagSection() { return TagSec; } const AOTSection &getAOTSection() const { return AOTSec; } AOTSection &getAOTSection() { return AOTSec; } - enum class Intrinsics : uint32_t { - kTrap, - kCall, - kCallIndirect, - kMemCopy, - kMemFill, - kMemGrow, - kMemSize, - kMemInit, - kDataDrop, - kTableGet, - kTableSet, - kTableCopy, - kTableFill, - kTableGrow, - kTableSize, - kTableInit, - kElemDrop, - kRefFunc, - kTableGetFuncSymbol, - kMemoryAtomicNotify, - kMemoryAtomicWait, - kCallRef, - kRefGetFuncSymbol, - kIntrinsicMax, - }; - using IntrinsicsTable = void * [uint32_t(Intrinsics::kIntrinsicMax)]; - /// Getter and setter of compiled symbol. const auto &getSymbol() const noexcept { return IntrSymbol; } - void setSymbol(Symbol<const IntrinsicsTable *> S) noexcept { + void setSymbol(Symbol<const Executable::IntrinsicsTable *> S) noexcept { IntrSymbol = std::move(S); } @@ -126,12 +100,13 @@ class Module { CodeSection CodeSec; DataSection DataSec; DataCountSection DataCountSec; + TagSection TagSec; /// @} /// \name Data of AOT. /// @{ AOTSection AOTSec; - Symbol<const IntrinsicsTable *> IntrSymbol; + Symbol<const Executable::IntrinsicsTable *> IntrSymbol; /// @} /// \name Validated flag. @@ -143,15 +118,22 @@ class Module { class CoreModuleSection : public Section { public: /// Getter of content. - Span<const Module> getContent() const noexcept { return Content; } - std::vector<Module> &getContent() noexcept { return Content; } + const Module &getContent() const noexcept { return Content; } + Module &getContent() noexcept { return Content; } private: - std::vector<Module> Content; + Module Content; }; namespace Component { + class Component { + using Section = + std::variant<CustomSection, CoreModuleSection, CoreInstanceSection, + CoreTypeSection, ComponentSection, InstanceSection, + AliasSection, TypeSection, CanonSection, StartSection, + ImportSection, ExportSection>; + public: /// Getter of magic vector. const std::vector<Byte> &getMagic() const noexcept { return Magic; } @@ -165,32 +147,8 @@ class Component { const std::vector<Byte> &getLayer() const noexcept { return Layer; } std::vector<Byte> &getLayer() noexcept { return Layer; } - std::vector<CustomSection> &getCustomSections() noexcept { - return CustomSecs; - } - CoreModuleSection &getCoreModuleSection() noexcept { return CoreModSec; } - const CoreModuleSection &getCoreModuleSection() const noexcept { - return CoreModSec; - } - std::vector<CoreInstanceSection> &getCoreInstanceSection() noexcept { - return CoreInstSec; - } - std::vector<CoreTypeSection> &getCoreTypeSection() noexcept { - return CoreTypeSec; - } - ComponentSection &getComponentSection() noexcept { return CompSec; } - const ComponentSection &getComponentSection() const noexcept { - return CompSec; - } - std::vector<InstanceSection> &getInstanceSection() noexcept { - return InstSec; - } - std::vector<AliasSection> &getAliasSection() noexcept { return AliasSec; } - std::vector<TypeSection> &getTypeSection() noexcept { return TySec; } - std::vector<CanonSection> &getCanonSection() noexcept { return CanonSec; } - StartSection &getStartSection() noexcept { return StartSec; } - std::vector<ImportSection> &getImportSection() noexcept { return ImSec; } - std::vector<ExportSection> &getExportSection() noexcept { return ExSec; } + std::vector<Section> &getSections() noexcept { return Secs; } + Span<const Section> getSections() const noexcept { return Secs; } private: /// \name Data of Module node. @@ -198,18 +156,8 @@ class Component { std::vector<Byte> Magic; std::vector<Byte> Version; std::vector<Byte> Layer; - std::vector<CustomSection> CustomSecs; - CoreModuleSection CoreModSec; - std::vector<CoreInstanceSection> CoreInstSec; - std::vector<CoreTypeSection> CoreTypeSec; - ComponentSection CompSec; - std::vector<InstanceSection> InstSec; - std::vector<AliasSection> AliasSec; - std::vector<TypeSection> TySec; - std::vector<CanonSection> CanonSec; - StartSection StartSec; - std::vector<ImportSection> ImSec; - std::vector<ExportSection> ExSec; + + std::vector<Section> Secs; /// @} }; diff --git a/include/ast/section.h b/include/ast/section.h index a492dcdc9991..c9d961c256d5 100644 --- a/include/ast/section.h +++ b/include/ast/section.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/ast/section.h - Section class definitions ----------------===// // @@ -70,13 +70,13 @@ class CustomSection : public Section { class TypeSection : public Section { public: /// Getter of content vector. - Span<const FunctionType> getContent() const noexcept { return Content; } - std::vector<FunctionType> &getContent() noexcept { return Content; } + Span<const SubType> getContent() const noexcept { return Content; } + std::vector<SubType> &getContent() noexcept { return Content; } private: /// \name Data of TypeSection. /// @{ - std::vector<FunctionType> Content; + std::vector<SubType> Content; /// @} }; @@ -223,7 +223,7 @@ class DataSection : public Section { /// AST DataCountSection node. class DataCountSection : public Section { public: - /// Getter and of content. + /// Getter and setter of content. std::optional<uint32_t> getContent() const noexcept { return Content; } void setContent(uint32_t Val) noexcept { Content = Val; } @@ -234,6 +234,20 @@ class DataCountSection : public Section { /// @} }; +/// AST TagSection node. +class TagSection : public Section { +public: + /// Getter of content vector. + Span<const TagType> getContent() const noexcept { return Content; } + std::vector<TagType> &getContent() noexcept { return Content; } + +private: + /// \name Data of TagSection. + /// @{ + std::vector<TagType> Content; + /// @} +}; + class AOTSection { public: /// Getter and setter of version. @@ -286,6 +300,7 @@ class AOTSection { std::vector<uintptr_t> CodesAddress; std::vector<std::tuple<uint8_t, uint64_t, uint64_t, std::vector<Byte>>> Sections; + std::vector<uint8_t> Bytecodes; /// @} }; @@ -372,13 +387,13 @@ class CanonSection : public Section { class StartSection : public Section { public: /// Getter of content module. - Span<const Start> getContent() const noexcept { return Content; } - std::vector<Start> &getContent() noexcept { return Content; } + const Start &getContent() const noexcept { return Content; } + Start &getContent() noexcept { return Content; } private: /// \name Data of StartSection. /// @{ - std::vector<Start> Content; + Start Content; /// @} }; @@ -411,18 +426,13 @@ class ExportSection : public Section { class Component; class ComponentSection : public Section { - public: /// Getter of content. - Span<const std::shared_ptr<Component>> getContent() const noexcept { - return Content; - } - std::vector<std::shared_ptr<Component>> &getContent() noexcept { - return Content; - } + const Component &getContent() const noexcept { return *Content; } + std::shared_ptr<Component> getContent() noexcept { return Content; } private: - std::vector<std::shared_ptr<Component>> Content; + std::shared_ptr<Component> Content; }; } // namespace Component diff --git a/include/ast/segment.h b/include/ast/segment.h index b0962de8de49..5241868713a9 100644 --- a/include/ast/segment.h +++ b/include/ast/segment.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/ast/segment.h - segment class definitions ----------------===// // diff --git a/include/ast/type.h b/include/ast/type.h index b9490e6776cb..258c5acbfbe4 100644 --- a/include/ast/type.h +++ b/include/ast/type.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/ast/type.h - type class definitions ----------------------===// // @@ -14,10 +14,12 @@ //===----------------------------------------------------------------------===// #pragma once +#include "common/executable.h" #include "common/span.h" #include "common/symbol.h" #include "common/types.h" +#include <optional> #include <vector> namespace WasmEdge { @@ -74,15 +76,12 @@ class Limit { /// AST FunctionType node. class FunctionType { public: - /// Function type wrapper for symbols. - using Wrapper = void(void *ExecCtx, void *Function, const ValVariant *Args, - ValVariant *Rets); - /// Constructors. - FunctionType() = default; - FunctionType(Span<const ValType> P, Span<const ValType> R) + FunctionType() noexcept = default; + FunctionType(Span<const ValType> P, Span<const ValType> R) noexcept : ParamTypes(P.begin(), P.end()), ReturnTypes(R.begin(), R.end()) {} - FunctionType(Span<const ValType> P, Span<const ValType> R, Symbol<Wrapper> S) + FunctionType(Span<const ValType> P, Span<const ValType> R, + Symbol<Executable::Wrapper> S) noexcept : ParamTypes(P.begin(), P.end()), ReturnTypes(R.begin(), R.end()), WrapSymbol(std::move(S)) {} @@ -112,17 +111,542 @@ class FunctionType { /// Getter and setter of symbol. const auto &getSymbol() const noexcept { return WrapSymbol; } - void setSymbol(Symbol<Wrapper> S) noexcept { WrapSymbol = std::move(S); } + void setSymbol(Symbol<Executable::Wrapper> S) noexcept { + WrapSymbol = std::move(S); + } private: /// \name Data of FunctionType. /// @{ std::vector<ValType> ParamTypes; std::vector<ValType> ReturnTypes; - Symbol<Wrapper> WrapSymbol; + Symbol<Executable::Wrapper> WrapSymbol; + /// @} +}; + +/// AST FieldType node for GC proposal. +class FieldType { +public: + /// Constructors. + FieldType() noexcept = default; + FieldType(const ValType &Type, ValMut Mut) noexcept : Type(Type), Mut(Mut) {} + + /// Getter and setter of storage type. + const ValType &getStorageType() const noexcept { return Type; } + void setStorageType(const ValType &VType) noexcept { Type = VType; } + + /// Getter and setter of value mutation. + ValMut getValMut() const noexcept { return Mut; } + void setValMut(ValMut VMut) noexcept { Mut = VMut; } + +private: + /// \name Data of FieldType. + /// @{ + ValType Type; + ValMut Mut; /// @} }; +/// AST CompositeType node for GC proposal. +class CompositeType { +public: + /// Constructors. + CompositeType() noexcept = default; + CompositeType(const FunctionType &FT) noexcept + : Type(TypeCode::Func), FType(FT) {} + + /// Getter of content. + const FunctionType &getFuncType() const noexcept { + return *std::get_if<FunctionType>(&FType); + } + FunctionType &getFuncType() noexcept { + return *std::get_if<FunctionType>(&FType); + } + const std::vector<FieldType> &getFieldTypes() const noexcept { + return *std::get_if<std::vector<FieldType>>(&FType); + } + + /// Setter of content. + void setArrayType(FieldType &&FT) noexcept { + Type = TypeCode::Array; + FType = std::vector<FieldType>{std::move(FT)}; + } + void setStructType(std::vector<FieldType> &&VFT) noexcept { + Type = TypeCode::Struct; + FType = std::move(VFT); + } + void setFunctionType(FunctionType &&FT) noexcept { + Type = TypeCode::Func; + FType = std::move(FT); + } + + /// Getter of content type. + TypeCode getContentTypeCode() const noexcept { return Type; } + + /// Checker if is a function type. + bool isFunc() const noexcept { return (Type == TypeCode::Func); } + + /// Expand the composite type to its reference. + TypeCode expand() const noexcept { + switch (Type) { + case TypeCode::Func: + return TypeCode::FuncRef; + case TypeCode::Struct: + return TypeCode::StructRef; + case TypeCode::Array: + return TypeCode::ArrayRef; + default: + assumingUnreachable(); + } + } + +private: + /// \name Data of CompositeType. + /// @{ + TypeCode Type; + std::variant<std::vector<FieldType>, FunctionType> FType; + /// @} +}; + +/// AST SubType node for GC proposal. +class SubType { +public: + /// Constructors. + SubType() noexcept = default; + SubType(const FunctionType &FT) noexcept + : IsFinal(true), CompType(FT), RecTypeInfo(std::nullopt), + TypeIndex(std::nullopt) {} + + /// Getter and setter of final flag. + bool isFinal() const noexcept { return IsFinal; } + void setFinal(bool F) noexcept { IsFinal = F; } + + /// Getter of type index vector. + Span<const uint32_t> getSuperTypeIndices() const noexcept { + return SuperTypeIndices; + } + std::vector<uint32_t> &getSuperTypeIndices() noexcept { + return SuperTypeIndices; + } + + /// Getter of composite type. + const CompositeType &getCompositeType() const noexcept { return CompType; } + CompositeType &getCompositeType() noexcept { return CompType; } + + /// Recursive type information. + struct RecInfo { + uint32_t Index; + uint32_t RecTypeSize; + }; + + /// Getter of recursive type information. + std::optional<RecInfo> getRecursiveInfo() const noexcept { + return RecTypeInfo; + } + void setRecursiveInfo(uint32_t Index, uint32_t Size) noexcept { + RecTypeInfo = RecInfo{Index, Size}; + } + + /// Getter of type index information in a module. + std::optional<uint32_t> getTypeIndex() const noexcept { return TypeIndex; } + void setTypeIndex(uint32_t Index) noexcept { TypeIndex = Index; } + +private: + /// \name Data of CompositeType. + /// @{ + /// Is final. + bool IsFinal; + /// List of super type indices. + std::vector<uint32_t> SuperTypeIndices; + /// Content of composite type. + CompositeType CompType; + /// @} + + /// \name Information for defined types. + /// @{ + /// Recursive type information. Record the index in the recursive type. + std::optional<RecInfo> RecTypeInfo; + /// Type index in the module. Record for backward iteration. + std::optional<uint32_t> TypeIndex; + /// @} +}; + +/// AST Type match helper class. +class TypeMatcher { +public: + /// Validator: Match 2 defined types in the same module. + static bool matchType(Span<const SubType *const> TypeList, uint32_t ExpIdx, + uint32_t GotIdx) noexcept { + return matchType(TypeList, ExpIdx, TypeList, GotIdx); + } + + /// Validator: Match 2 composite types in the same module. + static bool matchType(Span<const SubType *const> TypeList, + const CompositeType &Exp, + const CompositeType &Got) noexcept { + auto isFieldTypeMatched = [&](const FieldType &ExpFieldType, + const FieldType &GotFieldType) -> bool { + bool IsMatch = false; + if (ExpFieldType.getValMut() == GotFieldType.getValMut()) { + // For both const or both var: Got storage type should match the + // expected storage type. + IsMatch = matchType(TypeList, ExpFieldType.getStorageType(), + GotFieldType.getStorageType()); + if (ExpFieldType.getValMut() == ValMut::Var) { + // If both var: and vice versa. + IsMatch &= matchType(TypeList, GotFieldType.getStorageType(), + ExpFieldType.getStorageType()); + } + } + return IsMatch; + }; + + if (Exp.getContentTypeCode() != Got.getContentTypeCode()) { + return false; + } + switch (Exp.getContentTypeCode()) { + case TypeCode::Func: { + const auto &ExpFType = Exp.getFuncType(); + const auto &GotFType = Got.getFuncType(); + return matchTypes(TypeList, GotFType.getParamTypes(), + ExpFType.getParamTypes()) && + matchTypes(TypeList, ExpFType.getReturnTypes(), + GotFType.getReturnTypes()); + } + case TypeCode::Struct: { + const auto &ExpFType = Exp.getFieldTypes(); + const auto &GotFType = Got.getFieldTypes(); + if (GotFType.size() < ExpFType.size()) { + return false; + } + for (uint32_t I = 0; I < ExpFType.size(); I++) { + if (!isFieldTypeMatched(ExpFType[I], GotFType[I])) { + return false; + } + } + return true; + } + case TypeCode::Array: { + const auto &ExpFType = Exp.getFieldTypes(); + const auto &GotFType = Got.getFieldTypes(); + return isFieldTypeMatched(ExpFType[0], GotFType[0]); + } + default: + return false; + } + } + + /// Validator: Match 2 value types in the same module. + static bool matchType(Span<const SubType *const> TypeList, const ValType &Exp, + const ValType &Got) noexcept { + return matchType(TypeList, Exp, TypeList, Got); + } + + /// Validator: Match 2 type lists in the same module. + static bool matchTypes(Span<const SubType *const> TypeList, + Span<const ValType> Exp, + Span<const ValType> Got) noexcept { + if (Exp.size() != Got.size()) { + return false; + } + for (uint32_t I = 0; I < Exp.size(); I++) { + if (!matchType(TypeList, Exp[I], Got[I])) { + return false; + } + } + return true; + } + + /// Matcher: Match 2 defined types. + static bool matchType(Span<const SubType *const> ExpTypeList, uint32_t ExpIdx, + Span<const SubType *const> GotTypeList, + uint32_t GotIdx) noexcept { + if (ExpIdx >= ExpTypeList.size() || GotIdx >= GotTypeList.size()) { + return false; + } + if (isDefTypeEqual(ExpTypeList, ExpIdx, GotTypeList, GotIdx)) { + return true; + } + const auto *GotType = GotTypeList[GotIdx]; + for (auto TIdx : GotType->getSuperTypeIndices()) { + if (matchType(ExpTypeList, ExpIdx, GotTypeList, TIdx)) { + return true; + } + } + return false; + } + + /// Matcher: Match 2 value types. + static bool matchType(Span<const SubType *const> ExpTypeList, + const ValType &Exp, + Span<const SubType *const> GotTypeList, + const ValType &Got) noexcept { + if (!Exp.isRefType() && !Got.isRefType() && + Exp.getCode() == Got.getCode()) { + // Match for the non-reference type case. + return true; + } + if (Exp.isRefType() && Got.isRefType()) { + // Nullable matching. + if (!Exp.isNullableRefType() && Got.isNullableRefType()) { + return false; + } + + // Match heap type. + if (Exp.isAbsHeapType() && Got.isAbsHeapType()) { + // Case 1: Both abstract heap type. + return matchTypeCode(Exp.getHeapTypeCode(), Got.getHeapTypeCode()); + } else if (Exp.isAbsHeapType()) { + // Case 2: Match a type index to abstract heap type. + if (Got.getTypeIndex() >= GotTypeList.size()) { + return false; + } + return matchTypeCode( + Exp.getHeapTypeCode(), + GotTypeList[Got.getTypeIndex()]->getCompositeType().expand()); + } else if (Got.isAbsHeapType()) { + // Case 3: Match abstract heap type to a type index. + if (Exp.getTypeIndex() >= ExpTypeList.size()) { + return false; + } + TypeCode ExpandGotType = + ExpTypeList[Exp.getTypeIndex()]->getCompositeType().expand(); + switch (Got.getHeapTypeCode()) { + case TypeCode::NullRef: + return matchTypeCode(TypeCode::AnyRef, ExpandGotType); + case TypeCode::NullFuncRef: + return matchTypeCode(TypeCode::FuncRef, ExpandGotType); + case TypeCode::NullExternRef: + return matchTypeCode(TypeCode::ExternRef, ExpandGotType); + default: + return false; + } + } else { + // Case 4: Match defined types. + return matchType(ExpTypeList, Exp.getTypeIndex(), GotTypeList, + Got.getTypeIndex()); + } + } + return false; + } + +private: + /// Matcher: Helper for checking the equivalent of 2 defined types. + static bool isDefTypeEqual(Span<const SubType *const> LHSList, + uint32_t LHSIdx, + Span<const SubType *const> RHSList, + uint32_t RHSIdx) { + if (LHSList.data() == RHSList.data() && LHSIdx == RHSIdx) { + // Two type indices in the same module are the same. + return true; + } + const auto *LHSType = LHSList[LHSIdx]; + const auto *RHSType = RHSList[RHSIdx]; + // For GC proposal, a single subtype can be seemed as a self-recursive type. + // That is, `(rec (type $t1 (func (param (ref $t1)))))` and + // `(type $t1 (func (param (ref $t1))))` are the same. + // Therefore, use the subtype length for the recursive type size. + const uint32_t LRecSize = LHSType->getRecursiveInfo().has_value() + ? LHSType->getRecursiveInfo()->RecTypeSize + : 1U; + const uint32_t RRecSize = RHSType->getRecursiveInfo().has_value() + ? RHSType->getRecursiveInfo()->RecTypeSize + : 1U; + if (LRecSize != RRecSize) { + // 2 recursive type sizes are different. Must not be the same. + return false; + } + if (LRecSize > 1) { + // Both are in a recursive type with > 1 subtypes. + if (LHSType->getRecursiveInfo()->Index != + RHSType->getRecursiveInfo()->Index) { + // The recursive indices should be the same. + return false; + } + // The recursive types should be the same. + uint32_t LStartIdx = LHSIdx - LHSType->getRecursiveInfo()->Index; + uint32_t RStartIdx = RHSIdx - RHSType->getRecursiveInfo()->Index; + return isRecTypeEqual(LHSList, LStartIdx, RHSList, RStartIdx, LRecSize); + } else { + // Both are composite types or self-recursive types. + return isRecTypeEqual(LHSList, LHSIdx, RHSList, RHSIdx, 1); + } + } + + /// Matcher: Helper for checking the equivalent of 2 recursive types. + static bool isRecTypeEqual(Span<const SubType *const> LHSList, + uint32_t LStartIdx, + Span<const SubType *const> RHSList, + uint32_t RStartIdx, uint32_t RecSize) { + + auto isValTypeEqual = [&](const ValType <ype, + const ValType &RType) -> bool { + if (LType.getHeapTypeCode() == TypeCode::TypeIndex && + RType.getHeapTypeCode() == TypeCode::TypeIndex) { + if (LType.getCode() != RType.getCode()) { + return false; + } + // Check the index is the recursive type internal index or not. + auto LIdx = LType.getTypeIndex(); + auto RIdx = RType.getTypeIndex(); + assuming(LIdx < LHSList.size() && RIdx < RHSList.size()); + bool IsLInSelfRecType = + (LIdx >= LStartIdx && LIdx < LStartIdx + RecSize); + bool IsRInSelfRecType = + (RIdx >= RStartIdx && RIdx < RStartIdx + RecSize); + if (IsLInSelfRecType != IsRInSelfRecType) { + // If the one index is the recursive type internal index but the other + // isn't, the value types must be different. + return false; + } + if (IsLInSelfRecType) { + // For both are internal indices of the recursive types, the internal + // indices must be the same. + if (LIdx - LStartIdx == RIdx - RStartIdx) { + return true; + } else { + return false; + } + } + // For neither are internal indices, keep checking the equivalent of the + // defined types. + return isDefTypeEqual(LHSList, LIdx, RHSList, RIdx); + } else { + return (LType.getCode() == RType.getCode() && + LType.getHeapTypeCode() == RType.getHeapTypeCode()); + } + }; + + auto isFieldTypeEqual = + [isValTypeEqual](const std::vector<FieldType> &LFieldTypes, + const std::vector<FieldType> &RFieldTypes) -> bool { + if (LFieldTypes.size() != RFieldTypes.size()) { + return false; + } + for (uint32_t I = 0; I < LFieldTypes.size(); I++) { + if (LFieldTypes[I].getValMut() != RFieldTypes[I].getValMut()) { + return false; + } + if (!isValTypeEqual(LFieldTypes[I].getStorageType(), + RFieldTypes[I].getStorageType())) { + return false; + } + } + return true; + }; + + auto isFuncTypeEqual = + [isValTypeEqual](const FunctionType &LFuncType, + const FunctionType &RFuncType) -> bool { + auto &LPTypes = LFuncType.getParamTypes(); + auto &LRTypes = LFuncType.getReturnTypes(); + auto &RPTypes = RFuncType.getParamTypes(); + auto &RRTypes = RFuncType.getReturnTypes(); + if (LPTypes.size() != RPTypes.size() || + LRTypes.size() != RRTypes.size()) { + return false; + } + for (uint32_t I = 0; I < LPTypes.size(); I++) { + if (!isValTypeEqual(LPTypes[I], RPTypes[I])) { + return false; + } + } + for (uint32_t I = 0; I < LRTypes.size(); I++) { + if (!isValTypeEqual(LRTypes[I], RRTypes[I])) { + return false; + } + } + return true; + }; + + auto isCompTypeEqual = [isFuncTypeEqual, isFieldTypeEqual]( + const CompositeType &LCompType, + const CompositeType &RCompType) -> bool { + if (LCompType.expand() != RCompType.expand()) { + return false; + } + switch (LCompType.expand()) { + case TypeCode::FuncRef: + return isFuncTypeEqual(LCompType.getFuncType(), + RCompType.getFuncType()); + case TypeCode::StructRef: + case TypeCode::ArrayRef: + return isFieldTypeEqual(LCompType.getFieldTypes(), + RCompType.getFieldTypes()); + default: + assumingUnreachable(); + } + }; + + for (uint32_t I = 0; I < RecSize; I++) { + // Every subtype in the recursive types should be equivalent. + const auto *LHSType = LHSList[LStartIdx + I]; + const auto *RHSType = RHSList[RStartIdx + I]; + if (LHSType->isFinal() != RHSType->isFinal()) { + return false; + } + auto LSuperTypes = LHSType->getSuperTypeIndices(); + auto RSuperTypes = RHSType->getSuperTypeIndices(); + if (LSuperTypes.size() != RSuperTypes.size()) { + return false; + } + // TODO: GC - Fix the subtype matching. + uint32_t SuperTypesSize = static_cast<uint32_t>(LSuperTypes.size()); + for (uint32_t J = 0; J < SuperTypesSize; J++) { + if (!isValTypeEqual(ValType(TypeCode::Ref, LSuperTypes[J]), + ValType(TypeCode::Ref, RSuperTypes[J]))) { + return false; + } + } + if (!isCompTypeEqual(LHSType->getCompositeType(), + RHSType->getCompositeType())) { + return false; + } + } + return true; + } + + /// Matcher: Helper for matching 2 type codes. + static bool matchTypeCode(TypeCode Exp, TypeCode Got) noexcept { + // Handle the equal cases first. + if (Exp == Got) { + return true; + } + + // Match the func types: nofunc <= func + if (Exp == TypeCode::FuncRef || Exp == TypeCode::NullFuncRef) { + return Got == TypeCode::NullFuncRef; + } + if (Got == TypeCode::FuncRef || Got == TypeCode::NullFuncRef) { + return false; + } + + // Match the extern types: noextern <= extern + if (Exp == TypeCode::ExternRef || Exp == TypeCode::NullExternRef) { + return Got == TypeCode::NullExternRef; + } + if (Got == TypeCode::ExternRef || Got == TypeCode::NullExternRef) { + return false; + } + + // Match the other types: none <= i31 | struct | array <= eq <= any + switch (Exp) { + case TypeCode::I31Ref: + case TypeCode::StructRef: + case TypeCode::ArrayRef: + // This will filter out the i31/struct/array unmatch cases. + return Got == TypeCode::NullRef; + case TypeCode::EqRef: + return Got != TypeCode::AnyRef; + case TypeCode::AnyRef: + return true; + default: + break; + } + return false; + } +}; + /// AST MemoryType node. class MemoryType { public: @@ -207,5 +731,59 @@ class GlobalType { /// @} }; +class TagType { +public: + TagType() = default; + TagType(const uint32_t TIdx, const SubType *S) noexcept + : TypeIdx(TIdx), Type(S) {} + + /// Getter and setter of TypeIdx. + uint32_t getTypeIdx() const noexcept { return TypeIdx; } + void setTypeIdx(uint32_t TIdx) noexcept { TypeIdx = TIdx; } + + // Getter and setter of Defined Type. + const SubType &getDefType() const noexcept { return *Type; } + void setDefType(const SubType *DefType) noexcept { Type = DefType; } + + // Getter of the size of value that is associated with the tag. + uint32_t getAssocValSize() const noexcept { + if (Type && Type->getCompositeType().isFunc()) { + return static_cast<uint32_t>( + Type->getCompositeType().getFuncType().getParamTypes().size()); + } else { + return 0; + } + } + +private: + uint32_t TypeIdx; + const SubType *Type; +}; + } // namespace AST } // namespace WasmEdge + +template <> +struct fmt::formatter<WasmEdge::AST::FunctionType> + : fmt::formatter<std::string_view> { + fmt::format_context::iterator + format(const WasmEdge::AST::FunctionType &Type, + fmt::format_context &Ctx) const noexcept { + using namespace std::literals; + + fmt::memory_buffer Buffer; + + fmt::format_to(std::back_inserter(Buffer), "[ "sv); + for (auto &P : Type.getParamTypes()) { + fmt::format_to(std::back_inserter(Buffer), "{} "sv, P); + } + fmt::format_to(std::back_inserter(Buffer), "] -> [ "sv); + for (auto &R : Type.getReturnTypes()) { + fmt::format_to(std::back_inserter(Buffer), "{} "sv, R); + } + fmt::format_to(std::back_inserter(Buffer), "]"sv); + + return formatter<std::string_view>::format( + std::string_view(Buffer.data(), Buffer.size()), Ctx); + } +}; diff --git a/include/common/async.h b/include/common/async.h index 11d4c31a85ef..5b441d141452 100644 --- a/include/common/async.h +++ b/include/common/async.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/async.h - Asynchronous execution class definition -===// // diff --git a/include/common/config.h.in b/include/common/config.h.in index 13e1f38db2b0..f9df32d8cd0b 100644 --- a/include/common/config.h.in +++ b/include/common/config.h.in @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/config.h - Configure information ------------------===// // diff --git a/include/common/configure.h b/include/common/configure.h index add57945b5c2..b063071a2036 100644 --- a/include/common/configure.h +++ b/include/common/configure.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/configure.h - Configuration class -----------------===// // @@ -114,6 +114,7 @@ class RuntimeConfigure { RuntimeConfigure() noexcept = default; RuntimeConfigure(const RuntimeConfigure &RHS) noexcept : MaxMemPage(RHS.MaxMemPage.load(std::memory_order_relaxed)), + EnableJIT(RHS.EnableJIT.load(std::memory_order_relaxed)), ForceInterpreter(RHS.ForceInterpreter.load(std::memory_order_relaxed)), AllowAFUNIX(RHS.AllowAFUNIX.load(std::memory_order_relaxed)) {} @@ -125,6 +126,14 @@ class RuntimeConfigure { return MaxMemPage.load(std::memory_order_relaxed); } + void setEnableJIT(bool IsEnableJIT) noexcept { + EnableJIT.store(IsEnableJIT, std::memory_order_relaxed); + } + + bool isEnableJIT() const noexcept { + return EnableJIT.load(std::memory_order_relaxed); + } + void setForceInterpreter(bool IsForceInterpreter) noexcept { ForceInterpreter.store(IsForceInterpreter, std::memory_order_relaxed); } @@ -143,6 +152,7 @@ class RuntimeConfigure { private: std::atomic<uint32_t> MaxMemPage = 65536; + std::atomic<bool> EnableJIT = false; std::atomic<bool> ForceInterpreter = false; std::atomic<bool> AllowAFUNIX = false; }; @@ -221,6 +231,18 @@ class Configure { void removeProposal(const Proposal Type) noexcept { std::unique_lock Lock(Mutex); + if (Type == Proposal::FunctionReferences && + Proposals.test(static_cast<uint8_t>(Proposal::GC))) { + // Proposal dependency: GC depends FunctionReferences. + return; + } + if (Type == Proposal::ReferenceTypes && + (Proposals.test(static_cast<uint8_t>(Proposal::GC)) || + Proposals.test(static_cast<uint8_t>(Proposal::FunctionReferences)))) { + // Proposal dependency: GC and FunctionReferences depend on + // ReferenceTypes. + return; + } Proposals.reset(static_cast<uint8_t>(Type)); } @@ -307,6 +329,12 @@ class Configure { if (!hasProposal(Proposal::SIMD)) { return Proposal::SIMD; } + } else if (Code >= OpCode::I8x16__relaxed_swizzle && + Code <= OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s) { + // These instructions are for Relaxed SIMD proposal. + if (!hasProposal(Proposal::RelaxSIMD)) { + return Proposal::RelaxSIMD; + } } else if (Code == OpCode::Return_call || Code == OpCode::Return_call_indirect) { // These instructions are for TailCall proposal. @@ -329,6 +357,20 @@ class Configure { if (Code == OpCode::Return_call_ref && !hasProposal(Proposal::TailCall)) { return Proposal::TailCall; } + } else if (Code == OpCode::Ref__eq || + (Code >= OpCode::Struct__new && Code <= OpCode::I31__get_u)) { + // These instructions are for GC proposal. + if (!hasProposal(Proposal::GC)) { + return Proposal::GC; + } + } else if ((Code >= OpCode::Try && Code <= OpCode::Throw_ref) || + Code == OpCode::Delegate || Code == OpCode::Catch_all || + Code == OpCode::Try_table) { + // LEGACY-EH: remove the old instructions after deprecating legacy EH. + // These instructions are for ExceptionHandling proposal. + if (!hasProposal(Proposal::ExceptionHandling)) { + return Proposal::ExceptionHandling; + } } return {}; } @@ -341,6 +383,15 @@ class Configure { void unsafeAddProposal(const Proposal Type) noexcept { Proposals.set(static_cast<uint8_t>(Type)); + // Proposal dependency: FunctionReferences depends on ReferenceTypes. + if (Type == Proposal::FunctionReferences) { + Proposals.set(static_cast<uint8_t>(Proposal::ReferenceTypes)); + } + // Proposal dependency: GC depends on FunctionReferences and ReferenceTypes. + if (Type == Proposal::GC) { + Proposals.set(static_cast<uint8_t>(Proposal::FunctionReferences)); + Proposals.set(static_cast<uint8_t>(Proposal::ReferenceTypes)); + } } void unsafeAddHostRegistration(const HostRegistration Host) noexcept { diff --git a/include/common/defines.h b/include/common/defines.h index 96e358a8722d..f849b7b06988 100644 --- a/include/common/defines.h +++ b/include/common/defines.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/defines.h - General defines -----------------------===// // @@ -19,6 +19,7 @@ #define WASMEDGE_OS_LINUX 1 #define WASMEDGE_OS_MACOS 0 #define WASMEDGE_OS_WINDOWS 0 +#define WASMEDGE_LIB_PREFIX "lib" #define WASMEDGE_LIB_EXTENSION ".so" #elif defined(macintosh) || defined(Macintosh) || \ @@ -27,6 +28,7 @@ #define WASMEDGE_OS_LINUX 0 #define WASMEDGE_OS_MACOS 1 #define WASMEDGE_OS_WINDOWS 0 +#define WASMEDGE_LIB_PREFIX "lib" #define WASMEDGE_LIB_EXTENSION ".dylib" #elif defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || \ @@ -35,6 +37,7 @@ #define WASMEDGE_OS_LINUX 0 #define WASMEDGE_OS_MACOS 0 #define WASMEDGE_OS_WINDOWS 1 +#define WASMEDGE_LIB_PREFIX "" #define WASMEDGE_LIB_EXTENSION ".dll" #else diff --git a/include/common/dense_enum_map.h b/include/common/dense_enum_map.h index 361b3d5cef2d..97032f17c6d2 100644 --- a/include/common/dense_enum_map.h +++ b/include/common/dense_enum_map.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/dense_enum_map.h - mapping dense enum to data -----===// // diff --git a/include/common/endian.h b/include/common/endian.h index b1040addfce4..2d7f21221771 100644 --- a/include/common/endian.h +++ b/include/common/endian.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/endian.h - endian detect helper -------------------===// // diff --git a/include/common/enum.inc b/include/common/enum.inc index 33c376b4d55b..c38809c776bd 100644 --- a/include/common/enum.inc +++ b/include/common/enum.inc @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/enum.inc - Enumerations ---------------------------===// // @@ -59,6 +59,7 @@ A(Sec_Element, "element section") A(Sec_Code, "code section") A(Sec_Data, "data section") A(Sec_DataCount, "data count section") +A(Sec_Tag, "tag section") A(Desc_Import, "import description") A(Desc_Export, "export description") A(Seg_Table, "table segment") @@ -67,6 +68,8 @@ A(Seg_Element, "element segment") A(Seg_Code, "code segment") A(Seg_Data, "data segment") A(Type_Module, "module type") +A(Type_Rec, "recursive type") +A(Type_Sub, "sub type") A(Type_Limit, "limit") A(Type_Function, "function type") A(Type_Memory, "memory type") @@ -83,593 +86,694 @@ A(Sec_AOT, "aot section") #ifdef UseOpCode #define O Line +#define OFB Line_FB +#define OFC Line_FC +#define OFD Line_FD +#define OFE Line_FE + +// OpCode: +// NAME | STRING | CODE [ | EXTEND ] // Control instructions (part 1) -O(Unreachable, 0x00, "unreachable") -O(Nop, 0x01, "nop") -O(Block, 0x02, "block") -O(Loop, 0x03, "loop") -O(If, 0x04, "if") -O(Else, 0x05, "else") -O(End, 0x0B, "end") -O(Br, 0x0C, "br") -O(Br_if, 0x0D, "br_if") -O(Br_table, 0x0E, "br_table") -O(Return, 0x0F, "return") -O(Call, 0x10, "call") -O(Call_indirect, 0x11, "call_indirect") -O(Return_call, 0x12, "return_call") -O(Return_call_indirect, 0x13, "return_call_indirect") -O(Call_ref, 0x14, "call_ref") -O(Return_call_ref, 0x15, "return_call_ref") +O(Unreachable, "unreachable", 0x00) +O(Nop, "nop", 0x01) +O(Block, "block", 0x02) +O(Loop, "loop", 0x03) +O(If, "if", 0x04) +O(Else, "else", 0x05) +O(Try, "try", 0x06) // For legacy EH proposal +O(Catch, "catch", 0x07) // For legacy EH proposal +O(Throw, "throw", 0x08) +O(Rethrow, "rethrow", 0x09) // For legacy EH proposal +O(Throw_ref, "throw_ref", 0x0A) +O(End, "end", 0x0B) +O(Br, "br", 0x0C) +O(Br_if, "br_if", 0x0D) +O(Br_table, "br_table", 0x0E) +O(Return, "return", 0x0F) +O(Call, "call", 0x10) +O(Call_indirect, "call_indirect", 0x11) +O(Return_call, "return_call", 0x12) +O(Return_call_indirect, "return_call_indirect", 0x13) +O(Call_ref, "call_ref", 0x14) +O(Return_call_ref, "return_call_ref", 0x15) +// 0x16: Reserved +// 0x17: Reserved +O(Delegate, "delegate", 0x18) // For legacy EH proposal +O(Catch_all, "catch_all", 0x19) // For legacy EH proposal // Parametric Instructions -O(Drop, 0x1A, "drop") -O(Select, 0x1B, "select") -O(Select_t, 0x1C, "select") +O(Drop, "drop", 0x1A) +O(Select, "select", 0x1B) +O(Select_t, "select", 0x1C) +// 0x1D: Reserved +// 0x1E: Reserved + +// Control instructions (part 2) +O(Try_table, "try_table", 0x1F) // Variable Instructions -O(Local__get, 0x20, "local.get") -O(Local__set, 0x21, "local.set") -O(Local__tee, 0x22, "local.tee") -O(Global__get, 0x23, "global.get") -O(Global__set, 0x24, "global.set") +O(Local__get, "local.get", 0x20) +O(Local__set, "local.set", 0x21) +O(Local__tee, "local.tee", 0x22) +O(Global__get, "global.get", 0x23) +O(Global__set, "global.set", 0x24) // Table Instructions (part 1) -O(Table__get, 0x25, "table.get") -O(Table__set, 0x26, "table.set") +O(Table__get, "table.get", 0x25) +O(Table__set, "table.set", 0x26) +// 0x27: Reserved // Memory Instructions (part 1) -O(I32__load, 0x28, "i32.load") -O(I64__load, 0x29, "i64.load") -O(F32__load, 0x2A, "f32.load") -O(F64__load, 0x2B, "f64.load") -O(I32__load8_s, 0x2C, "i32.load8_s") -O(I32__load8_u, 0x2D, "i32.load8_u") -O(I32__load16_s, 0x2E, "i32.load16_s") -O(I32__load16_u, 0x2F, "i32.load16_u") -O(I64__load8_s, 0x30, "i64.load8_s") -O(I64__load8_u, 0x31, "i64.load8_u") -O(I64__load16_s, 0x32, "i64.load16_s") -O(I64__load16_u, 0x33, "i64.load16_u") -O(I64__load32_s, 0x34, "i64.load32_s") -O(I64__load32_u, 0x35, "i64.load32_u") -O(I32__store, 0x36, "i32.store") -O(I64__store, 0x37, "i64.store") -O(F32__store, 0x38, "f32.store") -O(F64__store, 0x39, "f64.store") -O(I32__store8, 0x3A, "i32.store8") -O(I32__store16, 0x3B, "i32.store16") -O(I64__store8, 0x3C, "i64.store8") -O(I64__store16, 0x3D, "i64.store16") -O(I64__store32, 0x3E, "i64.store32") -O(Memory__size, 0x3F, "memory.size") -O(Memory__grow, 0x40, "memory.grow") +O(I32__load, "i32.load", 0x28) +O(I64__load, "i64.load", 0x29) +O(F32__load, "f32.load", 0x2A) +O(F64__load, "f64.load", 0x2B) +O(I32__load8_s, "i32.load8_s", 0x2C) +O(I32__load8_u, "i32.load8_u", 0x2D) +O(I32__load16_s, "i32.load16_s", 0x2E) +O(I32__load16_u, "i32.load16_u", 0x2F) +O(I64__load8_s, "i64.load8_s", 0x30) +O(I64__load8_u, "i64.load8_u", 0x31) +O(I64__load16_s, "i64.load16_s", 0x32) +O(I64__load16_u, "i64.load16_u", 0x33) +O(I64__load32_s, "i64.load32_s", 0x34) +O(I64__load32_u, "i64.load32_u", 0x35) +O(I32__store, "i32.store", 0x36) +O(I64__store, "i64.store", 0x37) +O(F32__store, "f32.store", 0x38) +O(F64__store, "f64.store", 0x39) +O(I32__store8, "i32.store8", 0x3A) +O(I32__store16, "i32.store16", 0x3B) +O(I64__store8, "i64.store8", 0x3C) +O(I64__store16, "i64.store16", 0x3D) +O(I64__store32, "i64.store32", 0x3E) +O(Memory__size, "memory.size", 0x3F) +O(Memory__grow, "memory.grow", 0x40) // Const numeric instructions -O(I32__const, 0x41, "i32.const") -O(I64__const, 0x42, "i64.const") -O(F32__const, 0x43, "f32.const") -O(F64__const, 0x44, "f64.const") +O(I32__const, "i32.const", 0x41) +O(I64__const, "i64.const", 0x42) +O(F32__const, "f32.const", 0x43) +O(F64__const, "f64.const", 0x44) // Numeric instructions -O(I32__eqz, 0x45, "i32.eqz") -O(I32__eq, 0x46, "i32.eq") -O(I32__ne, 0x47, "i32.ne") -O(I32__lt_s, 0x48, "i32.lt_s") -O(I32__lt_u, 0x49, "i32.lt_u") -O(I32__gt_s, 0x4A, "i32.gt_s") -O(I32__gt_u, 0x4B, "i32.gt_u") -O(I32__le_s, 0x4C, "i32.le_s") -O(I32__le_u, 0x4D, "i32.le_u") -O(I32__ge_s, 0x4E, "i32.ge_s") -O(I32__ge_u, 0x4F, "i32.ge_u") -O(I64__eqz, 0x50, "i64.eqz") -O(I64__eq, 0x51, "i64.eq") -O(I64__ne, 0x52, "i64.ne") -O(I64__lt_s, 0x53, "i64.lt_s") -O(I64__lt_u, 0x54, "i64.lt_u") -O(I64__gt_s, 0x55, "i64.gt_s") -O(I64__gt_u, 0x56, "i64.gt_u") -O(I64__le_s, 0x57, "i64.le_s") -O(I64__le_u, 0x58, "i64.le_u") -O(I64__ge_s, 0x59, "i64.ge_s") -O(I64__ge_u, 0x5A, "i64.ge_u") -O(F32__eq, 0x5B, "f32.eq") -O(F32__ne, 0x5C, "f32.ne") -O(F32__lt, 0x5D, "f32.lt") -O(F32__gt, 0x5E, "f32.gt") -O(F32__le, 0x5F, "f32.le") -O(F32__ge, 0x60, "f32.ge") -O(F64__eq, 0x61, "f64.eq") -O(F64__ne, 0x62, "f64.ne") -O(F64__lt, 0x63, "f64.lt") -O(F64__gt, 0x64, "f64.gt") -O(F64__le, 0x65, "f64.le") -O(F64__ge, 0x66, "f64.ge") -O(I32__clz, 0x67, "i32.clz") -O(I32__ctz, 0x68, "i32.ctz") -O(I32__popcnt, 0x69, "i32.popcnt") -O(I32__add, 0x6A, "i32.add") -O(I32__sub, 0x6B, "i32.sub") -O(I32__mul, 0x6C, "i32.mul") -O(I32__div_s, 0x6D, "i32.div_s") -O(I32__div_u, 0x6E, "i32.div_u") -O(I32__rem_s, 0x6F, "i32.rem_s") -O(I32__rem_u, 0x70, "i32.rem_u") -O(I32__and, 0x71, "i32.and") -O(I32__or, 0x72, "i32.or") -O(I32__xor, 0x73, "i32.xor") -O(I32__shl, 0x74, "i32.shl") -O(I32__shr_s, 0x75, "i32.shr_s") -O(I32__shr_u, 0x76, "i32.shr_u") -O(I32__rotl, 0x77, "i32.rotl") -O(I32__rotr, 0x78, "i32.rotr") -O(I64__clz, 0x79, "i64.clz") -O(I64__ctz, 0x7a, "i64.ctz") -O(I64__popcnt, 0x7b, "i64.popcnt") -O(I64__add, 0x7c, "i64.add") -O(I64__sub, 0x7d, "i64.sub") -O(I64__mul, 0x7e, "i64.mul") -O(I64__div_s, 0x7f, "i64.div_s") -O(I64__div_u, 0x80, "i64.div_u") -O(I64__rem_s, 0x81, "i64.rem_s") -O(I64__rem_u, 0x82, "i64.rem_u") -O(I64__and, 0x83, "i64.and") -O(I64__or, 0x84, "i64.or") -O(I64__xor, 0x85, "i64.xor") -O(I64__shl, 0x86, "i64.shl") -O(I64__shr_s, 0x87, "i64.shr_s") -O(I64__shr_u, 0x88, "i64.shr_u") -O(I64__rotl, 0x89, "i64.rotl") -O(I64__rotr, 0x8A, "i64.rotr") -O(F32__abs, 0x8B, "f32.abs") -O(F32__neg, 0x8C, "f32.neg") -O(F32__ceil, 0x8D, "f32.ceil") -O(F32__floor, 0x8E, "f32.floor") -O(F32__trunc, 0x8F, "f32.trunc") -O(F32__nearest, 0x90, "f32.nearest") -O(F32__sqrt, 0x91, "f32.sqrt") -O(F32__add, 0x92, "f32.add") -O(F32__sub, 0x93, "f32.sub") -O(F32__mul, 0x94, "f32.mul") -O(F32__div, 0x95, "f32.div") -O(F32__min, 0x96, "f32.min") -O(F32__max, 0x97, "f32.max") -O(F32__copysign, 0x98, "f32.copysign") -O(F64__abs, 0x99, "f64.abs") -O(F64__neg, 0x9A, "f64.neg") -O(F64__ceil, 0x9B, "f64.ceil") -O(F64__floor, 0x9C, "f64.floor") -O(F64__trunc, 0x9D, "f64.trunc") -O(F64__nearest, 0x9E, "f64.nearest") -O(F64__sqrt, 0x9F, "f64.sqrt") -O(F64__add, 0xA0, "f64.add") -O(F64__sub, 0xA1, "f64.sub") -O(F64__mul, 0xA2, "f64.mul") -O(F64__div, 0xA3, "f64.div") -O(F64__min, 0xA4, "f64.min") -O(F64__max, 0xA5, "f64.max") -O(F64__copysign, 0xA6, "f64.copysign") -O(I32__wrap_i64, 0xA7, "i32.wrap_i64") -O(I32__trunc_f32_s, 0xA8, "i32.trunc_f32_s") -O(I32__trunc_f32_u, 0xA9, "i32.trunc_f32_u") -O(I32__trunc_f64_s, 0xAA, "i32.trunc_f64_s") -O(I32__trunc_f64_u, 0xAB, "i32.trunc_f64_u") -O(I64__extend_i32_s, 0xAC, "i64.extend_i32_s") -O(I64__extend_i32_u, 0xAD, "i64.extend_i32_u") -O(I64__trunc_f32_s, 0xAE, "i64.trunc_f32_s") -O(I64__trunc_f32_u, 0xAF, "i64.trunc_f32_u") -O(I64__trunc_f64_s, 0xB0, "i64.trunc_f64_s") -O(I64__trunc_f64_u, 0xB1, "i64.trunc_f64_u") -O(F32__convert_i32_s, 0xB2, "f32.convert_i32_s") -O(F32__convert_i32_u, 0xB3, "f32.convert_i32_u") -O(F32__convert_i64_s, 0xB4, "f32.convert_i64_s") -O(F32__convert_i64_u, 0xB5, "f32.convert_i64_u") -O(F32__demote_f64, 0xB6, "f32.demote_f64") -O(F64__convert_i32_s, 0xB7, "f64.convert_i32_s") -O(F64__convert_i32_u, 0xB8, "f64.convert_i32_u") -O(F64__convert_i64_s, 0xB9, "f64.convert_i64_s") -O(F64__convert_i64_u, 0xBA, "f64.convert_i64_u") -O(F64__promote_f32, 0xBB, "f64.promote_f32") -O(I32__reinterpret_f32, 0xBC, "i32.reinterpret_f32") -O(I64__reinterpret_f64, 0xBD, "i64.reinterpret_f64") -O(F32__reinterpret_i32, 0xBE, "f32.reinterpret_i32") -O(F64__reinterpret_i64, 0xBF, "f64.reinterpret_i64") -O(I32__extend8_s, 0xC0, "i32.extend8_s") -O(I32__extend16_s, 0xC1, "i32.extend16_s") -O(I64__extend8_s, 0xC2, "i64.extend8_s") -O(I64__extend16_s, 0xC3, "i64.extend16_s") -O(I64__extend32_s, 0xC4, "i64.extend32_s") +O(I32__eqz, "i32.eqz", 0x45) +O(I32__eq, "i32.eq", 0x46) +O(I32__ne, "i32.ne", 0x47) +O(I32__lt_s, "i32.lt_s", 0x48) +O(I32__lt_u, "i32.lt_u", 0x49) +O(I32__gt_s, "i32.gt_s", 0x4A) +O(I32__gt_u, "i32.gt_u", 0x4B) +O(I32__le_s, "i32.le_s", 0x4C) +O(I32__le_u, "i32.le_u", 0x4D) +O(I32__ge_s, "i32.ge_s", 0x4E) +O(I32__ge_u, "i32.ge_u", 0x4F) +O(I64__eqz, "i64.eqz", 0x50) +O(I64__eq, "i64.eq", 0x51) +O(I64__ne, "i64.ne", 0x52) +O(I64__lt_s, "i64.lt_s", 0x53) +O(I64__lt_u, "i64.lt_u", 0x54) +O(I64__gt_s, "i64.gt_s", 0x55) +O(I64__gt_u, "i64.gt_u", 0x56) +O(I64__le_s, "i64.le_s", 0x57) +O(I64__le_u, "i64.le_u", 0x58) +O(I64__ge_s, "i64.ge_s", 0x59) +O(I64__ge_u, "i64.ge_u", 0x5A) +O(F32__eq, "f32.eq", 0x5B) +O(F32__ne, "f32.ne", 0x5C) +O(F32__lt, "f32.lt", 0x5D) +O(F32__gt, "f32.gt", 0x5E) +O(F32__le, "f32.le", 0x5F) +O(F32__ge, "f32.ge", 0x60) +O(F64__eq, "f64.eq", 0x61) +O(F64__ne, "f64.ne", 0x62) +O(F64__lt, "f64.lt", 0x63) +O(F64__gt, "f64.gt", 0x64) +O(F64__le, "f64.le", 0x65) +O(F64__ge, "f64.ge", 0x66) +O(I32__clz, "i32.clz", 0x67) +O(I32__ctz, "i32.ctz", 0x68) +O(I32__popcnt, "i32.popcnt", 0x69) +O(I32__add, "i32.add", 0x6A) +O(I32__sub, "i32.sub", 0x6B) +O(I32__mul, "i32.mul", 0x6C) +O(I32__div_s, "i32.div_s", 0x6D) +O(I32__div_u, "i32.div_u", 0x6E) +O(I32__rem_s, "i32.rem_s", 0x6F) +O(I32__rem_u, "i32.rem_u", 0x70) +O(I32__and, "i32.and", 0x71) +O(I32__or, "i32.or", 0x72) +O(I32__xor, "i32.xor", 0x73) +O(I32__shl, "i32.shl", 0x74) +O(I32__shr_s, "i32.shr_s", 0x75) +O(I32__shr_u, "i32.shr_u", 0x76) +O(I32__rotl, "i32.rotl", 0x77) +O(I32__rotr, "i32.rotr", 0x78) +O(I64__clz, "i64.clz", 0x79) +O(I64__ctz, "i64.ctz", 0x7A) +O(I64__popcnt, "i64.popcnt", 0x7B) +O(I64__add, "i64.add", 0x7C) +O(I64__sub, "i64.sub", 0x7D) +O(I64__mul, "i64.mul", 0x7E) +O(I64__div_s, "i64.div_s", 0x7F) +O(I64__div_u, "i64.div_u", 0x80) +O(I64__rem_s, "i64.rem_s", 0x81) +O(I64__rem_u, "i64.rem_u", 0x82) +O(I64__and, "i64.and", 0x83) +O(I64__or, "i64.or", 0x84) +O(I64__xor, "i64.xor", 0x85) +O(I64__shl, "i64.shl", 0x86) +O(I64__shr_s, "i64.shr_s", 0x87) +O(I64__shr_u, "i64.shr_u", 0x88) +O(I64__rotl, "i64.rotl", 0x89) +O(I64__rotr, "i64.rotr", 0x8A) +O(F32__abs, "f32.abs", 0x8B) +O(F32__neg, "f32.neg", 0x8C) +O(F32__ceil, "f32.ceil", 0x8D) +O(F32__floor, "f32.floor", 0x8E) +O(F32__trunc, "f32.trunc", 0x8F) +O(F32__nearest, "f32.nearest", 0x90) +O(F32__sqrt, "f32.sqrt", 0x91) +O(F32__add, "f32.add", 0x92) +O(F32__sub, "f32.sub", 0x93) +O(F32__mul, "f32.mul", 0x94) +O(F32__div, "f32.div", 0x95) +O(F32__min, "f32.min", 0x96) +O(F32__max, "f32.max", 0x97) +O(F32__copysign, "f32.copysign", 0x98) +O(F64__abs, "f64.abs", 0x99) +O(F64__neg, "f64.neg", 0x9A) +O(F64__ceil, "f64.ceil", 0x9B) +O(F64__floor, "f64.floor", 0x9C) +O(F64__trunc, "f64.trunc", 0x9D) +O(F64__nearest, "f64.nearest", 0x9E) +O(F64__sqrt, "f64.sqrt", 0x9F) +O(F64__add, "f64.add", 0xA0) +O(F64__sub, "f64.sub", 0xA1) +O(F64__mul, "f64.mul", 0xA2) +O(F64__div, "f64.div", 0xA3) +O(F64__min, "f64.min", 0xA4) +O(F64__max, "f64.max", 0xA5) +O(F64__copysign, "f64.copysign", 0xA6) +O(I32__wrap_i64, "i32.wrap_i64", 0xA7) +O(I32__trunc_f32_s, "i32.trunc_f32_s", 0xA8) +O(I32__trunc_f32_u, "i32.trunc_f32_u", 0xA9) +O(I32__trunc_f64_s, "i32.trunc_f64_s", 0xAA) +O(I32__trunc_f64_u, "i32.trunc_f64_u", 0xAB) +O(I64__extend_i32_s, "i64.extend_i32_s", 0xAC) +O(I64__extend_i32_u, "i64.extend_i32_u", 0xAD) +O(I64__trunc_f32_s, "i64.trunc_f32_s", 0xAE) +O(I64__trunc_f32_u, "i64.trunc_f32_u", 0xAF) +O(I64__trunc_f64_s, "i64.trunc_f64_s", 0xB0) +O(I64__trunc_f64_u, "i64.trunc_f64_u", 0xB1) +O(F32__convert_i32_s, "f32.convert_i32_s", 0xB2) +O(F32__convert_i32_u, "f32.convert_i32_u", 0xB3) +O(F32__convert_i64_s, "f32.convert_i64_s", 0xB4) +O(F32__convert_i64_u, "f32.convert_i64_u", 0xB5) +O(F32__demote_f64, "f32.demote_f64", 0xB6) +O(F64__convert_i32_s, "f64.convert_i32_s", 0xB7) +O(F64__convert_i32_u, "f64.convert_i32_u", 0xB8) +O(F64__convert_i64_s, "f64.convert_i64_s", 0xB9) +O(F64__convert_i64_u, "f64.convert_i64_u", 0xBA) +O(F64__promote_f32, "f64.promote_f32", 0xBB) +O(I32__reinterpret_f32, "i32.reinterpret_f32", 0xBC) +O(I64__reinterpret_f64, "i64.reinterpret_f64", 0xBD) +O(F32__reinterpret_i32, "f32.reinterpret_i32", 0xBE) +O(F64__reinterpret_i64, "f64.reinterpret_i64", 0xBF) +O(I32__extend8_s, "i32.extend8_s", 0xC0) +O(I32__extend16_s, "i32.extend16_s", 0xC1) +O(I64__extend8_s, "i64.extend8_s", 0xC2) +O(I64__extend16_s, "i64.extend16_s", 0xC3) +O(I64__extend32_s, "i64.extend32_s", 0xC4) +// 0xC5 ~ 0xCF: Reserved // Reference Instructions -O(Ref__null, 0xD0, "ref.null") -O(Ref__is_null, 0xD1, "ref.is_null") -O(Ref__func, 0xD2, "ref.func") -O(Ref__as_non_null, 0xD4, "ref.as_non_null") - -// Control Instructions (part 2) -O(Br_on_null, 0xD5, "br_on_null") -O(Br_on_non_null, 0xD6, "br_on_non_null") - -// Saturating Truncation Instructions -O(I32__trunc_sat_f32_s, 0xFC00, "i32.trunc_sat_f32_s") -O(I32__trunc_sat_f32_u, 0xFC01, "i32.trunc_sat_f32_u") -O(I32__trunc_sat_f64_s, 0xFC02, "i32.trunc_sat_f64_s") -O(I32__trunc_sat_f64_u, 0xFC03, "i32.trunc_sat_f64_u") -O(I64__trunc_sat_f32_s, 0xFC04, "i64.trunc_sat_f32_s") -O(I64__trunc_sat_f32_u, 0xFC05, "i64.trunc_sat_f32_u") -O(I64__trunc_sat_f64_s, 0xFC06, "i64.trunc_sat_f64_s") -O(I64__trunc_sat_f64_u, 0xFC07, "i64.trunc_sat_f64_u") - -// Memory Instructions (part 2) -O(Memory__init, 0xFC08, "memory.init") -O(Data__drop, 0xFC09, "data.drop") -O(Memory__copy, 0xFC0A, "memory.copy") -O(Memory__fill, 0xFC0B, "memory.fill") - -// Table Instructions (part 2) -O(Table__init, 0xFC0C, "table.init") -O(Elem__drop, 0xFC0D, "elem.drop") -O(Table__copy, 0xFC0E, "table.copy") -O(Table__grow, 0xFC0F, "table.grow") -O(Table__size, 0xFC10, "table.size") -O(Table__fill, 0xFC11, "table.fill") - -// SIMD Memory Instructions -O(V128__load, 0xFD00, "v128.load") -O(V128__load8x8_s, 0xFD01, "v128.load8x8_s") -O(V128__load8x8_u, 0xFD02, "v128.load8x8_u") -O(V128__load16x4_s, 0xFD03, "v128.load16x4_s") -O(V128__load16x4_u, 0xFD04, "v128.load16x4_u") -O(V128__load32x2_s, 0xFD05, "v128.load32x2_s") -O(V128__load32x2_u, 0xFD06, "v128.load32x2_u") -O(V128__load8_splat, 0xFD07, "v128.load8_splat") -O(V128__load16_splat, 0xFD08, "v128.load16_splat") -O(V128__load32_splat, 0xFD09, "v128.load32_splat") -O(V128__load64_splat, 0xFD0A, "v128.load64_splat") -O(V128__load32_zero, 0xFD5C, "v128.load32_zero") -O(V128__load64_zero, 0xFD5D, "v128.load64_zero") -O(V128__store, 0xFD0B, "v128.store") -O(V128__load8_lane, 0xFD54, "v128.load8_lane") -O(V128__load16_lane, 0xFD55, "v128.load16_lane") -O(V128__load32_lane, 0xFD56, "v128.load32_lane") -O(V128__load64_lane, 0xFD57, "v128.load64_lane") -O(V128__store8_lane, 0xFD58, "v128.store8_lane") -O(V128__store16_lane, 0xFD59, "v128.store16_lane") -O(V128__store32_lane, 0xFD5A, "v128.store32_lane") -O(V128__store64_lane, 0xFD5B, "v128.store64_lane") - -// SIMD Const Instructions -O(V128__const, 0xFD0C, "v128.const") - -// SIMD Shuffle Instructions -O(I8x16__shuffle, 0xFD0D, "i8x16.shuffle") - -// SIMD Lane Instructions -O(I8x16__extract_lane_s, 0xFD15, "i8x16.extract_lane_s") -O(I8x16__extract_lane_u, 0xFD16, "i8x16.extract_lane_u") -O(I8x16__replace_lane, 0xFD17, "i8x16.replace_lane") -O(I16x8__extract_lane_s, 0xFD18, "i16x8.extract_lane_s") -O(I16x8__extract_lane_u, 0xFD19, "i16x8.extract_lane_u") -O(I16x8__replace_lane, 0xFD1A, "i16x8.replace_lane") -O(I32x4__extract_lane, 0xFD1B, "i32x4.extract_lane") -O(I32x4__replace_lane, 0xFD1C, "i32x4.replace_lane") -O(I64x2__extract_lane, 0xFD1D, "i64x2.extract_lane") -O(I64x2__replace_lane, 0xFD1E, "i64x2.replace_lane") -O(F32x4__extract_lane, 0xFD1F, "f32x4.extract_lane") -O(F32x4__replace_lane, 0xFD20, "f32x4.replace_lane") -O(F64x2__extract_lane, 0xFD21, "f64x2.extract_lane") -O(F64x2__replace_lane, 0xFD22, "f64x2.replace_lane") - -// SIMD Numeric Instructions -O(I8x16__swizzle, 0xFD0E, "i8x16.swizzle") -O(I8x16__splat, 0xFD0F, "i8x16.splat") -O(I16x8__splat, 0xFD10, "i16x8.splat") -O(I32x4__splat, 0xFD11, "i32x4.splat") -O(I64x2__splat, 0xFD12, "i64x2.splat") -O(F32x4__splat, 0xFD13, "f32x4.splat") -O(F64x2__splat, 0xFD14, "f64x2.splat") - -O(I8x16__eq, 0xFD23, "i8x16.eq") -O(I8x16__ne, 0xFD24, "i8x16.ne") -O(I8x16__lt_s, 0xFD25, "i8x16.lt_s") -O(I8x16__lt_u, 0xFD26, "i8x16.lt_u") -O(I8x16__gt_s, 0xFD27, "i8x16.gt_s") -O(I8x16__gt_u, 0xFD28, "i8x16.gt_u") -O(I8x16__le_s, 0xFD29, "i8x16.le_s") -O(I8x16__le_u, 0xFD2A, "i8x16.le_u") -O(I8x16__ge_s, 0xFD2B, "i8x16.ge_s") -O(I8x16__ge_u, 0xFD2C, "i8x16.ge_u") - -O(I16x8__eq, 0xFD2D, "i16x8.eq") -O(I16x8__ne, 0xFD2E, "i16x8.ne") -O(I16x8__lt_s, 0xFD2F, "i16x8.lt_s") -O(I16x8__lt_u, 0xFD30, "i16x8.lt_u") -O(I16x8__gt_s, 0xFD31, "i16x8.gt_s") -O(I16x8__gt_u, 0xFD32, "i16x8.gt_u") -O(I16x8__le_s, 0xFD33, "i16x8.le_s") -O(I16x8__le_u, 0xFD34, "i16x8.le_u") -O(I16x8__ge_s, 0xFD35, "i16x8.ge_s") -O(I16x8__ge_u, 0xFD36, "i16x8.ge_u") - -O(I32x4__eq, 0xFD37, "i32x4.eq") -O(I32x4__ne, 0xFD38, "i32x4.ne") -O(I32x4__lt_s, 0xFD39, "i32x4.lt_s") -O(I32x4__lt_u, 0xFD3A, "i32x4.lt_u") -O(I32x4__gt_s, 0xFD3B, "i32x4.gt_s") -O(I32x4__gt_u, 0xFD3C, "i32x4.gt_u") -O(I32x4__le_s, 0xFD3D, "i32x4.le_s") -O(I32x4__le_u, 0xFD3E, "i32x4.le_u") -O(I32x4__ge_s, 0xFD3F, "i32x4.ge_s") -O(I32x4__ge_u, 0xFD40, "i32x4.ge_u") - -O(I64x2__eq, 0xFDD6, "i64x2.eq") -O(I64x2__ne, 0xFDD7, "i64x2.ne") -O(I64x2__lt_s, 0xFDD8, "i64x2.lt_s") -O(I64x2__gt_s, 0xFDD9, "i64x2.gt_s") -O(I64x2__le_s, 0xFDDA, "i64x2.le_s") -O(I64x2__ge_s, 0xFDDB, "i64x2.ge_s") - -O(F32x4__eq, 0xFD41, "f32x4.eq") -O(F32x4__ne, 0xFD42, "f32x4.ne") -O(F32x4__lt, 0xFD43, "f32x4.lt") -O(F32x4__gt, 0xFD44, "f32x4.gt") -O(F32x4__le, 0xFD45, "f32x4.le") -O(F32x4__ge, 0xFD46, "f32x4.ge") - -O(F64x2__eq, 0xFD47, "f64x2.eq") -O(F64x2__ne, 0xFD48, "f64x2.ne") -O(F64x2__lt, 0xFD49, "f64x2.lt") -O(F64x2__gt, 0xFD4A, "f64x2.gt") -O(F64x2__le, 0xFD4B, "f64x2.le") -O(F64x2__ge, 0xFD4C, "f64x2.ge") - -O(V128__not, 0xFD4D, "v128.not") -O(V128__and, 0xFD4E, "v128.and") -O(V128__andnot, 0xFD4F, "v128.andnot") -O(V128__or, 0xFD50, "v128.or") -O(V128__xor, 0xFD51, "v128.xor") -O(V128__bitselect, 0xFD52, "v128.bitselect") -O(V128__any_true, 0xFD53, "v128.any_true") - -O(I8x16__abs, 0xFD60, "i8x16.abs") -O(I8x16__neg, 0xFD61, "i8x16.neg") -O(I8x16__popcnt, 0xFD62, "i8x16.popcnt") -O(I8x16__all_true, 0xFD63, "i8x16.all_true") -O(I8x16__bitmask, 0xFD64, "i8x16.bitmask") -O(I8x16__narrow_i16x8_s, 0xFD65, "i8x16.narrow_i16x8_s") -O(I8x16__narrow_i16x8_u, 0xFD66, "i8x16.narrow_i16x8_u") -O(I8x16__shl, 0xFD6B, "i8x16.shl") -O(I8x16__shr_s, 0xFD6C, "i8x16.shr_s") -O(I8x16__shr_u, 0xFD6D, "i8x16.shr_u") -O(I8x16__add, 0xFD6E, "i8x16.add") -O(I8x16__add_sat_s, 0xFD6F, "i8x16.add_sat_s") -O(I8x16__add_sat_u, 0xFD70, "i8x16.add_sat_u") -O(I8x16__sub, 0xFD71, "i8x16.sub") -O(I8x16__sub_sat_s, 0xFD72, "i8x16.sub_sat_s") -O(I8x16__sub_sat_u, 0xFD73, "i8x16.sub_sat_u") -O(I8x16__min_s, 0xFD76, "i8x16.min_s") -O(I8x16__min_u, 0xFD77, "i8x16.min_u") -O(I8x16__max_s, 0xFD78, "i8x16.max_s") -O(I8x16__max_u, 0xFD79, "i8x16.max_u") -O(I8x16__avgr_u, 0xFD7B, "i8x16.avgr_u") - -O(I16x8__abs, 0xFD80, "i16x8.abs") -O(I16x8__neg, 0xFD81, "i16x8.neg") -O(I16x8__all_true, 0xFD83, "i16x8.all_true") -O(I16x8__bitmask, 0xFD84, "i16x8.bitmask") -O(I16x8__narrow_i32x4_s, 0xFD85, "i16x8.narrow_i32x4_s") -O(I16x8__narrow_i32x4_u, 0xFD86, "i16x8.narrow_i32x4_u") -O(I16x8__extend_low_i8x16_s, 0xFD87, "i16x8.extend_low_i8x16_s") -O(I16x8__extend_high_i8x16_s, 0xFD88, "i16x8.extend_high_i8x16_s") -O(I16x8__extend_low_i8x16_u, 0xFD89, "i16x8.extend_low_i8x16_u") -O(I16x8__extend_high_i8x16_u, 0xFD8A, "i16x8.extend_high_i8x16_u") -O(I16x8__shl, 0xFD8B, "i16x8.shl") -O(I16x8__shr_s, 0xFD8C, "i16x8.shr_s") -O(I16x8__shr_u, 0xFD8D, "i16x8.shr_u") -O(I16x8__add, 0xFD8E, "i16x8.add") -O(I16x8__add_sat_s, 0xFD8F, "i16x8.add_sat_s") -O(I16x8__add_sat_u, 0xFD90, "i16x8.add_sat_u") -O(I16x8__sub, 0xFD91, "i16x8.sub") -O(I16x8__sub_sat_s, 0xFD92, "i16x8.sub_sat_s") -O(I16x8__sub_sat_u, 0xFD93, "i16x8.sub_sat_u") -O(I16x8__mul, 0xFD95, "i16x8.mul") -O(I16x8__min_s, 0xFD96, "i16x8.min_s") -O(I16x8__min_u, 0xFD97, "i16x8.min_u") -O(I16x8__max_s, 0xFD98, "i16x8.max_s") -O(I16x8__max_u, 0xFD99, "i16x8.max_u") -O(I16x8__avgr_u, 0xFD9B, "i16x8.avgr_u") -O(I16x8__extmul_low_i8x16_s, 0xFD9C, "i16x8.extmul_low_i8x16_s") -O(I16x8__extmul_high_i8x16_s, 0xFD9D, "i16x8.extmul_high_i8x16_s") -O(I16x8__extmul_low_i8x16_u, 0xFD9E, "i16x8.extmul_low_i8x16_u") -O(I16x8__extmul_high_i8x16_u, 0xFD9F, "i16x8.extmul_high_i8x16_u") -O(I16x8__q15mulr_sat_s, 0xFD82, "i16x8.q15mulr_sat_s") -O(I16x8__extadd_pairwise_i8x16_s, 0xFD7C, "i16x8.extadd_pairwise_i8x16_s") -O(I16x8__extadd_pairwise_i8x16_u, 0xFD7D, "i16x8.extadd_pairwise_i8x16_u") - -O(I32x4__abs, 0xFDA0, "i32x4.abs") -O(I32x4__neg, 0xFDA1, "i32x4.neg") -O(I32x4__all_true, 0xFDA3, "i32x4.all_true") -O(I32x4__bitmask, 0xFDA4, "i32x4.bitmask") -O(I32x4__extend_low_i16x8_s, 0xFDA7, "i32x4.extend_low_i16x8_s") -O(I32x4__extend_high_i16x8_s, 0xFDA8, "i32x4.extend_high_i16x8_s") -O(I32x4__extend_low_i16x8_u, 0xFDA9, "i32x4.extend_low_i16x8_u") -O(I32x4__extend_high_i16x8_u, 0xFDAA, "i32x4.extend_high_i16x8_u") -O(I32x4__shl, 0xFDAB, "i32x4.shl") -O(I32x4__shr_s, 0xFDAC, "i32x4.shr_s") -O(I32x4__shr_u, 0xFDAD, "i32x4.shr_u") -O(I32x4__add, 0xFDAE, "i32x4.add") -O(I32x4__sub, 0xFDB1, "i32x4.sub") -O(I32x4__mul, 0xFDB5, "i32x4.mul") -O(I32x4__min_s, 0xFDB6, "i32x4.min_s") -O(I32x4__min_u, 0xFDB7, "i32x4.min_u") -O(I32x4__max_s, 0xFDB8, "i32x4.max_s") -O(I32x4__max_u, 0xFDB9, "i32x4.max_u") -O(I32x4__dot_i16x8_s, 0xFDBA, "i32x4.dot_i16x8_s") -O(I32x4__extmul_low_i16x8_s, 0xFDBC, "i32x4.extmul_low_i16x8_s") -O(I32x4__extmul_high_i16x8_s, 0xFDBD, "i32x4.extmul_high_i16x8_s") -O(I32x4__extmul_low_i16x8_u, 0xFDBE, "i32x4.extmul_low_i16x8_u") -O(I32x4__extmul_high_i16x8_u, 0xFDBF, "i32x4.extmul_high_i16x8_u") -O(I32x4__extadd_pairwise_i16x8_s, 0xFD7E, "i32x4.extadd_pairwise_i16x8_s") -O(I32x4__extadd_pairwise_i16x8_u, 0xFD7F, "i32x4.extadd_pairwise_i16x8_u") - -O(I64x2__abs, 0xFDC0, "i64x2.abs") -O(I64x2__neg, 0xFDC1, "i64x2.neg") -O(I64x2__all_true, 0xFDC3, "i64x2.all_true") -O(I64x2__bitmask, 0xFDC4, "i64x2.bitmask") -O(I64x2__extend_low_i32x4_s, 0xFDC7, "i64x2.extend_low_i32x4_s") -O(I64x2__extend_high_i32x4_s, 0xFDC8, "i64x2.extend_high_i32x4_s") -O(I64x2__extend_low_i32x4_u, 0xFDC9, "i64x2.extend_low_i32x4_u") -O(I64x2__extend_high_i32x4_u, 0xFDCA, "i64x2.extend_high_i32x4_u") -O(I64x2__shl, 0xFDCB, "i64x2.shl") -O(I64x2__shr_s, 0xFDCC, "i64x2.shr_s") -O(I64x2__shr_u, 0xFDCD, "i64x2.shr_u") -O(I64x2__add, 0xFDCE, "i64x2.add") -O(I64x2__sub, 0xFDD1, "i64x2.sub") -O(I64x2__mul, 0xFDD5, "i64x2.mul") -O(I64x2__extmul_low_i32x4_s, 0xFDDC, "i64x2.extmul_low_i32x4_s") -O(I64x2__extmul_high_i32x4_s, 0xFDDD, "i64x2.extmul_high_i32x4_s") -O(I64x2__extmul_low_i32x4_u, 0xFDDE, "i64x2.extmul_low_i32x4_u") -O(I64x2__extmul_high_i32x4_u, 0xFDDF, "i64x2.extmul_high_i32x4_u") - -O(F32x4__abs, 0xFDE0, "f32x4.abs") -O(F32x4__neg, 0xFDE1, "f32x4.neg") -O(F32x4__sqrt, 0xFDE3, "f32x4.sqrt") -O(F32x4__add, 0xFDE4, "f32x4.add") -O(F32x4__sub, 0xFDE5, "f32x4.sub") -O(F32x4__mul, 0xFDE6, "f32x4.mul") -O(F32x4__div, 0xFDE7, "f32x4.div") -O(F32x4__min, 0xFDE8, "f32x4.min") -O(F32x4__max, 0xFDE9, "f32x4.max") -O(F32x4__pmin, 0xFDEA, "f32x4.pmin") -O(F32x4__pmax, 0xFDEB, "f32x4.pmax") -O(F32x4__ceil, 0xFD67, "f32x4.ceil") -O(F32x4__floor, 0xFD68, "f32x4.floor") -O(F32x4__trunc, 0xFD69, "f32x4.trunc") -O(F32x4__nearest, 0xFD6A, "f32x4.nearest") - -O(F64x2__abs, 0xFDEC, "f64x2.abs") -O(F64x2__neg, 0xFDED, "f64x2.neg") -O(F64x2__sqrt, 0xFDEF, "f64x2.sqrt") -O(F64x2__add, 0xFDF0, "f64x2.add") -O(F64x2__sub, 0xFDF1, "f64x2.sub") -O(F64x2__mul, 0xFDF2, "f64x2.mul") -O(F64x2__div, 0xFDF3, "f64x2.div") -O(F64x2__min, 0xFDF4, "f64x2.min") -O(F64x2__max, 0xFDF5, "f64x2.max") -O(F64x2__pmin, 0xFDF6, "f64x2.pmin") -O(F64x2__pmax, 0xFDF7, "f64x2.pmax") -O(F64x2__ceil, 0xFD74, "f64x2.ceil") -O(F64x2__floor, 0xFD75, "f64x2.floor") -O(F64x2__trunc, 0xFD7A, "f64x2.trunc") -O(F64x2__nearest, 0xFD94, "f64x2.nearest") - -O(I32x4__trunc_sat_f32x4_s, 0xFDF8, "i32x4.trunc_sat_f32x4_s") -O(I32x4__trunc_sat_f32x4_u, 0xFDF9, "i32x4.trunc_sat_f32x4_u") -O(F32x4__convert_i32x4_s, 0xFDFA, "f32x4.convert_i32x4_s") -O(F32x4__convert_i32x4_u, 0xFDFB, "f32x4.convert_i32x4_u") -O(I32x4__trunc_sat_f64x2_s_zero, 0xFDFC, "i32x4.trunc_sat_f64x2_s_zero") -O(I32x4__trunc_sat_f64x2_u_zero, 0xFDFD, "i32x4.trunc_sat_f64x2_u_zero") -O(F64x2__convert_low_i32x4_s, 0xFDFE, "f64x2.convert_low_i32x4_s") -O(F64x2__convert_low_i32x4_u, 0xFDFF, "f64x2.convert_low_i32x4_u") -O(F32x4__demote_f64x2_zero, 0xFD5E, "f32x4.demote_f64x2_zero") -O(F64x2__promote_low_f32x4, 0xFD5F, "f64x2.promote_low_f32x4") - -// Atomic instructions -O(Memory__atomic__notify, 0xFE00, "memory.atomic.notify") -O(Memory__atomic__wait32, 0xFE01, "memory.atomic.wait32") -O(Memory__atomic__wait64, 0xFE02, "memory.atomic.wait64") -O(Atomic__fence, 0xFE03, "atomic.fence") - -O(I32__atomic__load, 0xFE10, "i32.atomic.load") -O(I64__atomic__load, 0xFE11, "i64.atomic.load") -O(I32__atomic__load8_u, 0xFE12, "i32.atomic.load8_u") -O(I32__atomic__load16_u, 0xFE13, "i32.atomic.load16_u") -O(I64__atomic__load8_u, 0xFE14, "i64.atomic.load8_u") -O(I64__atomic__load16_u, 0xFE15, "i64.atomic.load16_u") -O(I64__atomic__load32_u, 0xFE16, "i64.atomic.load32_u") -O(I32__atomic__store, 0xFE17, "i32.atomic.store") -O(I64__atomic__store, 0xFE18, "i64.atomic.store") -O(I32__atomic__store8, 0xFE19, "i32.atomic.store8") -O(I32__atomic__store16, 0xFE1A, "i32.atomic.store16") -O(I64__atomic__store8, 0xFE1B, "i64.atomic.store8") -O(I64__atomic__store16, 0xFE1C, "i64.atomic.store16") -O(I64__atomic__store32, 0xFE1D, "i64.atomic.store32") - -O(I32__atomic__rmw__add, 0xFE1E, "i32.atomic.rmw.add") -O(I64__atomic__rmw__add, 0xFE1F, "i64.atomic.rmw.add") -O(I32__atomic__rmw8__add_u, 0xFE20, "i32.atomic.rmw8.add_u") -O(I32__atomic__rmw16__add_u, 0xFE21, "i32.atomic.rmw16.add_u") -O(I64__atomic__rmw8__add_u, 0xFE22, "i64.atomic.rmw8.add_u") -O(I64__atomic__rmw16__add_u, 0xFE23, "i64.atomic.rmw16.add_u") -O(I64__atomic__rmw32__add_u, 0xFE24, "i64.atomic.rmw32.add_u") -O(I32__atomic__rmw__sub, 0xFE25, "i32.atomic.rmw.sub") -O(I64__atomic__rmw__sub, 0xFE26, "i64.atomic.rmw.sub") -O(I32__atomic__rmw8__sub_u, 0xFE27, "i32.atomic.rmw8.sub_u") -O(I32__atomic__rmw16__sub_u, 0xFE28, "i32.atomic.rmw16.sub_u") -O(I64__atomic__rmw8__sub_u, 0xFE29, "i64.atomic.rmw8.sub_u") -O(I64__atomic__rmw16__sub_u, 0xFE2A, "i64.atomic.rmw16.sub_u") -O(I64__atomic__rmw32__sub_u, 0xFE2B, "i64.atomic.rmw32.sub_u") -O(I32__atomic__rmw__and, 0xFE2C, "i32.atomic.rmw.and") -O(I64__atomic__rmw__and, 0xFE2D, "i64.atomic.rmw.and") -O(I32__atomic__rmw8__and_u, 0xFE2E, "i32.atomic.rmw8.and_u") -O(I32__atomic__rmw16__and_u, 0xFE2F, "i32.atomic.rmw16.and_u") -O(I64__atomic__rmw8__and_u, 0xFE30, "i64.atomic.rmw8.and_u") -O(I64__atomic__rmw16__and_u, 0xFE31, "i64.atomic.rmw16.and_u") -O(I64__atomic__rmw32__and_u, 0xFE32, "i64.atomic.rmw32.and_u") -O(I32__atomic__rmw__or, 0xFE33, "i32.atomic.rmw.or") -O(I64__atomic__rmw__or, 0xFE34, "i64.atomic.rmw.or") -O(I32__atomic__rmw8__or_u, 0xFE35, "i32.atomic.rmw8.or_u") -O(I32__atomic__rmw16__or_u, 0xFE36, "i32.atomic.rmw16.or_u") -O(I64__atomic__rmw8__or_u, 0xFE37, "i64.atomic.rmw8.or_u") -O(I64__atomic__rmw16__or_u, 0xFE38, "i64.atomic.rmw16.or_u") -O(I64__atomic__rmw32__or_u, 0xFE39, "i64.atomic.rmw32.or_u") -O(I32__atomic__rmw__xor, 0xFE3A, "i32.atomic.rmw.xor") -O(I64__atomic__rmw__xor, 0xFE3B, "i64.atomic.rmw.xor") -O(I32__atomic__rmw8__xor_u, 0xFE3C, "i32.atomic.rmw8.xor_u") -O(I32__atomic__rmw16__xor_u, 0xFE3D, "i32.atomic.rmw16.xor_u") -O(I64__atomic__rmw8__xor_u, 0xFE3E, "i64.atomic.rmw8.xor_u") -O(I64__atomic__rmw16__xor_u, 0xFE3F, "i64.atomic.rmw16.xor_u") -O(I64__atomic__rmw32__xor_u, 0xFE40, "i64.atomic.rmw32.xor_u") -O(I32__atomic__rmw__xchg, 0xFE41, "i32.atomic.rmw.xchg") -O(I64__atomic__rmw__xchg, 0xFE42, "i64.atomic.rmw.xchg") -O(I32__atomic__rmw8__xchg_u, 0xFE43, "i32.atomic.rmw8.xchg_u") -O(I32__atomic__rmw16__xchg_u, 0xFE44, "i32.atomic.rmw16.xchg_u") -O(I64__atomic__rmw8__xchg_u, 0xFE45, "i64.atomic.rmw8.xchg_u") -O(I64__atomic__rmw16__xchg_u, 0xFE46, "i64.atomic.rmw16.xchg_u") -O(I64__atomic__rmw32__xchg_u, 0xFE47, "i64.atomic.rmw32.xchg_u") -O(I32__atomic__rmw__cmpxchg, 0xFE48, "i32.atomic.rmw.cmpxchg") -O(I64__atomic__rmw__cmpxchg, 0xFE49, "i64.atomic.rmw.cmpxchg") -O(I32__atomic__rmw8__cmpxchg_u, 0xFE4A, "i32.atomic.rmw8.cmpxchg_u") -O(I32__atomic__rmw16__cmpxchg_u, 0xFE4B, "i32.atomic.rmw16.cmpxchg_u") -O(I64__atomic__rmw8__cmpxchg_u, 0xFE4C, "i64.atomic.rmw8.cmpxchg_u") -O(I64__atomic__rmw16__cmpxchg_u, 0xFE4D, "i64.atomic.rmw16.cmpxchg_u") -O(I64__atomic__rmw32__cmpxchg_u, 0xFE4E, "i64.atomic.rmw32.cmpxchg_u") +O(Ref__null, "ref.null", 0xD0) +O(Ref__is_null, "ref.is_null", 0xD1) +O(Ref__func, "ref.func", 0xD2) +O(Ref__eq, "ref.eq", 0xD3) +O(Ref__as_non_null, "ref.as_non_null", 0xD4) + +// Control Instructions (part 3) +O(Br_on_null, "br_on_null", 0xD5) +O(Br_on_non_null, "br_on_non_null", 0xD6) +// 0xD7 ~ 0xFA: Reserved + +// 0xFB prefix - GC Instructions +OFB(Struct__new, "struct.new", 0xFB, 0) +OFB(Struct__new_default, "struct.new_default", 0xFB, 1) +OFB(Struct__get, "struct.get", 0xFB, 2) +OFB(Struct__get_s, "struct.get_s", 0xFB, 3) +OFB(Struct__get_u, "struct.get_u", 0xFB, 4) +OFB(Struct__set, "struct.set", 0xFB, 5) +OFB(Array__new, "array.new", 0xFB, 6) +OFB(Array__new_default, "array.new_default", 0xFB, 7) +OFB(Array__new_fixed, "array.new_fixed", 0xFB, 8) +OFB(Array__new_data, "array.new_data", 0xFB, 9) +OFB(Array__new_elem, "array.new_elem", 0xFB, 10) +OFB(Array__get, "array.get", 0xFB, 11) +OFB(Array__get_s, "array.get_s", 0xFB, 12) +OFB(Array__get_u, "array.get_u", 0xFB, 13) +OFB(Array__set, "array.set", 0xFB, 14) +OFB(Array__len, "array.len", 0xFB, 15) +OFB(Array__fill, "array.fill", 0xFB, 16) +OFB(Array__copy, "array.copy", 0xFB, 17) +OFB(Array__init_data, "array.init_data", 0xFB, 18) +OFB(Array__init_elem, "array.init_elem", 0xFB, 19) +OFB(Ref__test, "ref.test (ref)", 0xFB, 20) +OFB(Ref__test_null, "ref.test (ref.null)", 0xFB, 21) +OFB(Ref__cast, "ref.cast (ref)", 0xFB, 22) +OFB(Ref__cast_null, "ref.cast (ref.null)", 0xFB, 23) +OFB(Br_on_cast, "br_on_cast", 0xFB, 24) +OFB(Br_on_cast_fail, "br_on_cast_fail", 0xFB, 25) +OFB(Any__convert_extern, "any.convert_extern", 0xFB, 26) +OFB(Extern__convert_any, "extern.convert_any", 0xFB, 27) +OFB(Ref__i31, "ref.i31", 0xFB, 28) +OFB(I31__get_s, "i31.get_s", 0xFB, 29) +OFB(I31__get_u, "i31.get_u", 0xFB, 30) + +// 0xFC prefix - Saturating Truncation Instructions +OFC(I32__trunc_sat_f32_s, "i32.trunc_sat_f32_s", 0xFC, 0) +OFC(I32__trunc_sat_f32_u, "i32.trunc_sat_f32_u", 0xFC, 1) +OFC(I32__trunc_sat_f64_s, "i32.trunc_sat_f64_s", 0xFC, 2) +OFC(I32__trunc_sat_f64_u, "i32.trunc_sat_f64_u", 0xFC, 3) +OFC(I64__trunc_sat_f32_s, "i64.trunc_sat_f32_s", 0xFC, 4) +OFC(I64__trunc_sat_f32_u, "i64.trunc_sat_f32_u", 0xFC, 5) +OFC(I64__trunc_sat_f64_s, "i64.trunc_sat_f64_s", 0xFC, 6) +OFC(I64__trunc_sat_f64_u, "i64.trunc_sat_f64_u", 0xFC, 7) + +// 0xFC prefix - Memory Instructions (part 2) +OFC(Memory__init, "memory.init", 0xFC, 8) +OFC(Data__drop, "data.drop", 0xFC, 9) +OFC(Memory__copy, "memory.copy", 0xFC, 10) +OFC(Memory__fill, "memory.fill", 0xFC, 11) + +// 0xFC prefix - Table Instructions (part 2) +OFC(Table__init, "table.init", 0xFC, 12) +OFC(Elem__drop, "elem.drop", 0xFC, 13) +OFC(Table__copy, "table.copy", 0xFC, 14) +OFC(Table__grow, "table.grow", 0xFC, 15) +OFC(Table__size, "table.size", 0xFC, 16) +OFC(Table__fill, "table.fill", 0xFC, 17) + +// 0xFD prefix - Vector Memory Instructions (part 1) +OFD(V128__load, "v128.load", 0xFD, 0) +OFD(V128__load8x8_s, "v128.load8x8_s", 0xFD, 1) +OFD(V128__load8x8_u, "v128.load8x8_u", 0xFD, 2) +OFD(V128__load16x4_s, "v128.load16x4_s", 0xFD, 3) +OFD(V128__load16x4_u, "v128.load16x4_u", 0xFD, 4) +OFD(V128__load32x2_s, "v128.load32x2_s", 0xFD, 5) +OFD(V128__load32x2_u, "v128.load32x2_u", 0xFD, 6) +OFD(V128__load8_splat, "v128.load8_splat", 0xFD, 7) +OFD(V128__load16_splat, "v128.load16_splat", 0xFD, 8) +OFD(V128__load32_splat, "v128.load32_splat", 0xFD, 9) +OFD(V128__load64_splat, "v128.load64_splat", 0xFD, 10) +OFD(V128__store, "v128.store", 0xFD, 11) + +// 0xFD prefix - Vector Numeric Instructions (part 1) +OFD(V128__const, "v128.const", 0xFD, 12) +OFD(I8x16__shuffle, "i8x16.shuffle", 0xFD, 13) +OFD(I8x16__swizzle, "i8x16.swizzle", 0xFD, 14) +OFD(I8x16__splat, "i8x16.splat", 0xFD, 15) +OFD(I16x8__splat, "i16x8.splat", 0xFD, 16) +OFD(I32x4__splat, "i32x4.splat", 0xFD, 17) +OFD(I64x2__splat, "i64x2.splat", 0xFD, 18) +OFD(F32x4__splat, "f32x4.splat", 0xFD, 19) +OFD(F64x2__splat, "f64x2.splat", 0xFD, 20) + +// 0xFD prefix - Vector Lane Instructions +OFD(I8x16__extract_lane_s, "i8x16.extract_lane_s", 0xFD, 21) +OFD(I8x16__extract_lane_u, "i8x16.extract_lane_u", 0xFD, 22) +OFD(I8x16__replace_lane, "i8x16.replace_lane", 0xFD, 23) +OFD(I16x8__extract_lane_s, "i16x8.extract_lane_s", 0xFD, 24) +OFD(I16x8__extract_lane_u, "i16x8.extract_lane_u", 0xFD, 25) +OFD(I16x8__replace_lane, "i16x8.replace_lane", 0xFD, 26) +OFD(I32x4__extract_lane, "i32x4.extract_lane", 0xFD, 27) +OFD(I32x4__replace_lane, "i32x4.replace_lane", 0xFD, 28) +OFD(I64x2__extract_lane, "i64x2.extract_lane", 0xFD, 29) +OFD(I64x2__replace_lane, "i64x2.replace_lane", 0xFD, 30) +OFD(F32x4__extract_lane, "f32x4.extract_lane", 0xFD, 31) +OFD(F32x4__replace_lane, "f32x4.replace_lane", 0xFD, 32) +OFD(F64x2__extract_lane, "f64x2.extract_lane", 0xFD, 33) +OFD(F64x2__replace_lane, "f64x2.replace_lane", 0xFD, 34) + +// 0xFD prefix - Vector Numeric Instructions (part 2) +OFD(I8x16__eq, "i8x16.eq", 0xFD, 35) +OFD(I8x16__ne, "i8x16.ne", 0xFD, 36) +OFD(I8x16__lt_s, "i8x16.lt_s", 0xFD, 37) +OFD(I8x16__lt_u, "i8x16.lt_u", 0xFD, 38) +OFD(I8x16__gt_s, "i8x16.gt_s", 0xFD, 39) +OFD(I8x16__gt_u, "i8x16.gt_u", 0xFD, 40) +OFD(I8x16__le_s, "i8x16.le_s", 0xFD, 41) +OFD(I8x16__le_u, "i8x16.le_u", 0xFD, 42) +OFD(I8x16__ge_s, "i8x16.ge_s", 0xFD, 43) +OFD(I8x16__ge_u, "i8x16.ge_u", 0xFD, 44) +OFD(I16x8__eq, "i16x8.eq", 0xFD, 45) +OFD(I16x8__ne, "i16x8.ne", 0xFD, 46) +OFD(I16x8__lt_s, "i16x8.lt_s", 0xFD, 47) +OFD(I16x8__lt_u, "i16x8.lt_u", 0xFD, 48) +OFD(I16x8__gt_s, "i16x8.gt_s", 0xFD, 49) +OFD(I16x8__gt_u, "i16x8.gt_u", 0xFD, 50) +OFD(I16x8__le_s, "i16x8.le_s", 0xFD, 51) +OFD(I16x8__le_u, "i16x8.le_u", 0xFD, 52) +OFD(I16x8__ge_s, "i16x8.ge_s", 0xFD, 53) +OFD(I16x8__ge_u, "i16x8.ge_u", 0xFD, 54) +OFD(I32x4__eq, "i32x4.eq", 0xFD, 55) +OFD(I32x4__ne, "i32x4.ne", 0xFD, 56) +OFD(I32x4__lt_s, "i32x4.lt_s", 0xFD, 57) +OFD(I32x4__lt_u, "i32x4.lt_u", 0xFD, 58) +OFD(I32x4__gt_s, "i32x4.gt_s", 0xFD, 59) +OFD(I32x4__gt_u, "i32x4.gt_u", 0xFD, 60) +OFD(I32x4__le_s, "i32x4.le_s", 0xFD, 61) +OFD(I32x4__le_u, "i32x4.le_u", 0xFD, 62) +OFD(I32x4__ge_s, "i32x4.ge_s", 0xFD, 63) +OFD(I32x4__ge_u, "i32x4.ge_u", 0xFD, 64) +OFD(F32x4__eq, "f32x4.eq", 0xFD, 65) +OFD(F32x4__ne, "f32x4.ne", 0xFD, 66) +OFD(F32x4__lt, "f32x4.lt", 0xFD, 67) +OFD(F32x4__gt, "f32x4.gt", 0xFD, 68) +OFD(F32x4__le, "f32x4.le", 0xFD, 69) +OFD(F32x4__ge, "f32x4.ge", 0xFD, 70) +OFD(F64x2__eq, "f64x2.eq", 0xFD, 71) +OFD(F64x2__ne, "f64x2.ne", 0xFD, 72) +OFD(F64x2__lt, "f64x2.lt", 0xFD, 73) +OFD(F64x2__gt, "f64x2.gt", 0xFD, 74) +OFD(F64x2__le, "f64x2.le", 0xFD, 75) +OFD(F64x2__ge, "f64x2.ge", 0xFD, 76) +OFD(V128__not, "v128.not", 0xFD, 77) +OFD(V128__and, "v128.and", 0xFD, 78) +OFD(V128__andnot, "v128.andnot", 0xFD, 79) +OFD(V128__or, "v128.or", 0xFD, 80) +OFD(V128__xor, "v128.xor", 0xFD, 81) +OFD(V128__bitselect, "v128.bitselect", 0xFD, 82) +OFD(V128__any_true, "v128.any_true", 0xFD, 83) + +// 0xFD prefix - Vector Memory Instructions (part 2) +OFD(V128__load8_lane, "v128.load8_lane", 0xFD, 84) +OFD(V128__load16_lane, "v128.load16_lane", 0xFD, 85) +OFD(V128__load32_lane, "v128.load32_lane", 0xFD, 86) +OFD(V128__load64_lane, "v128.load64_lane", 0xFD, 87) +OFD(V128__store8_lane, "v128.store8_lane", 0xFD, 88) +OFD(V128__store16_lane, "v128.store16_lane", 0xFD, 89) +OFD(V128__store32_lane, "v128.store32_lane", 0xFD, 90) +OFD(V128__store64_lane, "v128.store64_lane", 0xFD, 91) +OFD(V128__load32_zero, "v128.load32_zero", 0xFD, 92) +OFD(V128__load64_zero, "v128.load64_zero", 0xFD, 93) + +// 0xFD prefix - Vector Numeric Instructions (part 3) +OFD(F32x4__demote_f64x2_zero, "f32x4.demote_f64x2_zero", 0xFD, 94) +OFD(F64x2__promote_low_f32x4, "f64x2.promote_low_f32x4", 0xFD, 95) +OFD(I8x16__abs, "i8x16.abs", 0xFD, 96) +OFD(I8x16__neg, "i8x16.neg", 0xFD, 97) +OFD(I8x16__popcnt, "i8x16.popcnt", 0xFD, 98) +OFD(I8x16__all_true, "i8x16.all_true", 0xFD, 99) +OFD(I8x16__bitmask, "i8x16.bitmask", 0xFD, 100) +OFD(I8x16__narrow_i16x8_s, "i8x16.narrow_i16x8_s", 0xFD, 101) +OFD(I8x16__narrow_i16x8_u, "i8x16.narrow_i16x8_u", 0xFD, 102) +OFD(F32x4__ceil, "f32x4.ceil", 0xFD, 103) +OFD(F32x4__floor, "f32x4.floor", 0xFD, 104) +OFD(F32x4__trunc, "f32x4.trunc", 0xFD, 105) +OFD(F32x4__nearest, "f32x4.nearest", 0xFD, 106) +OFD(I8x16__shl, "i8x16.shl", 0xFD, 107) +OFD(I8x16__shr_s, "i8x16.shr_s", 0xFD, 108) +OFD(I8x16__shr_u, "i8x16.shr_u", 0xFD, 109) +OFD(I8x16__add, "i8x16.add", 0xFD, 110) +OFD(I8x16__add_sat_s, "i8x16.add_sat_s", 0xFD, 111) +OFD(I8x16__add_sat_u, "i8x16.add_sat_u", 0xFD, 112) +OFD(I8x16__sub, "i8x16.sub", 0xFD, 113) +OFD(I8x16__sub_sat_s, "i8x16.sub_sat_s", 0xFD, 114) +OFD(I8x16__sub_sat_u, "i8x16.sub_sat_u", 0xFD, 115) +OFD(F64x2__ceil, "f64x2.ceil", 0xFD, 116) +OFD(F64x2__floor, "f64x2.floor", 0xFD, 117) +OFD(I8x16__min_s, "i8x16.min_s", 0xFD, 118) +OFD(I8x16__min_u, "i8x16.min_u", 0xFD, 119) +OFD(I8x16__max_s, "i8x16.max_s", 0xFD, 120) +OFD(I8x16__max_u, "i8x16.max_u", 0xFD, 121) +OFD(F64x2__trunc, "f64x2.trunc", 0xFD, 122) +OFD(I8x16__avgr_u, "i8x16.avgr_u", 0xFD, 123) +OFD(I16x8__extadd_pairwise_i8x16_s, "i16x8.extadd_pairwise_i8x16_s", 0xFD, 124) +OFD(I16x8__extadd_pairwise_i8x16_u, "i16x8.extadd_pairwise_i8x16_u", 0xFD, 125) +OFD(I32x4__extadd_pairwise_i16x8_s, "i32x4.extadd_pairwise_i16x8_s", 0xFD, 126) +OFD(I32x4__extadd_pairwise_i16x8_u, "i32x4.extadd_pairwise_i16x8_u", 0xFD, 127) +OFD(I16x8__abs, "i16x8.abs", 0xFD, 128) +OFD(I16x8__neg, "i16x8.neg", 0xFD, 129) +OFD(I16x8__q15mulr_sat_s, "i16x8.q15mulr_sat_s", 0xFD, 130) +OFD(I16x8__all_true, "i16x8.all_true", 0xFD, 131) +OFD(I16x8__bitmask, "i16x8.bitmask", 0xFD, 132) +OFD(I16x8__narrow_i32x4_s, "i16x8.narrow_i32x4_s", 0xFD, 133) +OFD(I16x8__narrow_i32x4_u, "i16x8.narrow_i32x4_u", 0xFD, 134) +OFD(I16x8__extend_low_i8x16_s, "i16x8.extend_low_i8x16_s", 0xFD, 135) +OFD(I16x8__extend_high_i8x16_s, "i16x8.extend_high_i8x16_s", 0xFD, 136) +OFD(I16x8__extend_low_i8x16_u, "i16x8.extend_low_i8x16_u", 0xFD, 137) +OFD(I16x8__extend_high_i8x16_u, "i16x8.extend_high_i8x16_u", 0xFD, 138) +OFD(I16x8__shl, "i16x8.shl", 0xFD, 139) +OFD(I16x8__shr_s, "i16x8.shr_s", 0xFD, 140) +OFD(I16x8__shr_u, "i16x8.shr_u", 0xFD, 141) +OFD(I16x8__add, "i16x8.add", 0xFD, 142) +OFD(I16x8__add_sat_s, "i16x8.add_sat_s", 0xFD, 143) +OFD(I16x8__add_sat_u, "i16x8.add_sat_u", 0xFD, 144) +OFD(I16x8__sub, "i16x8.sub", 0xFD, 145) +OFD(I16x8__sub_sat_s, "i16x8.sub_sat_s", 0xFD, 146) +OFD(I16x8__sub_sat_u, "i16x8.sub_sat_u", 0xFD, 147) +OFD(F64x2__nearest, "f64x2.nearest", 0xFD, 148) +OFD(I16x8__mul, "i16x8.mul", 0xFD, 149) +OFD(I16x8__min_s, "i16x8.min_s", 0xFD, 150) +OFD(I16x8__min_u, "i16x8.min_u", 0xFD, 151) +OFD(I16x8__max_s, "i16x8.max_s", 0xFD, 152) +OFD(I16x8__max_u, "i16x8.max_u", 0xFD, 153) +// 0xFD 154: Reserved +OFD(I16x8__avgr_u, "i16x8.avgr_u", 0xFD, 155) +OFD(I16x8__extmul_low_i8x16_s, "i16x8.extmul_low_i8x16_s", 0xFD, 156) +OFD(I16x8__extmul_high_i8x16_s, "i16x8.extmul_high_i8x16_s", 0xFD, 157) +OFD(I16x8__extmul_low_i8x16_u, "i16x8.extmul_low_i8x16_u", 0xFD, 158) +OFD(I16x8__extmul_high_i8x16_u, "i16x8.extmul_high_i8x16_u", 0xFD, 159) +OFD(I32x4__abs, "i32x4.abs", 0xFD, 160) +OFD(I32x4__neg, "i32x4.neg", 0xFD, 161) +// 0xFD 162: Reserved +OFD(I32x4__all_true, "i32x4.all_true", 0xFD, 163) +OFD(I32x4__bitmask, "i32x4.bitmask", 0xFD, 164) +// 0xFD 165: Reserved +// 0xFD 166: Reserved +OFD(I32x4__extend_low_i16x8_s, "i32x4.extend_low_i16x8_s", 0xFD, 167) +OFD(I32x4__extend_high_i16x8_s, "i32x4.extend_high_i16x8_s", 0xFD, 168) +OFD(I32x4__extend_low_i16x8_u, "i32x4.extend_low_i16x8_u", 0xFD, 169) +OFD(I32x4__extend_high_i16x8_u, "i32x4.extend_high_i16x8_u", 0xFD, 170) +OFD(I32x4__shl, "i32x4.shl", 0xFD, 171) +OFD(I32x4__shr_s, "i32x4.shr_s", 0xFD, 172) +OFD(I32x4__shr_u, "i32x4.shr_u", 0xFD, 173) +OFD(I32x4__add, "i32x4.add", 0xFD, 174) +// 0xFD 175: Reserved +// 0xFD 176: Reserved +OFD(I32x4__sub, "i32x4.sub", 0xFD, 177) +// 0xFD 178: Reserved +// 0xFD 179: Reserved +// 0xFD 180: Reserved +OFD(I32x4__mul, "i32x4.mul", 0xFD, 181) +OFD(I32x4__min_s, "i32x4.min_s", 0xFD, 182) +OFD(I32x4__min_u, "i32x4.min_u", 0xFD, 183) +OFD(I32x4__max_s, "i32x4.max_s", 0xFD, 184) +OFD(I32x4__max_u, "i32x4.max_u", 0xFD, 185) +OFD(I32x4__dot_i16x8_s, "i32x4.dot_i16x8_s", 0xFD, 186) +// 0xFD 187: Reserved +OFD(I32x4__extmul_low_i16x8_s, "i32x4.extmul_low_i16x8_s", 0xFD, 188) +OFD(I32x4__extmul_high_i16x8_s, "i32x4.extmul_high_i16x8_s", 0xFD, 189) +OFD(I32x4__extmul_low_i16x8_u, "i32x4.extmul_low_i16x8_u", 0xFD, 190) +OFD(I32x4__extmul_high_i16x8_u, "i32x4.extmul_high_i16x8_u", 0xFD, 191) +OFD(I64x2__abs, "i64x2.abs", 0xFD, 192) +OFD(I64x2__neg, "i64x2.neg", 0xFD, 193) +// 0xFD 194: Reserved +OFD(I64x2__all_true, "i64x2.all_true", 0xFD, 195) +OFD(I64x2__bitmask, "i64x2.bitmask", 0xFD, 196) +// 0xFD 197: Reserved +// 0xFD 198: Reserved +OFD(I64x2__extend_low_i32x4_s, "i64x2.extend_low_i32x4_s", 0xFD, 199) +OFD(I64x2__extend_high_i32x4_s, "i64x2.extend_high_i32x4_s", 0xFD, 200) +OFD(I64x2__extend_low_i32x4_u, "i64x2.extend_low_i32x4_u", 0xFD, 201) +OFD(I64x2__extend_high_i32x4_u, "i64x2.extend_high_i32x4_u", 0xFD, 202) +OFD(I64x2__shl, "i64x2.shl", 0xFD, 203) +OFD(I64x2__shr_s, "i64x2.shr_s", 0xFD, 204) +OFD(I64x2__shr_u, "i64x2.shr_u", 0xFD, 205) +OFD(I64x2__add, "i64x2.add", 0xFD, 206) +// 0xFD 207: Reserved +// 0xFD 208: Reserved +OFD(I64x2__sub, "i64x2.sub", 0xFD, 209) +// 0xFD 210: Reserved +// 0xFD 211: Reserved +// 0xFD 212: Reserved +OFD(I64x2__mul, "i64x2.mul", 0xFD, 213) +OFD(I64x2__eq, "i64x2.eq", 0xFD, 214) +OFD(I64x2__ne, "i64x2.ne", 0xFD, 215) +OFD(I64x2__lt_s, "i64x2.lt_s", 0xFD, 216) +OFD(I64x2__gt_s, "i64x2.gt_s", 0xFD, 217) +OFD(I64x2__le_s, "i64x2.le_s", 0xFD, 218) +OFD(I64x2__ge_s, "i64x2.ge_s", 0xFD, 219) +OFD(I64x2__extmul_low_i32x4_s, "i64x2.extmul_low_i32x4_s", 0xFD, 220) +OFD(I64x2__extmul_high_i32x4_s, "i64x2.extmul_high_i32x4_s", 0xFD, 221) +OFD(I64x2__extmul_low_i32x4_u, "i64x2.extmul_low_i32x4_u", 0xFD, 222) +OFD(I64x2__extmul_high_i32x4_u, "i64x2.extmul_high_i32x4_u", 0xFD, 223) +OFD(F32x4__abs, "f32x4.abs", 0xFD, 224) +OFD(F32x4__neg, "f32x4.neg", 0xFD, 225) +// 0xFD 226: Reserved +OFD(F32x4__sqrt, "f32x4.sqrt", 0xFD, 227) +OFD(F32x4__add, "f32x4.add", 0xFD, 228) +OFD(F32x4__sub, "f32x4.sub", 0xFD, 229) +OFD(F32x4__mul, "f32x4.mul", 0xFD, 230) +OFD(F32x4__div, "f32x4.div", 0xFD, 231) +OFD(F32x4__min, "f32x4.min", 0xFD, 232) +OFD(F32x4__max, "f32x4.max", 0xFD, 233) +OFD(F32x4__pmin, "f32x4.pmin", 0xFD, 234) +OFD(F32x4__pmax, "f32x4.pmax", 0xFD, 235) +OFD(F64x2__abs, "f64x2.abs", 0xFD, 236) +OFD(F64x2__neg, "f64x2.neg", 0xFD, 237) +OFD(F64x2__sqrt, "f64x2.sqrt", 0xFD, 239) +OFD(F64x2__add, "f64x2.add", 0xFD, 240) +OFD(F64x2__sub, "f64x2.sub", 0xFD, 241) +OFD(F64x2__mul, "f64x2.mul", 0xFD, 242) +OFD(F64x2__div, "f64x2.div", 0xFD, 243) +OFD(F64x2__min, "f64x2.min", 0xFD, 244) +OFD(F64x2__max, "f64x2.max", 0xFD, 245) +OFD(F64x2__pmin, "f64x2.pmin", 0xFD, 246) +OFD(F64x2__pmax, "f64x2.pmax", 0xFD, 247) +OFD(I32x4__trunc_sat_f32x4_s, "i32x4.trunc_sat_f32x4_s", 0xFD, 248) +OFD(I32x4__trunc_sat_f32x4_u, "i32x4.trunc_sat_f32x4_u", 0xFD, 249) +OFD(F32x4__convert_i32x4_s, "f32x4.convert_i32x4_s", 0xFD, 250) +OFD(F32x4__convert_i32x4_u, "f32x4.convert_i32x4_u", 0xFD, 251) +OFD(I32x4__trunc_sat_f64x2_s_zero, "i32x4.trunc_sat_f64x2_s_zero", 0xFD, 252) +OFD(I32x4__trunc_sat_f64x2_u_zero, "i32x4.trunc_sat_f64x2_u_zero", 0xFD, 253) +OFD(F64x2__convert_low_i32x4_s, "f64x2.convert_low_i32x4_s", 0xFD, 254) +OFD(F64x2__convert_low_i32x4_u, "f64x2.convert_low_i32x4_u", 0xFD, 255) + +// 0xFE prefix - Relaxed SIMD Instructions (part 4) +OFD(I8x16__relaxed_swizzle, "i8x16.relaxed_swizzle", 0xFD, 256) +OFD(I32x4__relaxed_trunc_f32x4_s, "i32x4.relaxed_trunc_f32x4_s", 0xFD, 257) +OFD(I32x4__relaxed_trunc_f32x4_u, "i32x4.relaxed_trunc_f32x4_u", 0xFD, 258) +OFD(I32x4__relaxed_trunc_f64x2_s_zero, "i32x4.relaxed_trunc_f64x2_s_zero", 0xFD, + 259) +OFD(I32x4__relaxed_trunc_f64x2_u_zero, "i32x4.relaxed_trunc_f64x2_u_zero", 0xFD, + 260) +OFD(F32x4__relaxed_madd, "f32x4.relaxed_madd", 0xFD, 261) +OFD(F32x4__relaxed_nmadd, "f32x4.relaxed_nmadd", 0xFD, 262) +OFD(F64x2__relaxed_madd, "f32x4.relaxed_madd", 0xFD, 263) +OFD(F64x2__relaxed_nmadd, "f32x4.relaxed_nmadd", 0xFD, 264) +OFD(I8x16__relaxed_laneselect, "i8x16.relaxed_laneselect", 0xFD, 265) +OFD(I16x8__relaxed_laneselect, "i16x8.relaxed_laneselect", 0xFD, 266) +OFD(I32x4__relaxed_laneselect, "i32x4.relaxed_laneselect", 0xFD, 267) +OFD(I64x2__relaxed_laneselect, "i64x2.relaxed_laneselect", 0xFD, 268) +OFD(F32x4__relaxed_min, "f32x4.relaxed_min", 0xFD, 269) +OFD(F32x4__relaxed_max, "f32x4.relaxed_max", 0xFD, 270) +OFD(F64x2__relaxed_min, "f64x2.relaxed_min", 0xFD, 271) +OFD(F64x2__relaxed_max, "f64x2.relaxed_max", 0xFD, 272) +OFD(I16x8__relaxed_q15mulr_s, "i16x8.relaxed_q15mulr_s", 0xFD, 273) +OFD(I16x8__relaxed_dot_i8x16_i7x16_s, "i16x8.relaxed_dot_i8x16_i7x16_s", 0xFD, + 274) +OFD(I32x4__relaxed_dot_i8x16_i7x16_add_s, "i32x4.relaxed_dot_i8x16_i7x16_add_s", + 0xFD, 275) +// 0xFD 276 ~ 303: Reserved + +// 0xFE prefix - Atomic instructions +OFE(Memory__atomic__notify, "memory.atomic.notify", 0xFE, 0) +OFE(Memory__atomic__wait32, "memory.atomic.wait32", 0xFE, 1) +OFE(Memory__atomic__wait64, "memory.atomic.wait64", 0xFE, 2) +OFE(Atomic__fence, "atomic.fence", 0xFE, 3) +// 0xFE 4 ~ 15: Reserved +OFE(I32__atomic__load, "i32.atomic.load", 0xFE, 16) +OFE(I64__atomic__load, "i64.atomic.load", 0xFE, 17) +OFE(I32__atomic__load8_u, "i32.atomic.load8_u", 0xFE, 18) +OFE(I32__atomic__load16_u, "i32.atomic.load16_u", 0xFE, 19) +OFE(I64__atomic__load8_u, "i64.atomic.load8_u", 0xFE, 20) +OFE(I64__atomic__load16_u, "i64.atomic.load16_u", 0xFE, 21) +OFE(I64__atomic__load32_u, "i64.atomic.load32_u", 0xFE, 22) +OFE(I32__atomic__store, "i32.atomic.store", 0xFE, 23) +OFE(I64__atomic__store, "i64.atomic.store", 0xFE, 24) +OFE(I32__atomic__store8, "i32.atomic.store8", 0xFE, 25) +OFE(I32__atomic__store16, "i32.atomic.store16", 0xFE, 26) +OFE(I64__atomic__store8, "i64.atomic.store8", 0xFE, 27) +OFE(I64__atomic__store16, "i64.atomic.store16", 0xFE, 28) +OFE(I64__atomic__store32, "i64.atomic.store32", 0xFE, 29) +OFE(I32__atomic__rmw__add, "i32.atomic.rmw.add", 0xFE, 30) +OFE(I64__atomic__rmw__add, "i64.atomic.rmw.add", 0xFE, 31) +OFE(I32__atomic__rmw8__add_u, "i32.atomic.rmw8.add_u", 0xFE, 32) +OFE(I32__atomic__rmw16__add_u, "i32.atomic.rmw16.add_u", 0xFE, 33) +OFE(I64__atomic__rmw8__add_u, "i64.atomic.rmw8.add_u", 0xFE, 34) +OFE(I64__atomic__rmw16__add_u, "i64.atomic.rmw16.add_u", 0xFE, 35) +OFE(I64__atomic__rmw32__add_u, "i64.atomic.rmw32.add_u", 0xFE, 36) +OFE(I32__atomic__rmw__sub, "i32.atomic.rmw.sub", 0xFE, 37) +OFE(I64__atomic__rmw__sub, "i64.atomic.rmw.sub", 0xFE, 38) +OFE(I32__atomic__rmw8__sub_u, "i32.atomic.rmw8.sub_u", 0xFE, 39) +OFE(I32__atomic__rmw16__sub_u, "i32.atomic.rmw16.sub_u", 0xFE, 40) +OFE(I64__atomic__rmw8__sub_u, "i64.atomic.rmw8.sub_u", 0xFE, 41) +OFE(I64__atomic__rmw16__sub_u, "i64.atomic.rmw16.sub_u", 0xFE, 42) +OFE(I64__atomic__rmw32__sub_u, "i64.atomic.rmw32.sub_u", 0xFE, 43) +OFE(I32__atomic__rmw__and, "i32.atomic.rmw.and", 0xFE, 44) +OFE(I64__atomic__rmw__and, "i64.atomic.rmw.and", 0xFE, 45) +OFE(I32__atomic__rmw8__and_u, "i32.atomic.rmw8.and_u", 0xFE, 46) +OFE(I32__atomic__rmw16__and_u, "i32.atomic.rmw16.and_u", 0xFE, 47) +OFE(I64__atomic__rmw8__and_u, "i64.atomic.rmw8.and_u", 0xFE, 48) +OFE(I64__atomic__rmw16__and_u, "i64.atomic.rmw16.and_u", 0xFE, 49) +OFE(I64__atomic__rmw32__and_u, "i64.atomic.rmw32.and_u", 0xFE, 50) +OFE(I32__atomic__rmw__or, "i32.atomic.rmw.or", 0xFE, 51) +OFE(I64__atomic__rmw__or, "i64.atomic.rmw.or", 0xFE, 52) +OFE(I32__atomic__rmw8__or_u, "i32.atomic.rmw8.or_u", 0xFE, 53) +OFE(I32__atomic__rmw16__or_u, "i32.atomic.rmw16.or_u", 0xFE, 54) +OFE(I64__atomic__rmw8__or_u, "i64.atomic.rmw8.or_u", 0xFE, 55) +OFE(I64__atomic__rmw16__or_u, "i64.atomic.rmw16.or_u", 0xFE, 56) +OFE(I64__atomic__rmw32__or_u, "i64.atomic.rmw32.or_u", 0xFE, 57) +OFE(I32__atomic__rmw__xor, "i32.atomic.rmw.xor", 0xFE, 58) +OFE(I64__atomic__rmw__xor, "i64.atomic.rmw.xor", 0xFE, 59) +OFE(I32__atomic__rmw8__xor_u, "i32.atomic.rmw8.xor_u", 0xFE, 60) +OFE(I32__atomic__rmw16__xor_u, "i32.atomic.rmw16.xor_u", 0xFE, 61) +OFE(I64__atomic__rmw8__xor_u, "i64.atomic.rmw8.xor_u", 0xFE, 62) +OFE(I64__atomic__rmw16__xor_u, "i64.atomic.rmw16.xor_u", 0xFE, 63) +OFE(I64__atomic__rmw32__xor_u, "i64.atomic.rmw32.xor_u", 0xFE, 64) +OFE(I32__atomic__rmw__xchg, "i32.atomic.rmw.xchg", 0xFE, 65) +OFE(I64__atomic__rmw__xchg, "i64.atomic.rmw.xchg", 0xFE, 66) +OFE(I32__atomic__rmw8__xchg_u, "i32.atomic.rmw8.xchg_u", 0xFE, 67) +OFE(I32__atomic__rmw16__xchg_u, "i32.atomic.rmw16.xchg_u", 0xFE, 68) +OFE(I64__atomic__rmw8__xchg_u, "i64.atomic.rmw8.xchg_u", 0xFE, 69) +OFE(I64__atomic__rmw16__xchg_u, "i64.atomic.rmw16.xchg_u", 0xFE, 70) +OFE(I64__atomic__rmw32__xchg_u, "i64.atomic.rmw32.xchg_u", 0xFE, 71) +OFE(I32__atomic__rmw__cmpxchg, "i32.atomic.rmw.cmpxchg", 0xFE, 72) +OFE(I64__atomic__rmw__cmpxchg, "i64.atomic.rmw.cmpxchg", 0xFE, 73) +OFE(I32__atomic__rmw8__cmpxchg_u, "i32.atomic.rmw8.cmpxchg_u", 0xFE, 74) +OFE(I32__atomic__rmw16__cmpxchg_u, "i32.atomic.rmw16.cmpxchg_u", 0xFE, 75) +OFE(I64__atomic__rmw8__cmpxchg_u, "i64.atomic.rmw8.cmpxchg_u", 0xFE, 76) +OFE(I64__atomic__rmw16__cmpxchg_u, "i64.atomic.rmw16.cmpxchg_u", 0xFE, 77) +OFE(I64__atomic__rmw32__cmpxchg_u, "i64.atomic.rmw32.cmpxchg_u", 0xFE, 78) #undef O +#undef OFB +#undef OFC +#undef OFD +#undef OFE #endif // UseOpCode // enum_configure.h #ifdef UseProposal #define P Line -P(ImportExportMutGlobals, "Import/Export of mutable globals") -P(NonTrapFloatToIntConversions, "Non-trapping float-to-int conversions") -P(SignExtensionOperators, "Sign-extension operators") -P(MultiValue, "Multi-value returns") -P(BulkMemoryOperations, "Bulk memory operations") -P(ReferenceTypes, "Reference types") +// Finished and standardized proposals +P(ImportExportMutGlobals, "Import/Export of Mutable Globals") +P(NonTrapFloatToIntConversions, "Non-trapping float-to-int Conversions") +P(SignExtensionOperators, "Sign-extension Operators") +P(MultiValue, "Multi-value") +P(BulkMemoryOperations, "Bulk Memory Operations") +P(ReferenceTypes, "Reference Types") P(SIMD, "Fixed-width SIMD") -P(TailCall, "Tail call") -P(MultiMemories, "Multiple memories") +// Phase 4 proposals +P(TailCall, "Tail Call") +P(ExtendedConst, "Extended Const Expressions") +P(FunctionReferences, "Typed Function References") +P(GC, "Garbage Collection") +P(MultiMemories, "Multiple Memories") +P(Threads, "Threads") +P(RelaxSIMD, "Relaxed SIMD") +// Phase 3 proposals P(Annotations, "Custom Annotation Syntax in the Text Format") P(Memory64, "Memory64") -P(ExceptionHandling, "Exception handling") -P(ExtendedConst, "Extended const") -P(Threads, "Threads") -P(FunctionReferences, "Typed Function References") -P(Component, "Component model") +P(ExceptionHandling, "Exception Handling") +// Phase 1 proposals +P(Component, "Component Model") #undef P #endif // UseProposal @@ -716,8 +820,10 @@ E(NonNullRequired, 0x0009, "set null value into non-nullable value type") E(SetValueToConst, 0x000A, "set value into const") // Set value failed due to mismatch value type E(SetValueErrorType, 0x000B, "set value type mismatch") +// JIT is disabled +E(JITDisabled, 0x000C, "JIT is disabled in this build") // User defined error -E(UserDefError, 0x000C, "user defined error code") +E(UserDefError, 0x000D, "user defined error code") // Load phase // @{ @@ -781,6 +887,8 @@ E(SharedMemoryNoMax, 0x011A, "shared memory must have maximum") E(IntrinsicsTableNotFound, 0x011B, "intrinsics table not found") // Malformed table (Ref-types proposal) E(MalformedTable, 0x011C, "malformed table") +// Alignment must < 64 without and < 128 with multi-memory proposal. +E(InvalidStoreAlignment, 0x011D, "invalid store alignment") // @} // Validation phase @@ -805,58 +913,62 @@ E(InvalidTableIdx, 0x0207, "unknown table") E(InvalidMemoryIdx, 0x0208, "unknown memory") // Global index not defined E(InvalidGlobalIdx, 0x0209, "unknown global") +// Tag index not defined +E(InvalidTagIdx, 0x020A, "unknown tag") // Element segment index not defined -E(InvalidElemIdx, 0x020A, "unknown elem segment") +E(InvalidElemIdx, 0x020B, "unknown elem segment") // Data segment index not defined -E(InvalidDataIdx, 0x020B, "unknown data segment") +E(InvalidDataIdx, 0x020C, "unknown data segment") // Undeclared reference -E(InvalidRefIdx, 0x020C, "undeclared function reference") +E(InvalidRefIdx, 0x020D, "undeclared function reference") // Should be constant expression -E(ConstExprRequired, 0x020D, "constant expression required") +E(ConstExprRequired, 0x020E, "constant expression required") // Export name conflicted -E(DupExportName, 0x020E, "duplicate export name") +E(DupExportName, 0x020F, "duplicate export name") // Tried to store to const global value -E(ImmutableGlobal, 0x020F, "global is immutable") +E(ImmutableGlobal, 0x0210, "global is immutable") // Tried to store to const field of structure -E(ImmutableField, 0x0210, "field is immutable") +E(ImmutableField, 0x0211, "field is immutable") // Tried to store to const array -E(ImmutableArray, 0x0211, "array is immutable") +E(ImmutableArray, 0x0212, "array is immutable") // Invalid result arity in select t* instruction -E(InvalidResultArity, 0x0212, "invalid result arity") +E(InvalidResultArity, 0x0213, "invalid result arity") // #Tables > 1 (without Ref-types proposal) -E(MultiTables, 0x0213, "multiple tables") +E(MultiTables, 0x0214, "multiple tables") // #Memories > 1 -E(MultiMemories, 0x0214, "multiple memories") +E(MultiMemories, 0x0215, "multiple memories") // Invalid Limit grammar -E(InvalidLimit, 0x0215, "size minimum must not be greater than maximum") +E(InvalidLimit, 0x0216, "size minimum must not be greater than maximum") // Memory pages > 65536 -E(InvalidMemPages, 0x0216, "memory size must be at most 65536 pages (4GiB)") +E(InvalidMemPages, 0x0217, "memory size must be at most 65536 pages (4GiB)") // Invalid start function signature -E(InvalidStartFunc, 0x0217, "start function") +E(InvalidStartFunc, 0x0218, "start function") // Invalid lane index -E(InvalidLaneIdx, 0x0218, "invalid lane index") +E(InvalidLaneIdx, 0x0219, "invalid lane index") // Invalid uninitialized local -E(InvalidUninitLocal, 0x0219, "uninitialized local") +E(InvalidUninitLocal, 0x021A, "uninitialized local") // Defaultable field type required -E(InvalidNotDefaultableField, 0x021A, "field type is not defaultable") +E(InvalidNotDefaultableField, 0x021B, "field type is not defaultable") // Defaultable array type required -E(InvalidNotDefaultableArray, 0x021B, "array type is not defaultable") +E(InvalidNotDefaultableArray, 0x021C, "array type is not defaultable") // Unpacked field type required, but got packed one -E(InvalidPackedField, 0x021C, "field is packed") +E(InvalidPackedField, 0x021D, "field is packed") // Unpacked array type required, but got packed one -E(InvalidPackedArray, 0x021D, "array is packed") +E(InvalidPackedArray, 0x021E, "array is packed") // Packed field type required, but got unpacked one -E(InvalidUnpackedField, 0x021E, "field is unpacked") +E(InvalidUnpackedField, 0x021F, "field is unpacked") // Packed array type required, but got unpacked one -E(InvalidUnpackedArray, 0x021F, "array is unpacked") +E(InvalidUnpackedArray, 0x0220, "array is unpacked") // Invalid Br ref type -E(InvalidBrRefType, 0x0220, "invalid br ref type") +E(InvalidBrRefType, 0x0221, "invalid br ref type") // 2 array types not matched -E(ArrayTypesMismatch, 0x0221, "array types do not match") +E(ArrayTypesMismatch, 0x0222, "array types do not match") // Should be numeric type in array type -E(ArrayTypesNumtypeRequired, 0x0222, "array type is not numeric or vector") +E(ArrayTypesNumtypeRequired, 0x0223, "array type is not numeric or vector") // Sub type matching or validation failed -E(InvalidSubType, 0x0223, "sub type") +E(InvalidSubType, 0x0224, "sub type") +// Invalid Tag type +E(InvalidTagResultType, 0x0225, "non-empty tag result type") // @} // Instantiation phase @@ -871,6 +983,9 @@ E(UnknownImport, 0x0302, "unknown import") E(DataSegDoesNotFit, 0x0303, "data segment does not fit") // Init failed when instantiating element segment E(ElemSegDoesNotFit, 0x0304, "elements segment does not fit") +// Invalid core sort for component export +E(InvalidCoreSort, 0x0305, "invalid core sort") +E(InvalidCanonOption, 0x0306, "invalid canonical option") // @} // Execution phase @@ -921,11 +1036,15 @@ E(AccessNullStruct, 0x0414, "null structure reference") E(AccessNullArray, 0x0415, "null array reference") // Access to null i31 reference E(AccessNullI31, 0x0416, "null i31 reference") +// Access to null exception reference +E(AccessNullException, 0x0417, "null exception reference") // Fail to cast reference -E(CastFailed, 0x0417, "cast failure") +E(CastFailed, 0x0418, "cast failure") +// Uncaught Exception +E(UncaughtException, 0x0419, "uncaught exception") // @} -// Component model phase +// Component model load phase // @{ // Malformed sort E(MalformedSort, 0x0500, "malformed sort") @@ -953,6 +1072,11 @@ E(UnknownCanonicalOption, 0x050A, "unknown canonical option") E(MalformedName, 0x050B, "malformed name") // @} +// Component model instantiation phase +// @{ +E(CoreInvalidExport, 0x0600, "invalid export in core module") +// @} + #undef E #endif // UseErrCode @@ -1002,6 +1126,7 @@ M(Version, "version") // Versions I(Label, "label") I(Local, "local") +I(DefinedType, "defined type") I(FunctionType, "function type") I(Function, "function") I(Table, "table") @@ -1010,6 +1135,9 @@ I(Global, "global") I(Element, "element") I(Data, "data") I(Lane, "lane") +I(Field, "field") +I(TagType, "tag type") +I(Tag, "tag") #undef I #endif // UseIndexCategory @@ -1037,6 +1165,7 @@ T(EqRef, 0x6D, "eq") // -0x13 for heap type T(I31Ref, 0x6C, "i31") // -0x14 for heap type T(StructRef, 0x6B, "struct") // -0x15 for heap type T(ArrayRef, 0x6A, "array") // -0x16 for heap type +T(ExnRef, 0x69, "exn") // -0x17 for reference type T(Ref, 0x64, "ref") // -0x1C for reference type T(RefNull, 0x63, "ref_null") // -0x1D for reference type T(Func, 0x60, "func") // -0x20 for composite type @@ -1046,6 +1175,8 @@ T(Sub, 0x50, "sub") // -0x30 for sub type T(SubFinal, 0x4F, "sub_final") // -0x31 for sub type T(Rec, 0x4E, "rec") // -0x32 for recursive type T(Epsilon, 0x40, "-") // -0x40 for result type +// component model types +T(String, 0x80, "string") // string type #undef T #endif // UseTypeCode @@ -1066,6 +1197,7 @@ E(Function, 0x00U, "function") E(Table, 0x01U, "table") E(Memory, 0x02U, "memory") E(Global, 0x03U, "global") +E(Tag, 0x04U, "tag") #undef E #endif // UseExternalType diff --git a/include/common/enum_ast.hpp b/include/common/enum_ast.hpp index b2526fcef136..a0036fe2e711 100644 --- a/include/common/enum_ast.hpp +++ b/include/common/enum_ast.hpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/enum_ast.hpp - AST C++ enumerations ---------------===// // @@ -17,9 +17,9 @@ #pragma once -#include "dense_enum_map.h" -#include "log.h" -#include "spare_enum_map.h" +#include "common/dense_enum_map.h" +#include "common/spare_enum_map.h" +#include "common/spdlog.h" #include <cstdint> #include <string> @@ -46,15 +46,22 @@ static inline constexpr auto ASTNodeAttrStr = []() constexpr { #undef UseASTNodeAttr }; return DenseEnumMap(Array); -} -(); +}(); /// Instruction opcode enumeration class. -enum class OpCode : uint16_t { +enum class OpCode : uint32_t { #define UseOpCode -#define Line(NAME, VALUE, STRING) NAME = VALUE, +#define Line(NAME, STRING, PREFIX) NAME, +#define Line_FB(NAME, STRING, PREFIX, EXTEND) NAME, +#define Line_FC(NAME, STRING, PREFIX, EXTEND) NAME, +#define Line_FD(NAME, STRING, PREFIX, EXTEND) NAME, +#define Line_FE(NAME, STRING, PREFIX, EXTEND) NAME, #include "enum.inc" #undef Line +#undef Line_FB +#undef Line_FC +#undef Line_FD +#undef Line_FE #undef UseOpCode }; @@ -63,14 +70,21 @@ static inline constexpr const auto OpCodeStr = []() constexpr { using namespace std::literals::string_view_literals; std::pair<OpCode, std::string_view> Array[] = { #define UseOpCode -#define Line(NAME, VALUE, STRING) {OpCode::NAME, STRING}, +#define Line(NAME, STRING, PREFIX) {OpCode::NAME, STRING}, +#define Line_FB(NAME, STRING, PREFIX, EXTEND) {OpCode::NAME, STRING}, +#define Line_FC(NAME, STRING, PREFIX, EXTEND) {OpCode::NAME, STRING}, +#define Line_FD(NAME, STRING, PREFIX, EXTEND) {OpCode::NAME, STRING}, +#define Line_FE(NAME, STRING, PREFIX, EXTEND) {OpCode::NAME, STRING}, #include "enum.inc" #undef Line +#undef Line_FB +#undef Line_FC +#undef Line_FD +#undef Line_FE #undef UseOpCode }; return SpareEnumMap(Array); -} -(); +}(); } // namespace WasmEdge diff --git a/include/common/enum_configure.h b/include/common/enum_configure.h index dbf008a08a90..eb40f76c94c9 100644 --- a/include/common/enum_configure.h +++ b/include/common/enum_configure.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/enum_configure.h - Configure related enumerations -===// // diff --git a/include/common/enum_configure.hpp b/include/common/enum_configure.hpp index f3965a490f66..7035537d85e0 100644 --- a/include/common/enum_configure.hpp +++ b/include/common/enum_configure.hpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/enum_configure.hpp - Configure C++ enumerations ---===// // @@ -41,8 +41,7 @@ static inline constexpr auto ProposalStr = []() constexpr { #undef UseProposal }; return DenseEnumMap(Array); -} -(); +}(); /// Host Module Registration C++ enumeration class. enum class HostRegistration : uint8_t { diff --git a/include/common/enum_errcode.h b/include/common/enum_errcode.h index f40f441c31bc..68292cbcd960 100644 --- a/include/common/enum_errcode.h +++ b/include/common/enum_errcode.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/enum_errcode.h - Error code enumerations ----------===// // diff --git a/include/common/enum_errcode.hpp b/include/common/enum_errcode.hpp index 643d3178286d..43e33bd7a82d 100644 --- a/include/common/enum_errcode.hpp +++ b/include/common/enum_errcode.hpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/enum_errcode.h - Error code C++ enumerations ------===// // @@ -14,9 +14,9 @@ #pragma once -#include "dense_enum_map.h" -#include "log.h" -#include "spare_enum_map.h" +#include "common/dense_enum_map.h" +#include "common/spare_enum_map.h" +#include "common/spdlog.h" #include <cstdint> #include <string_view> diff --git a/include/common/enum_errinfo.hpp b/include/common/enum_errinfo.hpp index f385010a23d9..499d89a8dd65 100644 --- a/include/common/enum_errinfo.hpp +++ b/include/common/enum_errinfo.hpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/enum_errinfo.hpp - ErrInfo C++ enumerations -------===// // @@ -60,8 +60,7 @@ static inline constexpr auto PtrTypeStr = []() constexpr { #undef UsePtrType }; return DenseEnumMap(Array); -} -(); +}(); /// Error info mismatch category C++ enumeration class. enum class MismatchCategory : uint8_t { @@ -82,8 +81,7 @@ static inline constexpr auto MismatchCategoryStr = []() constexpr { #undef UseMismatchCategory }; return DenseEnumMap(Array); -} -(); +}(); /// Error info index category C++ enumeration class. enum class IndexCategory : uint8_t { @@ -104,8 +102,7 @@ static inline constexpr auto IndexCategoryStr = []() constexpr { #undef UseIndexCategory }; return DenseEnumMap(Array); -} -(); +}(); } // namespace ErrInfo } // namespace WasmEdge diff --git a/include/common/enum_types.h b/include/common/enum_types.h index b6a5e48b98e1..4b89c003f2e6 100644 --- a/include/common/enum_types.h +++ b/include/common/enum_types.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/enum_types.h - WASM types related enumerations ----===// // diff --git a/include/common/enum_types.hpp b/include/common/enum_types.hpp index 340e8ec192f8..9ebf6e3e1e27 100644 --- a/include/common/enum_types.hpp +++ b/include/common/enum_types.hpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/enum_types.hpp - WASM types C++ enumerations ------===// // diff --git a/include/common/errcode.h b/include/common/errcode.h index 8dcc2c53b70e..2661c5207260 100644 --- a/include/common/errcode.h +++ b/include/common/errcode.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/errcode.h - Error code definition -----------------===// // @@ -16,7 +16,7 @@ #include "common/enum_errcode.hpp" #include "common/expected.h" #include "common/hexstr.h" -#include "common/log.h" +#include "common/spdlog.h" #include <cassert> #include <ostream> diff --git a/include/common/errinfo.h b/include/common/errinfo.h index 975e127f744e..a652205ffafc 100644 --- a/include/common/errinfo.h +++ b/include/common/errinfo.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/errinfo.h - Error information definition ----------===// // @@ -19,7 +19,7 @@ #include "common/enum_errinfo.hpp" #include "common/enum_types.hpp" #include "common/filesystem.h" -#include "common/log.h" +#include "common/spdlog.h" #include "common/types.h" #include <cstdint> diff --git a/include/common/executable.h b/include/common/executable.h new file mode 100644 index 000000000000..2824170caeaf --- /dev/null +++ b/include/common/executable.h @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +//===-- wasmedge/common/executable.h - Executable Code definition ---------===// +// +// Part of the WasmEdge Project. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the declaration of the Executable, which holds interface +/// to executable binary objects. +/// +//===----------------------------------------------------------------------===// +#pragma once + +#include "common/defines.h" +#include "common/symbol.h" +#include "common/types.h" + +#include <cstdint> +#include <memory> +#include <vector> + +namespace WasmEdge { + +/// Holder class for library handle +class Executable : public std::enable_shared_from_this<Executable> { + Executable(const Executable &) = delete; + Executable &operator=(const Executable &) = delete; + Executable(Executable &&) = delete; + Executable &operator=(Executable &&) = delete; + +public: + Executable() noexcept = default; + virtual ~Executable() noexcept = default; + + /// Function type wrapper for symbols. + using Wrapper = void(void *ExecCtx, void *Function, const ValVariant *Args, + ValVariant *Rets); + + enum class Intrinsics : uint32_t { + kTrap, + kCall, + kCallIndirect, + kMemCopy, + kMemFill, + kMemGrow, + kMemSize, + kMemInit, + kDataDrop, + kTableGet, + kTableSet, + kTableCopy, + kTableFill, + kTableGrow, + kTableSize, + kTableInit, + kElemDrop, + kRefFunc, + kTableGetFuncSymbol, + kMemoryAtomicNotify, + kMemoryAtomicWait, + kCallRef, + kRefGetFuncSymbol, + kIntrinsicMax, + }; + using IntrinsicsTable = void * [uint32_t(Intrinsics::kIntrinsicMax)]; + + virtual Symbol<const IntrinsicsTable *> getIntrinsics() noexcept = 0; + + virtual std::vector<Symbol<Wrapper>> getTypes(size_t Size) noexcept = 0; + + virtual std::vector<Symbol<void>> getCodes(size_t Offset, + size_t Size) noexcept = 0; + +protected: + template <typename T> Symbol<T> createSymbol(T *Pointer) const noexcept { + return Symbol<T>(shared_from_this(), Pointer); + } +}; + +} // namespace WasmEdge diff --git a/include/common/expected.h b/include/common/expected.h index 2a9ca5bf10b8..ef958e4b605c 100644 --- a/include/common/expected.h +++ b/include/common/expected.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/common/filesystem.h b/include/common/filesystem.h index 51b79ffaa659..4e81d7fa9da8 100644 --- a/include/common/filesystem.h +++ b/include/common/filesystem.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/filesystem.h - std::filesystem selection ----------===// // diff --git a/include/common/hexstr.h b/include/common/hexstr.h index c9b372f0f63b..d50eeacf1eaa 100644 --- a/include/common/hexstr.h +++ b/include/common/hexstr.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/hexstr.h - Hex string formation -------------------===// // diff --git a/include/common/int128.h b/include/common/int128.h index 935fdf162ba6..41a32fc455f6 100644 --- a/include/common/int128.h +++ b/include/common/int128.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/int128.h - 128-bit integer type -------------------===// // @@ -13,24 +13,18 @@ //===----------------------------------------------------------------------===// #pragma once -#if defined(_MSC_VER) && !defined(__clang__) -#pragma intrinsic(_BitScanReverse64) -#endif - -#include <ostream> - // If there is a built-in type __int128, then use it directly #if defined(__x86_64__) || defined(__aarch64__) || \ (defined(__riscv) && __riscv_xlen == 64) - namespace WasmEdge { using int128_t = __int128; using uint128_t = unsigned __int128; -std::ostream &operator<<(std::ostream &OS, uint128_t Value); } // namespace WasmEdge - #else +#if defined(_MSC_VER) && !defined(__clang__) +#pragma intrinsic(_BitScanReverse64) +#endif // We have to detect for those environments who don't support __int128 type // natively. #include "endian.h" @@ -376,7 +370,6 @@ inline constexpr int128_t &int128_t::operator=(uint128_t V) noexcept { return *this = int128_t(V); } -std::ostream &operator<<(std::ostream &OS, uint128_t Value); } // namespace WasmEdge namespace std { @@ -467,3 +460,44 @@ template <> class numeric_limits<WasmEdge::int128_t> { } // namespace std #endif + +#include <type_traits> +namespace std { +template <> struct is_class<WasmEdge::uint128_t> : std::true_type {}; +} // namespace std + +#include <fmt/format.h> + +#if !FMT_USE_INT128 + +FMT_BEGIN_NAMESPACE +template <typename Char> struct formatter<WasmEdge::uint128_t, Char> { +private: + detail::dynamic_format_specs<> Specs; + +public: + template <typename ParseContext> constexpr auto parse(ParseContext &Ctx) { + return parse_format_specs(Ctx.begin(), Ctx.end(), Specs, Ctx, + detail::type::uint_type); + } + + template <typename FormatContext> + auto format(WasmEdge::uint128_t V, FormatContext &Ctx) const { + auto S = Specs; + detail::handle_dynamic_spec<detail::width_checker>(S.width, S.width_ref, + Ctx); + detail::handle_dynamic_spec<detail::precision_checker>( + S.precision, S.precision_ref, Ctx); + constexpr const unsigned Prefixes[4] = {0, 0, 0x1000000u | '+', + 0x1000000u | ' '}; + const detail::uint128_t U{static_cast<uint64_t>(V >> 64), + static_cast<uint64_t>(V)}; + return detail::write_int<Char>( + Ctx.out(), + detail::write_int_arg<detail::uint128_t>{U, Prefixes[S.sign]}, S, + Ctx.locale()); + } +}; +FMT_END_NAMESPACE + +#endif diff --git a/include/common/roundeven.h b/include/common/roundeven.h index 0521fb764536..d06d34f102d6 100644 --- a/include/common/roundeven.h +++ b/include/common/roundeven.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/roundeven.h - rounding to nearest integer ---------===// // diff --git a/include/common/span.h b/include/common/span.h index b606cb025f2f..426ac9dfcbf8 100644 --- a/include/common/span.h +++ b/include/common/span.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/span.h - Helper template of std::span -------------===// // diff --git a/include/common/spare_enum_map.h b/include/common/spare_enum_map.h index 87d243859695..369d6cc18fd1 100644 --- a/include/common/spare_enum_map.h +++ b/include/common/spare_enum_map.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/spare_enum_map.h - mapping spare enum to data -----===// // diff --git a/include/common/log.h b/include/common/spdlog.h similarity index 90% rename from include/common/log.h rename to include/common/spdlog.h index fa3ec2df93b6..4e30b90f3504 100644 --- a/include/common/log.h +++ b/include/common/spdlog.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC -//===-- wasmedge/common/log.h - Logging system ----------------------------===// +//===-- wasmedge/common/spdlog.h - Logging system -------------------------===// // // Part of the WasmEdge Project. // @@ -14,6 +14,7 @@ #pragma once #include "common/filesystem.h" +#include "common/int128.h" #define SPDLOG_NO_EXCEPTIONS 1 #include "spdlog/spdlog.h" diff --git a/include/common/statistics.h b/include/common/statistics.h index d06f8460f71d..db0c579e3e51 100644 --- a/include/common/statistics.h +++ b/include/common/statistics.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/statistics.h - Executor statistics definition -----===// // @@ -16,8 +16,8 @@ #include "common/configure.h" #include "common/enum_ast.hpp" #include "common/errcode.h" -#include "common/log.h" #include "common/span.h" +#include "common/spdlog.h" #include "common/timer.h" #include <atomic> diff --git a/include/common/symbol.h b/include/common/symbol.h index 282333b56df9..b68e920b4aef 100644 --- a/include/common/symbol.h +++ b/include/common/symbol.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/symbol.h - Symbol definition ----------------------===// // @@ -16,19 +16,16 @@ #include <memory> -namespace WasmEdge::Loader { -class SharedLibrary; -} - namespace WasmEdge { +class Executable; /// Holder class for library symbol template <typename T = void> class Symbol { private: - friend class Loader::SharedLibrary; + friend class Executable; template <typename> friend class Symbol; - Symbol(std::shared_ptr<Loader::SharedLibrary> H, T *S) noexcept + Symbol(std::shared_ptr<const Executable> H, T *S) noexcept : Library(std::move(H)), Pointer(S) {} public: @@ -57,16 +54,16 @@ template <typename T = void> class Symbol { } private: - std::shared_ptr<Loader::SharedLibrary> Library; + std::shared_ptr<const Executable> Library; T *Pointer = nullptr; }; template <typename T> class Symbol<T[]> { private: - friend class Loader::SharedLibrary; + friend class Executable; template <typename> friend class Symbol; - Symbol(std::shared_ptr<Loader::SharedLibrary> H, T (*S)[]) noexcept + Symbol(std::shared_ptr<const Executable> H, T (*S)[]) noexcept : Library(std::move(H)), Pointer(*S) {} public: @@ -88,7 +85,7 @@ template <typename T> class Symbol<T[]> { } private: - std::shared_ptr<Loader::SharedLibrary> Library; + std::shared_ptr<const Executable> Library; T *Pointer = nullptr; }; diff --git a/include/common/timer.h b/include/common/timer.h index ec20b85c86a9..820749a63234 100644 --- a/include/common/timer.h +++ b/include/common/timer.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/timer.h - Timer class definition ------------------===// // diff --git a/include/common/types.h b/include/common/types.h index a13cd555c94e..cd66cbe95090 100644 --- a/include/common/types.h +++ b/include/common/types.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/types.h - Types definition ------------------------===// // @@ -61,20 +61,22 @@ using doublex2_t = SIMDArray<double, 16>; using floatx4_t = SIMDArray<float, 16>; // The bit pattern of the value types: -// ---------------------------------------------------------------------------- -// byte | 0th | 1st | 2nd | 3rd | 4th ~ 7th -// ------|-----------|--------------|---------------------|-------------------- -// | | ValTypeCode | For the HeapType use -// | | 0x7F, 0x7E, | (Function references and GC proposal) -// | | 0x7D, 0x7C, | HeapTypeCode | -// | | (numtype) | 0x00, 0x40, | Type index -// code | Reserved | 0x7B, | 0x70, 0x6F, | (uint32_t) -// | (Padding) | (vectype) | (func-ref proposal) | -// | | 0x78, 0x77, | 0x73, 0x72, 0x71, | -// | | (packedtype) | 0x6E, 0x6D, 0x6C, | -// | | 0x64, 0x63 | 0x6B, 0x6A | -// | | (reftype) | (GC proposal) | -// ---------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// byte | 0th | 1st | 2nd | 3rd | 4th ~ 7th +// ------|-------------|--------------|---------------------|------------------- +// | | ValTypeCode | For the HeapType use +// | 0th: | 0x7F, 0x7E, | (Function references and GC proposal) +// | Reserved | 0x7D, 0x7C, | HeapTypeCode | +// | (Padding) | (numtype) | 0x00, 0x40, | Type index +// code | | 0x7B, | 0x70, 0x6F, | (uint32_t) +// | | (vectype) | (func-ref proposal) | +// | 1st: | 0x78, 0x77, | 0x73, 0x72, 0x71, | +// | Externalize | (packedtype) | 0x6E, 0x6D, 0x6C, | +// | | 0x64, 0x63 | 0x6B, 0x6A, | +// | | (reftype) | (GC proposal) | +// | | | 0x69 | +// | | | (Exception handling proposal) +// ----------------------------------------------------------------------------- // In order to compress the various value type definitions into uint64_t length, // WasmEdge implements the ValType class for extending the value types. // As the definitions in the typed function references and GC proposal, the @@ -89,6 +91,7 @@ class ValType { ValType() noexcept = default; // General constructors for initializing data. ValType(TypeCode C, TypeCode HT, uint32_t I) noexcept { + Inner.Data.Externalize = 0; Inner.Data.Code = C; Inner.Data.HTCode = HT; Inner.Data.Idx = I; @@ -98,6 +101,7 @@ class ValType { } // Constructor for the value type codes without heap type immediates. ValType(TypeCode C) noexcept { + Inner.Data.Externalize = 0; Inner.Data.Idx = 0; switch (C) { case TypeCode::I32: @@ -123,10 +127,16 @@ class ValType { case TypeCode::I31Ref: case TypeCode::StructRef: case TypeCode::ArrayRef: + case TypeCode::ExnRef: // Abstract heap type Inner.Data.Code = TypeCode::RefNull; Inner.Data.HTCode = C; break; + case TypeCode::String: + // Abstract heap type + Inner.Data.Code = TypeCode::String; + Inner.Data.HTCode = C; + break; case TypeCode::Ref: case TypeCode::RefNull: // Reference type with heap immediates should use the constructors below. @@ -136,14 +146,15 @@ class ValType { } // Constructor for the value type with abs heap type in reference type. ValType(TypeCode C, TypeCode HT) noexcept { + Inner.Data.Externalize = 0; Inner.Data.Code = C; Inner.Data.HTCode = HT; Inner.Data.Idx = 0; assuming(isAbsHeapType()); - assuming(isRefType()); } // Constructor for the value type with type index in reference type. ValType(TypeCode C, uint32_t I) noexcept { + Inner.Data.Externalize = 0; Inner.Data.Code = C; Inner.Data.HTCode = TypeCode::TypeIndex; Inner.Data.Idx = I; @@ -207,11 +218,14 @@ class ValType { bool isFuncRefType() const noexcept { return (Inner.Data.HTCode == TypeCode::FuncRef) || + (Inner.Data.HTCode == TypeCode::NullFuncRef) || (Inner.Data.HTCode == TypeCode::TypeIndex); } bool isExternRefType() const noexcept { - return (Inner.Data.HTCode == TypeCode::ExternRef); + return (Inner.Data.HTCode == TypeCode::ExternRef) || + (Inner.Data.HTCode == TypeCode::NullExternRef) || + Inner.Data.Externalize; } bool isNullableRefType() const noexcept { @@ -219,28 +233,77 @@ class ValType { } bool isAbsHeapType() const noexcept { - switch (Inner.Data.HTCode) { - case TypeCode::NullFuncRef: - case TypeCode::NullExternRef: - case TypeCode::NullRef: - case TypeCode::FuncRef: - case TypeCode::ExternRef: - case TypeCode::AnyRef: - case TypeCode::EqRef: - case TypeCode::I31Ref: - case TypeCode::StructRef: - case TypeCode::ArrayRef: - return true; + if (isRefType()) { + switch (Inner.Data.HTCode) { + case TypeCode::NullFuncRef: + case TypeCode::NullExternRef: + case TypeCode::NullRef: + case TypeCode::FuncRef: + case TypeCode::ExternRef: + case TypeCode::AnyRef: + case TypeCode::EqRef: + case TypeCode::I31Ref: + case TypeCode::StructRef: + case TypeCode::ArrayRef: + case TypeCode::ExnRef: + case TypeCode::String: + return true; + default: + return false; + } + } + return false; + } + + uint32_t getBitWidth() const noexcept { + switch (Inner.Data.Code) { + case TypeCode::I8: + return 8U; + case TypeCode::I16: + return 16U; + case TypeCode::I32: + case TypeCode::F32: + return 32U; + case TypeCode::I64: + case TypeCode::F64: + return 64U; + case TypeCode::V128: + return 128U; default: - return false; + // Bit width not available for reftypes. + assumingUnreachable(); } } -protected: + ValType getNullableRef() const noexcept { + assuming(isRefType()); + return ValType(TypeCode::RefNull, Inner.Data.HTCode, Inner.Data.Idx); + } + ValType &toNullableRef() noexcept { + assuming(isRefType()); + Inner.Data.Code = TypeCode::RefNull; + return *this; + } + ValType getNonNullableRef() const noexcept { + assuming(isRefType()); + return ValType(TypeCode::Ref, Inner.Data.HTCode, Inner.Data.Idx); + } + ValType &toNonNullableRef() noexcept { + assuming(isRefType()); + Inner.Data.Code = TypeCode::Ref; + return *this; + } + + void setExternalized() noexcept { Inner.Data.Externalize = 1U; } + void setInternalized() noexcept { Inner.Data.Externalize = 0U; } + bool isExternalized() noexcept { return Inner.Data.Externalize != 0U; } + +private: union { uint8_t Raw[8]; struct { - uint8_t Paddings[2]; + uint8_t Padding; + uint8_t Externalize; TypeCode Code; TypeCode HTCode; uint32_t Idx; @@ -303,6 +366,8 @@ class BlockType { /// FuncRef definition. namespace Runtime::Instance { class FunctionInstance; +class StructInstance; +class ArrayInstance; } // namespace Runtime::Instance /// NumType and RefType variant definitions. @@ -317,9 +382,18 @@ struct RefVariant { template <typename T> RefVariant(const T *P) noexcept { setData(TypeCode::ExternRef, reinterpret_cast<const void *>(P)); } + template <typename T> RefVariant(const ValType &VT, const T *P) noexcept { + setData(VT, reinterpret_cast<const void *>(P)); + } RefVariant(const Runtime::Instance::FunctionInstance *P) noexcept { setData(TypeCode::FuncRef, reinterpret_cast<const void *>(P)); } + RefVariant(const Runtime::Instance::StructInstance *P) noexcept { + setData(TypeCode::StructRef, reinterpret_cast<const void *>(P)); + } + RefVariant(const Runtime::Instance::ArrayInstance *P) noexcept { + setData(TypeCode::ArrayRef, reinterpret_cast<const void *>(P)); + } // Getter of type. const ValType &getType() const noexcept { @@ -360,11 +434,44 @@ struct RefVariant { uint64x2_t Data; }; +struct StrVariant { + // Constructors. + StrVariant(std::string &&P) noexcept { setData(std::move(P)); } + + // Getter of type. + const ValType getType() const noexcept { return TypeCode::String; } + + // Getter of pointer. + std::string_view getString() const noexcept { + const auto *Ptr = reinterpret_cast<const char *>(toArray()[0]); + auto Size = static_cast<size_t>(toArray()[1]); + return std::string_view(Ptr, Size); + } + +private: + // Helper function of converting data to array. + const std::array<uint64_t, 2> &toArray() const noexcept { + return reinterpret_cast<const std::array<uint64_t, 2> &>(Data); + } + std::array<uint64_t, 2> &toArray() noexcept { + return reinterpret_cast<std::array<uint64_t, 2> &>(Data); + } + + // Helper function to set the content. + void setData(std::string &&S) noexcept { + toArray()[0] = reinterpret_cast<uintptr_t>(S.c_str()); + toArray()[1] = static_cast<uint64_t>(S.size()); + } + + // Member data. + uint64x2_t Data; +}; + using ValVariant = Variant<uint32_t, int32_t, uint64_t, int64_t, float, double, uint128_t, int128_t, uint64x2_t, int64x2_t, uint32x4_t, int32x4_t, uint16x8_t, - int16x8_t, uint8x16_t, int8x16_t, floatx4_t, doublex2_t, - RefVariant>; + int16x8_t, uint8x16_t, int8x16_t, floatx4_t, doublex2_t, RefVariant, + StrVariant>; // <<<<<<<< Value definitions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -492,6 +599,10 @@ template <> inline ValType ValTypeFromType<float>() noexcept { template <> inline ValType ValTypeFromType<double>() noexcept { return ValType(TypeCode::F64); } +// wasm interface types +template <> inline ValType ValTypeFromType<StrVariant>() noexcept { + return ValType(TypeCode::String); +} // <<<<<<<< Template to get value type from type <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -512,6 +623,9 @@ inline ValVariant ValueFromType(ValType Type) noexcept { case TypeCode::Ref: case TypeCode::RefNull: return RefVariant(Type); + // wasm interface types + case TypeCode::String: + return StrVariant(""); default: assumingUnreachable(); } diff --git a/include/common/variant.h b/include/common/variant.h index 67aa3b903534..31817e7192aa 100644 --- a/include/common/variant.h +++ b/include/common/variant.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/variant.h - Unsafe variant implementation ---------===// // diff --git a/include/common/version.h.in b/include/common/version.h.in index 99de91ac1690..81b607928ec1 100644 --- a/include/common/version.h.in +++ b/include/common/version.h.in @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/common/version.h - Version information -------------------===// // diff --git a/include/driver/compiler.h b/include/driver/compiler.h index ca86b813a056..eb1b13ac8760 100644 --- a/include/driver/compiler.h +++ b/include/driver/compiler.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/driver/compiler.h - Compiler entrypoint ------------------===// // @@ -49,10 +49,13 @@ struct DriverCompilerOptions { PO::Description("Disable Bulk memory operations proposal"sv)), PropRefTypes(PO::Description("Disable Reference types proposal"sv)), PropSIMD(PO::Description("Disable SIMD proposal"sv)), - PropMultiMem(PO::Description("Enable Multiple memories proposal"sv)), PropTailCall(PO::Description("Enable Tail-call proposal"sv)), PropExtendConst(PO::Description("Enable Extended-const proposal"sv)), + PropFunctionReference( + PO::Description("Enable Function Reference proposal"sv)), + PropMultiMem(PO::Description("Enable Multiple memories proposal"sv)), PropThreads(PO::Description("Enable Threads proposal"sv)), + PropRelaxedSIMD(PO::Description("Enable Relaxed SIMD proposal"sv)), PropAll(PO::Description("Enable all features"sv)), PropOptimizationLevel( PO::Description("Optimization level, one of 0, 1, 2, 3, s, z."sv), @@ -74,10 +77,12 @@ struct DriverCompilerOptions { PO::Option<PO::Toggle> PropBulkMemOps; PO::Option<PO::Toggle> PropRefTypes; PO::Option<PO::Toggle> PropSIMD; - PO::Option<PO::Toggle> PropMultiMem; PO::Option<PO::Toggle> PropTailCall; PO::Option<PO::Toggle> PropExtendConst; + PO::Option<PO::Toggle> PropFunctionReference; + PO::Option<PO::Toggle> PropMultiMem; PO::Option<PO::Toggle> PropThreads; + PO::Option<PO::Toggle> PropRelaxedSIMD; PO::Option<PO::Toggle> PropAll; PO::Option<std::string> PropOptimizationLevel; @@ -98,10 +103,12 @@ struct DriverCompilerOptions { .add_option("disable-bulk-memory"sv, PropBulkMemOps) .add_option("disable-reference-types"sv, PropRefTypes) .add_option("disable-simd"sv, PropSIMD) - .add_option("enable-multi-memory"sv, PropMultiMem) .add_option("enable-tail-call"sv, PropTailCall) .add_option("enable-extended-const"sv, PropExtendConst) + .add_option("enable-function-reference"sv, PropFunctionReference) + .add_option("enable-multi-memory"sv, PropMultiMem) .add_option("enable-threads"sv, PropThreads) + .add_option("enable-relaxed-simd"sv, PropRelaxedSIMD) .add_option("enable-all"sv, PropAll) .add_option("optimize"sv, PropOptimizationLevel); } diff --git a/include/driver/fuzzPO.h b/include/driver/fuzzPO.h index d3fe532adb27..db065a987846 100644 --- a/include/driver/fuzzPO.h +++ b/include/driver/fuzzPO.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/driver/fuzzPO.h - Fuzz PO entrypoint ---------------------===// // diff --git a/include/driver/fuzzTool.h b/include/driver/fuzzTool.h index 4326c422e684..5019890c6cda 100644 --- a/include/driver/fuzzTool.h +++ b/include/driver/fuzzTool.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/driver/fuzzTool.h - Fuzz Tool entrypoint -----------------===// // diff --git a/include/driver/tool.h b/include/driver/tool.h index 63cafb655908..2b420b04626b 100644 --- a/include/driver/tool.h +++ b/include/driver/tool.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/driver/tool.h - Tool entrypoint --------------------------===// // @@ -56,12 +56,16 @@ struct DriverToolOptions { PO::Description("Disable Bulk memory operations proposal"sv)), PropRefTypes(PO::Description("Disable Reference types proposal"sv)), PropSIMD(PO::Description("Disable SIMD proposal"sv)), - PropMultiMem(PO::Description("Enable Multiple memories proposal"sv)), PropTailCall(PO::Description("Enable Tail-call proposal"sv)), PropExtendConst(PO::Description("Enable Extended-const proposal"sv)), - PropThreads(PO::Description("Enable Threads proposal"sv)), PropFunctionReference( PO::Description("Enable Function Reference proposal"sv)), + PropGC(PO::Description("Enable GC proposal, this is experimental"sv)), + PropMultiMem(PO::Description("Enable Multiple memories proposal"sv)), + PropThreads(PO::Description("Enable Threads proposal"sv)), + PropRelaxedSIMD(PO::Description("Enable Relaxed SIMD proposal"sv)), + PropExceptionHandling( + PO::Description("Enable Exception handling proposal"sv)), PropComponent(PO::Description( "Enable Component Model proposal, this is experimental"sv)), PropAll(PO::Description("Enable all features"sv)), @@ -73,6 +77,8 @@ struct DriverToolOptions { "Enable generating code for counting time during execution."sv)), ConfEnableAllStatistics(PO::Description( "Enable generating code for all statistics options include instruction counting, gas measuring, and execution time"sv)), + ConfEnableJIT( + PO::Description("Enable Just-In-Time compiler for running WASM"sv)), ConfForceInterpreter( PO::Description("Forcibly run WASM in interpreter mode."sv)), TimeLim( @@ -103,17 +109,21 @@ struct DriverToolOptions { PO::Option<PO::Toggle> PropBulkMemOps; PO::Option<PO::Toggle> PropRefTypes; PO::Option<PO::Toggle> PropSIMD; - PO::Option<PO::Toggle> PropMultiMem; PO::Option<PO::Toggle> PropTailCall; PO::Option<PO::Toggle> PropExtendConst; - PO::Option<PO::Toggle> PropThreads; PO::Option<PO::Toggle> PropFunctionReference; + PO::Option<PO::Toggle> PropGC; + PO::Option<PO::Toggle> PropMultiMem; + PO::Option<PO::Toggle> PropThreads; + PO::Option<PO::Toggle> PropRelaxedSIMD; + PO::Option<PO::Toggle> PropExceptionHandling; PO::Option<PO::Toggle> PropComponent; PO::Option<PO::Toggle> PropAll; PO::Option<PO::Toggle> ConfEnableInstructionCounting; PO::Option<PO::Toggle> ConfEnableGasMeasuring; PO::Option<PO::Toggle> ConfEnableTimeMeasuring; PO::Option<PO::Toggle> ConfEnableAllStatistics; + PO::Option<PO::Toggle> ConfEnableJIT; PO::Option<PO::Toggle> ConfForceInterpreter; PO::Option<uint64_t> TimeLim; PO::List<int> GasLim; @@ -131,6 +141,7 @@ struct DriverToolOptions { .add_option("enable-gas-measuring"sv, ConfEnableGasMeasuring) .add_option("enable-time-measuring"sv, ConfEnableTimeMeasuring) .add_option("enable-all-statistics"sv, ConfEnableAllStatistics) + .add_option("enable-jit"sv, ConfEnableJIT) .add_option("force-interpreter"sv, ConfForceInterpreter) .add_option("disable-import-export-mut-globals"sv, PropMutGlobals) .add_option("disable-non-trap-float-to-int"sv, PropNonTrapF2IConvs) @@ -140,11 +151,14 @@ struct DriverToolOptions { .add_option("disable-reference-types"sv, PropRefTypes) .add_option("disable-simd"sv, PropSIMD) .add_option("allow-af-unix"sv, PropAFUNIX) - .add_option("enable-multi-memory"sv, PropMultiMem) .add_option("enable-tail-call"sv, PropTailCall) .add_option("enable-extended-const"sv, PropExtendConst) - .add_option("enable-threads"sv, PropThreads) .add_option("enable-function-reference"sv, PropFunctionReference) + .add_option("enable-gc"sv, PropGC) + .add_option("enable-multi-memory"sv, PropMultiMem) + .add_option("enable-threads"sv, PropThreads) + .add_option("enable-relaxed-simd"sv, PropRelaxedSIMD) + .add_option("enable-exception-handling"sv, PropExceptionHandling) .add_option("enable-component"sv, PropComponent) .add_option("enable-all"sv, PropAll) .add_option("time-limit"sv, TimeLim) @@ -152,9 +166,7 @@ struct DriverToolOptions { .add_option("memory-page-limit"sv, MemLim) .add_option("forbidden-plugin"sv, ForbiddenPlugins); - for (const auto &Path : Plugin::Plugin::getDefaultPluginPaths()) { - Plugin::Plugin::load(Path); - } + Plugin::Plugin::loadFromDefaultPaths(); Plugin::Plugin::addPluginOptions(Parser); } }; diff --git a/include/driver/unitool.h b/include/driver/unitool.h index 330a14db423f..59cb706be98e 100644 --- a/include/driver/unitool.h +++ b/include/driver/unitool.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/driver/unitool.h - UniTool entrypoint ------------------===// // @@ -21,4 +21,4 @@ enum class ToolType : char { All, Compiler, Tool }; int UniTool(int Argc, const char *Argv[], const ToolType ToolSelect) noexcept; } // namespace Driver -} // namespace WasmEdge \ No newline at end of file +} // namespace WasmEdge diff --git a/include/driver/wasi_nn_rpc/wasi_nn_rpcserver/wasi_nn_rpcserver.h b/include/driver/wasi_nn_rpc/wasi_nn_rpcserver/wasi_nn_rpcserver.h index 10cd68579b78..81032d4446de 100644 --- a/include/driver/wasi_nn_rpc/wasi_nn_rpcserver/wasi_nn_rpcserver.h +++ b/include/driver/wasi_nn_rpc/wasi_nn_rpcserver/wasi_nn_rpcserver.h @@ -89,9 +89,10 @@ class HostFuncCaller { Runtime::CallingFrame Frame; }; -grpc::Status createRPCStatusFromErrno(std::string_view FuncName, +grpc::Status createRPCStatusFromErrno(grpc::ServerContext *RPCContext, + std::string_view FuncName, uint32_t Errno) { - // TODO: propagate Errno as gRPC metadata for machine-readability + RPCContext->AddTrailingMetadata("errno", std::to_string(Errno)); return grpc::Status( grpc::StatusCode::UNKNOWN, fmt::format("failed to call host function \"{}\", errno={}"sv, FuncName, @@ -108,13 +109,14 @@ class GraphService final : public wasi_ephemeral_nn::Graph::Service { NamePtr, uint32_t NameLen, uint32_t GraphIdPtr) */ virtual grpc::Status - LoadByName(grpc::ServerContext * /*RPCContext*/, + LoadByName(grpc::ServerContext *RPCContext, const wasi_ephemeral_nn::LoadByNameRequest *RPCRequest, wasi_ephemeral_nn::LoadByNameResult *RPCResult) { std::string_view FuncName = "load_by_name"sv; auto Name = RPCRequest->name(); uint32_t NamePtr = UINT32_C(0); - uint32_t NameLen = Name.size(); // does not include the '\0' terminator + uint32_t NameLen = static_cast<uint32_t>( + Name.size()); // does not include the '\0' terminator uint32_t OutPtr = NamePtr + NameLen + 1; // 1 is for the '\0' terminator uint32_t MemorySize = OutPtr + 4; // 4 is for sizeof(OutPtr) @@ -124,7 +126,49 @@ class GraphService final : public wasi_ephemeral_nn::Graph::Service { writeBinaries(MemInst, NameVec, NamePtr); uint32_t Errno = HostFuncCaller.call({NamePtr, NameLen, OutPtr}); if (Errno != 0) { - return createRPCStatusFromErrno(FuncName, Errno); + return createRPCStatusFromErrno(RPCContext, FuncName, Errno); + } + uint32_t GraphHandle = *MemInst.getPointer<uint32_t *>(OutPtr); + RPCResult->set_graph_handle(GraphHandle); + return grpc::Status::OK; + } + + /* + Expect<WASINN::ErrNo> + WasiNNLoadByNameWithConfig::bodyImpl( + const Runtime::CallingFrame &Frame, + uint32_t NamePtr, uint32_t NameLen, + uint32_t ConfigPtr, uint32_t ConfigLen, + uint32_t GraphIdPtr + ) + */ + virtual grpc::Status LoadByNameWithConfig( + grpc::ServerContext *RPCContext, + const wasi_ephemeral_nn::LoadByNameWithConfigRequest *RPCRequest, + wasi_ephemeral_nn::LoadByNameWithConfigResult *RPCResult) { + std::string_view FuncName = "load_by_name_with_config"sv; + auto Name = RPCRequest->name(); + auto Config = RPCRequest->config(); + uint32_t NamePtr = UINT32_C(0); + uint32_t NameLen = static_cast<uint32_t>( + Name.size()); // does not include the '\0' terminator + uint32_t ConfigPtr = static_cast<uint32_t>( + Name.size() + 1); // 1 is for the '\0' terminator of Name + uint32_t ConfigLen = Config.size(); // does not include the '\0' terminator + uint32_t OutPtr = + NamePtr + NameLen + 1 + ConfigLen + 1; // 1 is for the '\0' terminator + uint32_t MemorySize = OutPtr + 4; // 4 is for sizeof(OutPtr) + + HostFuncCaller HostFuncCaller(NNMod, FuncName, MemorySize); + auto &MemInst = HostFuncCaller.getMemInst(); + std::vector<char> NameVec(Name.begin(), Name.end()); + std::vector<char> ConfigVec(Config.begin(), Config.end()); + writeBinaries(MemInst, NameVec, NamePtr); + writeBinaries(MemInst, ConfigVec, ConfigPtr); + uint32_t Errno = + HostFuncCaller.call({NamePtr, NameLen, ConfigPtr, ConfigLen, OutPtr}); + if (Errno != 0) { + return createRPCStatusFromErrno(RPCContext, FuncName, Errno); } uint32_t GraphHandle = *MemInst.getPointer<uint32_t *>(OutPtr); RPCResult->set_graph_handle(GraphHandle); @@ -145,7 +189,7 @@ class GraphResourceService final uint32_t &ContextId) noexcept */ virtual grpc::Status InitExecutionContext( - grpc::ServerContext * /*RPCContext*/, + grpc::ServerContext *RPCContext, const wasi_ephemeral_nn::InitExecutionContextRequest *RPCRequest, wasi_ephemeral_nn::InitExecutionContextResult *RPCResult) { std::string_view FuncName = "init_execution_context"sv; @@ -157,7 +201,7 @@ class GraphResourceService final auto &MemInst = HostFuncCaller.getMemInst(); uint32_t Errno = HostFuncCaller.call({ResourceHandle, OutPtr}); if (Errno != 0) { - return createRPCStatusFromErrno(FuncName, Errno); + return createRPCStatusFromErrno(RPCContext, FuncName, Errno); } uint32_t CtxHandle = *MemInst.getPointer<uint32_t *>(OutPtr); RPCResult->set_ctx_handle(CtxHandle); @@ -180,7 +224,7 @@ class GraphExecutionContextResourceService final uint32_t Index, const TensorData &Tensor) noexcept */ virtual grpc::Status - SetInput(grpc::ServerContext * /*RPCContext*/, + SetInput(grpc::ServerContext *RPCContext, const wasi_ephemeral_nn::SetInputRequest *RPCRequest, google::protobuf::Empty * /*RPCResult*/) { std::string_view FuncName = "set_input"sv; @@ -191,7 +235,7 @@ class GraphExecutionContextResourceService final uint32_t TensorDimSize = TensorDim.size(); uint32_t TensorTy = Tensor.ty(); auto TensorData = Tensor.data(); - uint32_t TensorDataSize = TensorData.size(); + uint32_t TensorDataSize = static_cast<uint32_t>(TensorData.size()); /* clang-format off */ /** @@ -221,7 +265,7 @@ class GraphExecutionContextResourceService final uint32_t Errno = HostFuncCaller.call({ResourceHandle, Index, SetInputEntryPtr}); if (Errno != 0) { - return createRPCStatusFromErrno(FuncName, Errno); + return createRPCStatusFromErrno(RPCContext, FuncName, Errno); } return grpc::Status::OK; } @@ -230,7 +274,7 @@ class GraphExecutionContextResourceService final Expect<ErrNo> compute(WasiNNEnvironment &Env, uint32_t ContextId) noexcept */ virtual grpc::Status - Compute(grpc::ServerContext * /*RPCContext*/, + Compute(grpc::ServerContext *RPCContext, const wasi_ephemeral_nn::ComputeRequest *RPCRequest, google::protobuf::Empty * /*RPCResult*/) { std::string_view FuncName = "compute"sv; @@ -239,7 +283,26 @@ class GraphExecutionContextResourceService final HostFuncCaller HostFuncCaller(NNMod, FuncName, MemorySize); uint32_t Errno = HostFuncCaller.call({ResourceHandle}); if (Errno != 0) { - return createRPCStatusFromErrno(FuncName, Errno); + return createRPCStatusFromErrno(RPCContext, FuncName, Errno); + } + return grpc::Status::OK; + } + + /* + Expect<ErrNo> computeSingle(WasiNNEnvironment &Env, uint32_t ContextId) + noexcept + */ + virtual grpc::Status + ComputeSingle(grpc::ServerContext *RPCContext, + const wasi_ephemeral_nn::ComputeRequest *RPCRequest, + google::protobuf::Empty * /*RPCResult*/) { + std::string_view FuncName = "compute_single"sv; + uint32_t ResourceHandle = RPCRequest->resource_handle(); + uint32_t MemorySize = UINT32_C(0); + HostFuncCaller HostFuncCaller(NNMod, FuncName, MemorySize); + uint32_t Errno = HostFuncCaller.call({ResourceHandle}); + if (Errno != 0) { + return createRPCStatusFromErrno(RPCContext, FuncName, Errno); } return grpc::Status::OK; } @@ -250,7 +313,7 @@ class GraphExecutionContextResourceService final uint32_t &BytesWritten) noexcept */ virtual grpc::Status - GetOutput(grpc::ServerContext * /*RPCContext*/, + GetOutput(grpc::ServerContext *RPCContext, const wasi_ephemeral_nn::GetOutputRequest *RPCRequest, wasi_ephemeral_nn::GetOutputResult *RPCResult) { std::string_view FuncName = "get_output"sv; @@ -265,7 +328,7 @@ class GraphExecutionContextResourceService final uint32_t Errno = HostFuncCaller.call( {ResourceHandle, Index, BufPtr, BufMaxSize, BytesWrittenPtr}); if (Errno != 0) { - return createRPCStatusFromErrno(FuncName, Errno); + return createRPCStatusFromErrno(RPCContext, FuncName, Errno); } /* clang-format off */ /** @@ -279,6 +342,60 @@ class GraphExecutionContextResourceService final return grpc::Status::OK; } + /* + Expect<ErrNo> getOutputSingle(WasiNNEnvironment &Env, uint32_t ContextId, + uint32_t Index, Span<uint8_t> OutBuffer, + uint32_t &BytesWritten) noexcept + */ + virtual grpc::Status + GetOutputSingle(grpc::ServerContext *RPCContext, + const wasi_ephemeral_nn::GetOutputRequest *RPCRequest, + wasi_ephemeral_nn::GetOutputResult *RPCResult) { + std::string_view FuncName = "get_output_single"sv; + uint32_t ResourceHandle = RPCRequest->resource_handle(); + uint32_t Index = RPCRequest->index(); + uint32_t MemorySize = UINT32_C(65536); // FIXME + uint32_t BytesWrittenPtr = UINT32_C(0); + uint32_t BufPtr = BytesWrittenPtr + UINT32_C(4); + uint32_t BufMaxSize = MemorySize - BufPtr; + HostFuncCaller HostFuncCaller(NNMod, FuncName, MemorySize); + auto &MemInst = HostFuncCaller.getMemInst(); + uint32_t Errno = HostFuncCaller.call( + {ResourceHandle, Index, BufPtr, BufMaxSize, BytesWrittenPtr}); + if (Errno != 0) { + return createRPCStatusFromErrno(RPCContext, FuncName, Errno); + } + /* clang-format off */ + /** + 0 : BytesWritten + 4 : Buf + */ + /* clang-format on */ + auto BytesWritten = *MemInst.getPointer<uint32_t *>(BytesWrittenPtr); + auto *Buf = MemInst.getPointer<char *>(BufPtr); + RPCResult->set_data(Buf, BytesWritten); + return grpc::Status::OK; + } + + /* + Expect<ErrNo> finiSingle(WasiNNEnvironment &Env, uint32_t ContextId) + noexcept + */ + virtual grpc::Status + FiniSingle(grpc::ServerContext *RPCContext, + const wasi_ephemeral_nn::FiniSingleRequest *RPCRequest, + google::protobuf::Empty * /*RPCResult*/) { + std::string_view FuncName = "fini_single"sv; + uint32_t ResourceHandle = RPCRequest->resource_handle(); + uint32_t MemorySize = UINT32_C(0); + HostFuncCaller HostFuncCaller(NNMod, FuncName, MemorySize); + uint32_t Errno = HostFuncCaller.call({ResourceHandle}); + if (Errno != 0) { + return createRPCStatusFromErrno(RPCContext, FuncName, Errno); + } + return grpc::Status::OK; + } + private: const Runtime::Instance::ModuleInstance &NNMod; }; diff --git a/include/executor/engine/atomic.ipp b/include/executor/engine/atomic.ipp index 80e8e5ba6a29..65c5581adecd 100644 --- a/include/executor/engine/atomic.ipp +++ b/include/executor/engine/atomic.ipp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" #include "runtime/instance/memory.h" diff --git a/include/executor/engine/binary_numeric.ipp b/include/executor/engine/binary_numeric.ipp index 7210f396749c..4ae919171df9 100644 --- a/include/executor/engine/binary_numeric.ipp +++ b/include/executor/engine/binary_numeric.ipp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" diff --git a/include/executor/engine/binary_numeric_vector.ipp b/include/executor/engine/binary_numeric_vector.ipp index 3f5134112d4f..94cf32673c5a 100644 --- a/include/executor/engine/binary_numeric_vector.ipp +++ b/include/executor/engine/binary_numeric_vector.ipp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/engine/vector_helper.h" #include "executor/executor.h" @@ -374,5 +374,66 @@ Executor::runVectorQ15MulSatOp(ValVariant &Val1, const ValVariant &Val2) const { return {}; } +template <typename T> +Expect<void> +Executor::runVectorRelaxedLaneselectOp(ValVariant &Val1, const ValVariant &Val2, + const ValVariant &Mask) const { + using VT [[gnu::vector_size(16)]] = T; + + VT &V1 = Val1.get<VT>(); + const VT &V2 = Val2.get<VT>(); + const VT &C = Mask.get<VT>(); + + V1 = (V1 & C) | (V2 & ~C); + return {}; +} + +inline Expect<void> +Executor::runVectorRelaxedIntegerDotProductOp(ValVariant &Val1, + const ValVariant &Val2) const { + using int16x8_t [[gnu::vector_size(16)]] = int16_t; + + const int16x8_t &V1 = Val1.get<int16x8_t>(); + const int16x8_t &V2 = Val2.get<int16x8_t>(); + const int Size = 8; + + const auto V1L = V1 >> Size; + const auto V1R = (V1 << Size) >> Size; + const auto V2L = V2 >> Size; + const auto V2R = (V2 << Size) >> Size; + + Val1.emplace<int16x8_t>(V1L * V2L + V1R * V2R); + return {}; +} + +inline Expect<void> Executor::runVectorRelaxedIntegerDotProductOpAdd( + ValVariant &Val1, const ValVariant &Val2, const ValVariant &C) const { + using int16x8_t [[gnu::vector_size(16)]] = int16_t; + using int32x4_t [[gnu::vector_size(16)]] = int32_t; + + const int16x8_t &V1 = Val1.get<int16x8_t>(); + const int16x8_t &V2 = Val2.get<int16x8_t>(); + const int Size = 8; + const int32x4_t &VC = C.get<int32x4_t>(); + + const auto V1L = V1 >> Size; + const auto V1R = (V1 << Size) >> Size; + const auto V2L = V2 >> Size; + const auto V2R = (V2 << Size) >> Size; + + union VecConverter { + int16x8_t S16; + int32x4_t S32; + } IM; + + IM.S16 = V1L * V2L + V1R * V2R; + const int IMSize = 16; + auto IML = IM.S32 >> IMSize; + auto IMR = (IM.S32 << IMSize) >> IMSize; + + Val1.emplace<int32x4_t>(IML + IMR + VC); + return {}; +} + } // namespace Executor } // namespace WasmEdge diff --git a/include/executor/engine/binary_numeric_vector_msvc.ipp b/include/executor/engine/binary_numeric_vector_msvc.ipp index a2a5a74d0aa7..4e16808a443e 100644 --- a/include/executor/engine/binary_numeric_vector_msvc.ipp +++ b/include/executor/engine/binary_numeric_vector_msvc.ipp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" @@ -25,11 +25,11 @@ Expect<void> Executor::runVectorEqOp(ValVariant &Val1, const VT &V2 = Val2.get<VT>(); int64_t IAllOnes = INT64_C(-1); - const T AllOnes = reinterpret_cast<T&>(IAllOnes); + const T AllOnes = reinterpret_cast<T &>(IAllOnes); // unrolling V1 = (V1 == V2); VT VOut; - for(size_t I = 0; I < V1.size(); I++) { + for (size_t I = 0; I < V1.size(); I++) { if (V1[I] == V2[I]) { // all ones VOut[I] = AllOnes; @@ -51,11 +51,11 @@ Expect<void> Executor::runVectorNeOp(ValVariant &Val1, const VT &V2 = Val2.get<VT>(); int64_t IAllOnes = INT64_C(-1); - const T AllOnes = reinterpret_cast<T&>(IAllOnes); + const T AllOnes = reinterpret_cast<T &>(IAllOnes); // unrolling V1 = (V1 != V2); VT VOut; - for(size_t I = 0; I < V1.size(); I++) { + for (size_t I = 0; I < V1.size(); I++) { if (V1[I] != V2[I]) { // all ones VOut[I] = AllOnes; @@ -77,11 +77,11 @@ Expect<void> Executor::runVectorLtOp(ValVariant &Val1, const VT &V2 = Val2.get<VT>(); int64_t IAllOnes = INT64_C(-1); - const T AllOnes = reinterpret_cast<T&>(IAllOnes); + const T AllOnes = reinterpret_cast<T &>(IAllOnes); // unrolling V1 = (V1 < V2); VT VOut; - for(size_t I = 0; I < V1.size(); I++) { + for (size_t I = 0; I < V1.size(); I++) { if (V1[I] < V2[I]) { // all ones VOut[I] = AllOnes; @@ -103,11 +103,11 @@ Expect<void> Executor::runVectorGtOp(ValVariant &Val1, const VT &V2 = Val2.get<VT>(); int64_t IAllOnes = INT64_C(-1); - const T AllOnes = reinterpret_cast<T&>(IAllOnes); + const T AllOnes = reinterpret_cast<T &>(IAllOnes); // unrolling V1 = (V1 > V2); VT VOut; - for(size_t I = 0; I < V1.size(); I++) { + for (size_t I = 0; I < V1.size(); I++) { if (V1[I] > V2[I]) { // all ones VOut[I] = AllOnes; @@ -129,11 +129,11 @@ Expect<void> Executor::runVectorLeOp(ValVariant &Val1, const VT &V2 = Val2.get<VT>(); int64_t IAllOnes = INT64_C(-1); - const T AllOnes = reinterpret_cast<T&>(IAllOnes); + const T AllOnes = reinterpret_cast<T &>(IAllOnes); // unrolling V1 = (V1 <= V2); VT VOut; - for(size_t I = 0; I < V1.size(); I++) { + for (size_t I = 0; I < V1.size(); I++) { if (V1[I] <= V2[I]) { // all ones VOut[I] = AllOnes; @@ -155,11 +155,11 @@ Expect<void> Executor::runVectorGeOp(ValVariant &Val1, const VT &V2 = Val2.get<VT>(); int64_t IAllOnes = INT64_C(-1); - const T AllOnes = reinterpret_cast<T&>(IAllOnes); + const T AllOnes = reinterpret_cast<T &>(IAllOnes); // unrolling V1 = (V1 >= V2); VT VOut; - for(size_t I = 0; I < V1.size(); I++) { + for (size_t I = 0; I < V1.size(); I++) { if (V1[I] >= V2[I]) { // all ones VOut[I] = AllOnes; @@ -184,7 +184,7 @@ Expect<void> Executor::runVectorNarrowOp(ValVariant &Val1, VTOut Result; VTIn V1 = Val1.get<VTIn>(); constexpr size_t HSize = V1.size(); - for(size_t I = 0; I < HSize; ++I) { + for (size_t I = 0; I < HSize; ++I) { if (V1[I] > std::numeric_limits<TOut>::max()) { Result[I] = std::numeric_limits<TOut>::max(); } else if (V1[I] < std::numeric_limits<TOut>::min()) { @@ -194,7 +194,7 @@ Expect<void> Executor::runVectorNarrowOp(ValVariant &Val1, } } const VTIn &V2 = Val2.get<VTIn>(); - for(size_t I = 0; I < HSize; ++I) { + for (size_t I = 0; I < HSize; ++I) { if (V2[I] > std::numeric_limits<TOut>::max()) { Result[HSize + I] = std::numeric_limits<TOut>::max(); } else if (V2[I] < std::numeric_limits<TOut>::min()) { @@ -214,7 +214,7 @@ Expect<void> Executor::runVectorShlOp(ValVariant &Val1, const uint32_t Mask = static_cast<uint32_t>(sizeof(T) * 8 - 1); const uint32_t Count = Val2.get<uint32_t>() & Mask; VT &V1 = Val1.get<VT>(); - for(size_t I = 0; I < V1.size(); ++I) { + for (size_t I = 0; I < V1.size(); ++I) { V1[I] <<= Count; } @@ -228,7 +228,7 @@ Expect<void> Executor::runVectorShrOp(ValVariant &Val1, const uint32_t Mask = static_cast<uint32_t>(sizeof(T) * 8 - 1); const uint32_t Count = Val2.get<uint32_t>() & Mask; VT &V1 = Val1.get<VT>(); - for(size_t I = 0; I < V1.size(); ++I) { + for (size_t I = 0; I < V1.size(); ++I) { V1[I] >>= Count; } @@ -265,7 +265,7 @@ Expect<void> Executor::runVectorAddSatOp(ValVariant &Val1, continue; } } else { - if (std::numeric_limits<T>::min() - V1[I] > V2[I] ) { + if (std::numeric_limits<T>::min() - V1[I] > V2[I]) { V1[I] = std::numeric_limits<T>::min(); continue; } @@ -459,7 +459,8 @@ Expect<void> Executor::runVectorExtMulHighOp(ValVariant &Val1, const VTIn &V2 = Val2.get<VTIn>(); constexpr size_t HSize = Result.size(); for (size_t I = 0; I < HSize; ++I) { - Result[I] = static_cast<TOut>(V1[HSize + I]) * static_cast<TOut>(V2[HSize + I]); + Result[I] = + static_cast<TOut>(V1[HSize + I]) * static_cast<TOut>(V2[HSize + I]); } Val1.emplace<VTOut>(Result); return {}; @@ -471,8 +472,10 @@ Executor::runVectorQ15MulSatOp(ValVariant &Val1, const ValVariant &Val2) const { const auto &V1 = Val1.get<int16x8_t>(); const auto &V2 = Val2.get<int16x8_t>(); int16x8_t VOut; - for(size_t I = 0; I < 8; I++) { - int32_t ER = (static_cast<int32_t>(V1[I]) * static_cast<int32_t>(V2[I]) + INT32_C(0x4000)) >> INT32_C(15); + for (size_t I = 0; I < 8; I++) { + int32_t ER = (static_cast<int32_t>(V1[I]) * static_cast<int32_t>(V2[I]) + + INT32_C(0x4000)) >> + INT32_C(15); if (ER > 0x7fff) { ER = 0x7fff; } @@ -482,5 +485,67 @@ Executor::runVectorQ15MulSatOp(ValVariant &Val1, const ValVariant &Val2) const { return {}; } +template <typename T> +Expect<void> +Executor::runVectorRelaxedLaneselectOp(ValVariant &Val1, const ValVariant &Val2, + const ValVariant &Mask) const { + using VT = SIMDArray<T, 16>; + + VT &V1 = Val1.get<VT>(); + const VT &V2 = Val2.get<VT>(); + const VT &C = Mask.get<VT>(); + + for (size_t I = 0; I < V1.size(); ++I) { + V1[I] = (V1[I] & C[I]) | (V2[I] & ~C[I]); + } + + return {}; +} + +inline Expect<void> +Executor::runVectorRelaxedIntegerDotProductOp(ValVariant &Val1, + const ValVariant &Val2) const { + using int8x16_t = SIMDArray<int8_t, 16>; + using int16x8_t = SIMDArray<int16_t, 16>; + + const int8x16_t &V1 = Val1.get<int8x16_t>(); + const int8x16_t &V2 = Val2.get<int8x16_t>(); + + int16x8_t Result; + for (size_t I = 0; I < Result.size(); ++I) { + Result[I] = + static_cast<int16_t>(V1[I * 2]) * static_cast<int16_t>(V2[I * 2]) + + static_cast<int16_t>(V1[I * 2 + 1]) * + static_cast<int16_t>(V2[I * 2 + 1]); + } + + Val1.emplace<int16x8_t>(Result); + return {}; +} + +inline Expect<void> Executor::runVectorRelaxedIntegerDotProductOpAdd( + ValVariant &Val1, const ValVariant &Val2, const ValVariant &C) const { + using int8x16_t = SIMDArray<int8_t, 16>; + using int16x8_t = SIMDArray<int16_t, 16>; + using int32x4_t = SIMDArray<int32_t, 16>; + + const int8x16_t &V1 = Val1.get<int8x16_t>(); + const int8x16_t &V2 = Val2.get<int8x16_t>(); + const int32x4_t &VC = C.get<int32x4_t>(); + + int32x4_t Result{0, 0, 0, 0}; + + for (size_t I = 0; I < V1.size(); ++I) { + Result[I / 4] += static_cast<int16_t>(V1[I]) * static_cast<int16_t>(V2[I]); + } + + for (size_t I = 0; I < VC.size(); ++I) { + Result[I] = Result[I] + VC[I]; + } + + Val1.emplace<int32x4_t>(Result); + return {}; +} + } // namespace Executor } // namespace WasmEdge diff --git a/include/executor/engine/cast_numeric.ipp b/include/executor/engine/cast_numeric.ipp index af59978bec1b..8c0f2ed90e57 100644 --- a/include/executor/engine/cast_numeric.ipp +++ b/include/executor/engine/cast_numeric.ipp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" diff --git a/include/executor/engine/memory.ipp b/include/executor/engine/memory.ipp index bc8dd523b19b..d58ea6f225ae 100644 --- a/include/executor/engine/memory.ipp +++ b/include/executor/engine/memory.ipp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" #include "runtime/instance/memory.h" diff --git a/include/executor/engine/relation_numeric.ipp b/include/executor/engine/relation_numeric.ipp index 33746c4bcac2..9a7cf9a3fd62 100644 --- a/include/executor/engine/relation_numeric.ipp +++ b/include/executor/engine/relation_numeric.ipp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" diff --git a/include/executor/engine/unary_numeric.ipp b/include/executor/engine/unary_numeric.ipp index 0cd731219780..16a5f06d4665 100644 --- a/include/executor/engine/unary_numeric.ipp +++ b/include/executor/engine/unary_numeric.ipp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/roundeven.h" #include "executor/executor.h" @@ -62,15 +62,17 @@ template <typename T> TypeU<T> Executor::runPopcntOp(ValVariant &Val) const { template <typename T> TypeF<T> Executor::runAbsOp(ValVariant &Val) const { #if defined(_MSC_VER) && !defined(__clang__) // MSVC - // In MSVC, std::fabs cannot be used. If input is NAN, std::fabs will set the highest bit of fraction. + // In MSVC, std::fabs cannot be used. If input is NAN, std::fabs will set the + // highest bit of fraction. T &Fp = Val.get<T>(); static_assert(std::is_floating_point_v<T>); if constexpr (sizeof(T) == 4) { - uint32_t Tmp = reinterpret_cast<uint32_t&>(Fp) & UINT32_C(0x7fffffff); - Val.get<T>() = reinterpret_cast<T&>(Tmp); + uint32_t Tmp = reinterpret_cast<uint32_t &>(Fp) & UINT32_C(0x7fffffff); + Val.get<T>() = reinterpret_cast<T &>(Tmp); } else { - uint64_t Tmp = reinterpret_cast<uint64_t&>(Fp) & UINT64_C(0x7fffffffffffffff); - Val.get<T>() = reinterpret_cast<T&>(Tmp); + uint64_t Tmp = + reinterpret_cast<uint64_t &>(Fp) & UINT64_C(0x7fffffffffffffff); + Val.get<T>() = reinterpret_cast<T &>(Tmp); } #else Val.get<T>() = std::fabs(Val.get<T>()); diff --git a/include/executor/engine/unary_numeric_vector.ipp b/include/executor/engine/unary_numeric_vector.ipp index 3a96a1900ff4..17647af17a65 100644 --- a/include/executor/engine/unary_numeric_vector.ipp +++ b/include/executor/engine/unary_numeric_vector.ipp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/roundeven.h" #include "executor/executor.h" diff --git a/include/executor/engine/unary_numeric_vector_msvc.ipp b/include/executor/engine/unary_numeric_vector_msvc.ipp index bbb11da768ec..6000d5d2cb4c 100644 --- a/include/executor/engine/unary_numeric_vector_msvc.ipp +++ b/include/executor/engine/unary_numeric_vector_msvc.ipp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/roundeven.h" #include "executor/executor.h" @@ -21,8 +21,8 @@ Expect<void> Executor::runSplatOp(ValVariant &Val) const { const TOut Part = static_cast<TOut>(Val.get<TIn>()); using VTOut = SIMDArray<TOut, 16>; if constexpr (sizeof(TOut) == 1) { - Val.emplace<VTOut>(VTOut{Part, Part, Part, Part, Part, Part, Part, Part, Part, - Part, Part, Part, Part, Part, Part, Part}); + Val.emplace<VTOut>(VTOut{Part, Part, Part, Part, Part, Part, Part, Part, + Part, Part, Part, Part, Part, Part, Part, Part}); } else if constexpr (sizeof(TOut) == 2) { Val.emplace<VTOut>(VTOut{Part, Part, Part, Part, Part, Part, Part, Part}); } else if constexpr (sizeof(TOut) == 4) { @@ -74,7 +74,7 @@ Expect<void> Executor::runVectorExtAddPairwiseOp(ValVariant &Val) const { VTOut Result; const VTIn &V = Val.get<VTIn>(); for (size_t I = 0; I < Result.size(); ++I) { - Result[I] = static_cast<TOut>(V[I*2]) + static_cast<TOut>(V[I*2+1]); + Result[I] = static_cast<TOut>(V[I * 2]) + static_cast<TOut>(V[I * 2 + 1]); } Val.emplace<VTOut>(Result); @@ -88,11 +88,13 @@ Expect<void> Executor::runVectorAbsOp(ValVariant &Val) const { for (size_t I = 0; I < Result.size(); ++I) { if constexpr (std::is_floating_point_v<T>) { if constexpr (sizeof(T) == 4) { - uint32_t Tmp = reinterpret_cast<uint32_t&>(Result[I]) & UINT32_C(0x7fffffff); - Result[I] = reinterpret_cast<T&>(Tmp); + uint32_t Tmp = + reinterpret_cast<uint32_t &>(Result[I]) & UINT32_C(0x7fffffff); + Result[I] = reinterpret_cast<T &>(Tmp); } else { - uint64_t Tmp = reinterpret_cast<uint64_t&>(Result[I]) & UINT64_C(0x7fffffffffffffff); - Result[I] = reinterpret_cast<T&>(Tmp); + uint64_t Tmp = reinterpret_cast<uint64_t &>(Result[I]) & + UINT64_C(0x7fffffffffffffff); + Result[I] = reinterpret_cast<T &>(Tmp); } } else { Result[I] = Result[I] > 0 ? Result[I] : -Result[I]; @@ -113,12 +115,13 @@ Expect<void> Executor::runVectorNegOp(ValVariant &Val) const { inline Expect<void> Executor::runVectorPopcntOp(ValVariant &Val) const { auto &Result = Val.get<uint8x16_t>(); - for(size_t I = 0; I < 16; ++I) { + for (size_t I = 0; I < 16; ++I) { Result[I] -= ((Result[I] >> UINT8_C(1)) & UINT8_C(0x55)); - Result[I] = (Result[I] & UINT8_C(0x33)) + ((Result[I] >> UINT8_C(2)) & UINT8_C(0x33)); + Result[I] = (Result[I] & UINT8_C(0x33)) + + ((Result[I] >> UINT8_C(2)) & UINT8_C(0x33)); Result[I] += Result[I] >> UINT8_C(4); Result[I] &= UINT8_C(0x0f); - } + } return {}; } @@ -169,7 +172,8 @@ Expect<void> Executor::runVectorConvertOp(ValVariant &Val) const { auto &V = Val.get<VTIn>(); // int32/uint32 to float if constexpr (sizeof(TIn) == sizeof(TOut)) { - Val.emplace<VTOut>(VTOut{static_cast<TOut>(V[0]), static_cast<TOut>(V[1]), static_cast<TOut>(V[2]), static_cast<TOut>(V[3])}); + Val.emplace<VTOut>(VTOut{static_cast<TOut>(V[0]), static_cast<TOut>(V[1]), + static_cast<TOut>(V[2]), static_cast<TOut>(V[3])}); } else { // int32/uint32 to double Val.emplace<VTOut>(VTOut{static_cast<TOut>(V[0]), static_cast<TOut>(V[1])}); } @@ -205,10 +209,13 @@ Expect<void> Executor::runVectorAllTrueOp(ValVariant &Val) const { VT &V = Val.get<VT>(); uint32_t Result; if constexpr (sizeof(T) == 1) { - Result = V[0] != 0 && V[1] != 0 && V[2] != 0 && V[3] != 0 && V[4] != 0 && V[5] != 0 && V[6] != 0 && V[7] != 0 && - V[8] != 0 && V[9] != 0 && V[10] != 0 && V[11] != 0 && V[12] != 0 && V[13] != 0 && V[14] != 0 && V[15] != 0; + Result = V[0] != 0 && V[1] != 0 && V[2] != 0 && V[3] != 0 && V[4] != 0 && + V[5] != 0 && V[6] != 0 && V[7] != 0 && V[8] != 0 && V[9] != 0 && + V[10] != 0 && V[11] != 0 && V[12] != 0 && V[13] != 0 && + V[14] != 0 && V[15] != 0; } else if constexpr (sizeof(T) == 2) { - Result = V[0] != 0 && V[1] != 0 && V[2] != 0 && V[3] != 0 && V[4] != 0 && V[5] != 0 && V[6] != 0 && V[7] != 0; + Result = V[0] != 0 && V[1] != 0 && V[2] != 0 && V[3] != 0 && V[4] != 0 && + V[5] != 0 && V[6] != 0 && V[7] != 0; } else if constexpr (sizeof(T) == 4) { Result = V[0] != 0 && V[1] != 0 && V[2] != 0 && V[3] != 0; } else if constexpr (sizeof(T) == 8) { @@ -231,32 +238,32 @@ Expect<void> Executor::runVectorBitMaskOp(ValVariant &Val) const { 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000}; uint16_t Result = 0; - for(size_t I = 0; I < 16; ++I) { - Result |= Vector[I] < 0 ? Mask[I] : 0; + for (size_t I = 0; I < 16; ++I) { + Result |= Vector[I] < 0 ? Mask[I] : 0; } Val.emplace<uint32_t>(Result); } else if constexpr (sizeof(T) == 2) { const uint16x8_t Mask = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80}; using uint8x8_t = SIMDArray<uint8_t, 8>; uint8_t Result = 0; - for(size_t I = 0; I < 8; ++I) { - Result |= Vector[I] < 0 ? Mask[I] : 0; + for (size_t I = 0; I < 8; ++I) { + Result |= Vector[I] < 0 ? Mask[I] : 0; } Val.emplace<uint32_t>(Result); } else if constexpr (sizeof(T) == 4) { const uint32x4_t Mask = {0x1, 0x2, 0x4, 0x8}; using uint8x4_t = SIMDArray<uint8_t, 4>; uint8_t Result = 0; - for(size_t I = 0; I < 4; ++I) { - Result |= Vector[I] < 0 ? Mask[I] : 0; + for (size_t I = 0; I < 4; ++I) { + Result |= Vector[I] < 0 ? Mask[I] : 0; } Val.emplace<uint32_t>(Result); } else if constexpr (sizeof(T) == 8) { const uint64x2_t Mask = {0x1, 0x2}; using uint8x2_t = SIMDArray<uint8_t, 2>; uint8_t Result = 0; - for(size_t I = 0; I < 2; ++I) { - Result |= Vector[I] < 0 ? Mask[I] : 0; + for (size_t I = 0; I < 2; ++I) { + Result |= Vector[I] < 0 ? Mask[I] : 0; } Val.emplace<uint32_t>(Result); } diff --git a/include/executor/engine/vector_helper.h b/include/executor/engine/vector_helper.h index 8cd7997821cf..ca38673b5c33 100644 --- a/include/executor/engine/vector_helper.h +++ b/include/executor/engine/vector_helper.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/executor/executor.h b/include/executor/executor.h index ed7eed61e20a..bfa1efb6e583 100644 --- a/include/executor/executor.h +++ b/include/executor/executor.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/executor/executor.h - Executor class definition ----------===// // @@ -152,6 +152,14 @@ class Executor { Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>> instantiateModule(Runtime::StoreManager &StoreMgr, const AST::Module &Mod); + Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>> + instantiateComponent(Runtime::StoreManager &StoreMgr, + const AST::Component::Component &Comp); + Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>> + instantiateComponent(Runtime::StoreManager &StoreMgr, + const AST::Component::Component &Comp, + std::string_view Name); + /// Instantiate and register a WASM module into a named module instance. Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>> registerModule(Runtime::StoreManager &StoreMgr, const AST::Module &Mod, @@ -160,6 +168,9 @@ class Executor { /// Register an instantiated module into a named module instance. Expect<void> registerModule(Runtime::StoreManager &StoreMgr, const Runtime::Instance::ModuleInstance &ModInst); + Expect<void> + registerComponent(Runtime::StoreManager &StoreMgr, + const Runtime::Instance::ComponentInstance &CompInst); /// Register a host function which will be invoked before calling a /// host function. @@ -188,7 +199,8 @@ class Executor { } // [qdrvm] - Expect<uint32_t> dataSegmentOffset(Runtime::StackManager &StackMgr, const AST::DataSegment &DataSeg); + Expect<uint32_t> dataSegmentOffset(Runtime::StackManager &StackMgr, + const AST::DataSegment &DataSeg); private: /// Run Wasm bytecode expression for initialization. @@ -231,6 +243,10 @@ class Executor { Expect<void> instantiate(Runtime::Instance::ModuleInstance &ModInst, const AST::MemorySection &MemSec); + /// Instantiateion of Tag Instances. + Expect<void> instantiate(Runtime::Instance::ModuleInstance &ModInst, + const AST::TagSection &TagSec); + /// Instantiation of Global Instances. Expect<void> instantiate(Runtime::StackManager &StackMgr, Runtime::Instance::ModuleInstance &ModInst, @@ -259,6 +275,57 @@ class Executor { const AST::ExportSection &ExportSec); /// @} + /// @{ + /// Instantiation of Component Instance. + Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>> + instantiate(Runtime::StoreManager &StoreMgr, + const AST::Component::Component &Comp, + std::optional<std::string_view> Name = std::nullopt); + + Expect<void> instantiate(Runtime::StoreManager &StoreMgr, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::CoreInstanceSection &); + Expect<void> instantiate(Runtime::StoreManager &StoreMgr, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::CoreTypeSection &); + Expect<void> instantiate(Runtime::StoreManager &StoreMgr, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::InstanceSection &); + Expect<void> instantiate(Runtime::StoreManager &StoreMgr, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::AliasSection &); + Expect<void> instantiate(Runtime::StoreManager &StoreMgr, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::TypeSection &); + Expect<void> instantiate(Runtime::StoreManager &StoreMgr, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::CanonSection &); + Expect<void> instantiate(Runtime::StoreManager &StoreMgr, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::StartSection &); + Expect<void> instantiate(Runtime::StoreManager &StoreMgr, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::ImportSection &); + Expect<void> instantiate(Runtime::StoreManager &StoreMgr, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::ExportSection &); + /// @} + + /// \name Helper Functions for canonical ABI + /// @{ + std::unique_ptr<Runtime::Instance::FunctionInstance> + lifting(Runtime::Instance::ComponentInstance &Comp, + const WasmEdge::AST::Component::FuncType &FuncType, + Runtime::Instance::FunctionInstance *F, + Runtime::Instance::MemoryInstance *Memory, + Runtime::Instance::FunctionInstance *Realloc); + + std::unique_ptr<Runtime::Instance::FunctionInstance> + lowering(Runtime::Instance::FunctionInstance *F, + Runtime::Instance::MemoryInstance *Memory, + Runtime::Instance::FunctionInstance *Realloc); + /// @} + /// \name Helper Functions for block controls. /// @{ /// Helper function for calling functions. Return the continuation iterator. @@ -269,26 +336,21 @@ class Executor { /// Helper function for branching to label. Expect<void> branchToLabel(Runtime::StackManager &StackMgr, - uint32_t EraseBegin, uint32_t EraseEnd, - int32_t PCOffset, + const AST::Instruction::JumpDescriptor &JumpDesc, AST::InstrView::iterator &PC) noexcept; - /// @} - /// \name Helper Functions for matching value types. - /// @{ - bool matchType(const Runtime::Instance::ModuleInstance &ModExp, - const ValType &Exp, - const Runtime::Instance::ModuleInstance &ModGot, - const ValType &Got) const noexcept; - - bool matchTypes(const Runtime::Instance::ModuleInstance &ModExp, - Span<const ValType> Exp, - const Runtime::Instance::ModuleInstance &ModGot, - Span<const ValType> Got) const noexcept; + /// Helper function for throwing an exception. + Expect<void> throwException(Runtime::StackManager &StackMgr, + Runtime::Instance::TagInstance &TagInst, + AST::InstrView::iterator &PC) noexcept; /// @} - /// \name Helper Functions for getting instances. + /// \name Helper Functions for getting instances or types. /// @{ + /// Helper function for get defined type by index. + const AST::SubType *getDefTypeByIdx(Runtime::StackManager &StackMgr, + const uint32_t Idx) const; + /// Helper function for get function instance by index. Runtime::Instance::FunctionInstance * getFuncInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const; @@ -301,6 +363,10 @@ class Executor { Runtime::Instance::MemoryInstance * getMemInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const; + /// Helper function for get tag instance by index. + Runtime::Instance::TagInstance * + getTagInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const; + /// Helper function for get global instance by index. Runtime::Instance::GlobalInstance * getGlobInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const; @@ -312,6 +378,13 @@ class Executor { /// Helper function for get data instance by index. Runtime::Instance::DataInstance * getDataInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const; + + /// Helper function for converting into bottom abstract heap type. + TypeCode toBottomType(Runtime::StackManager &StackMgr, + const ValType &Type) const; + + /// Helper function for clean the unused bits of numeric values in ValVariant. + void cleanNumericVal(ValVariant &Val, const ValType &Type) const noexcept; /// @} /// \name Run instructions functions @@ -320,21 +393,31 @@ class Executor { Expect<void> runIfElseOp(Runtime::StackManager &StackMgr, const AST::Instruction &Instr, AST::InstrView::iterator &PC) noexcept; + Expect<void> runThrowOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept; + Expect<void> runThrowRefOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept; Expect<void> runBrOp(Runtime::StackManager &StackMgr, const AST::Instruction &Instr, AST::InstrView::iterator &PC) noexcept; Expect<void> runBrIfOp(Runtime::StackManager &StackMgr, const AST::Instruction &Instr, AST::InstrView::iterator &PC) noexcept; - Expect<void> runBrOnNull(Runtime::StackManager &StackMgr, - const AST::Instruction &Instr, - AST::InstrView::iterator &PC) noexcept; - Expect<void> runBrOnNonNull(Runtime::StackManager &StackMgr, - const AST::Instruction &Instr, - AST::InstrView::iterator &PC) noexcept; + Expect<void> runBrOnNullOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept; + Expect<void> runBrOnNonNullOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept; Expect<void> runBrTableOp(Runtime::StackManager &StackMgr, const AST::Instruction &Instr, AST::InstrView::iterator &PC) noexcept; + Expect<void> runBrOnCastOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC, + bool IsReverse = false) noexcept; Expect<void> runReturnOp(Runtime::StackManager &StackMgr, AST::InstrView::iterator &PC) noexcept; Expect<void> runCallOp(Runtime::StackManager &StackMgr, @@ -349,6 +432,9 @@ class Executor { const AST::Instruction &Instr, AST::InstrView::iterator &PC, bool IsTailCall = false) noexcept; + Expect<void> runTryTableOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept; /// ======= Variable instructions ======= Expect<void> runLocalGetOp(Runtime::StackManager &StackMgr, uint32_t StackOffset) const noexcept; @@ -360,6 +446,76 @@ class Executor { uint32_t Idx) const noexcept; Expect<void> runGlobalSetOp(Runtime::StackManager &StackMgr, uint32_t Idx) const noexcept; + /// ======= Reference instructions ======= + Expect<void> runRefNullOp(Runtime::StackManager &StackMgr, + const ValType &Type) const noexcept; + Expect<void> runRefIsNullOp(ValVariant &Val) const noexcept; + Expect<void> runRefFuncOp(Runtime::StackManager &StackMgr, + uint32_t Idx) const noexcept; + Expect<void> runRefEqOp(ValVariant &Val1, + const ValVariant &Val2) const noexcept; + Expect<void> runRefAsNonNullOp(RefVariant &Val, + const AST::Instruction &Instr) const noexcept; + Expect<void> runStructNewOp(Runtime::StackManager &StackMgr, + const uint32_t DefIndex, + bool IsDefault = false) const noexcept; + Expect<void> runStructGetOp(ValVariant &Val, const uint32_t Idx, + const AST::CompositeType &CompType, + const AST::Instruction &Instr, + bool IsSigned = false) const noexcept; + Expect<void> runStructSetOp(const ValVariant &Val, const RefVariant &InstRef, + const AST::CompositeType &CompType, uint32_t Idx, + const AST::Instruction &Instr) const noexcept; + Expect<void> runArrayNewOp(Runtime::StackManager &StackMgr, + const uint32_t DefIndex, uint32_t InitCnt, + uint32_t ValCnt) const noexcept; + Expect<void> + runArrayNewDataOp(Runtime::StackManager &StackMgr, + const Runtime::Instance::DataInstance &DataInst, + const AST::Instruction &Instr) const noexcept; + Expect<void> + runArrayNewElemOp(Runtime::StackManager &StackMgr, + const Runtime::Instance::ElementInstance &ElemInst, + const AST::Instruction &Instr) const noexcept; + Expect<void> runArraySetOp(const ValVariant &Val, const uint32_t Idx, + const RefVariant &InstRef, + const AST::CompositeType &CompType, + const AST::Instruction &Instr) const noexcept; + Expect<void> runArrayGetOp(ValVariant &Val, const uint32_t Idx, + const AST::CompositeType &CompType, + const AST::Instruction &Instr, + bool IsSigned = false) const noexcept; + Expect<void> runArrayLenOp(ValVariant &Val, + const AST::Instruction &Instr) const noexcept; + Expect<void> runArrayFillOp(uint32_t N, const ValVariant &Val, uint32_t D, + const RefVariant &InstRef, + const AST::CompositeType &CompType, + const AST::Instruction &Instr) const noexcept; + Expect<void> runArrayCopyOp(uint32_t N, uint32_t S, + const RefVariant &SrcInstRef, uint32_t D, + const RefVariant &DstInstRef, + const AST::CompositeType &SrcCompType, + const AST::CompositeType &DstCompType, + const AST::Instruction &Instr) const noexcept; + Expect<void> + runArrayInitDataOp(uint32_t N, uint32_t S, uint32_t D, + const RefVariant &InstRef, + const AST::CompositeType &CompType, + const Runtime::Instance::DataInstance &DataInst, + const AST::Instruction &Instr) const noexcept; + Expect<void> + runArrayInitElemOp(uint32_t N, uint32_t S, uint32_t D, + const RefVariant &InstRef, + const AST::CompositeType &CompType, + const Runtime::Instance::ElementInstance &ElemInst, + const AST::Instruction &Instr) const noexcept; + Expect<void> runRefTestOp(const Runtime::Instance::ModuleInstance *ModInst, + ValVariant &Val, const AST::Instruction &Instr, + bool IsCast = false) const noexcept; + Expect<void> runRefConvOp(RefVariant &Val, TypeCode TCode) const noexcept; + Expect<void> runRefI31Op(ValVariant &Val) const noexcept; + Expect<void> runI31GetOp(ValVariant &Val, const AST::Instruction &Instr, + bool IsSigned = false) const noexcept; /// ======= Table instructions ======= Expect<void> runTableGetOp(Runtime::StackManager &StackMgr, Runtime::Instance::TableInstance &TabInst, @@ -584,6 +740,17 @@ class Executor { template <typename T> Expect<void> runVectorFloorOp(ValVariant &Val) const; template <typename T> Expect<void> runVectorTruncOp(ValVariant &Val) const; template <typename T> Expect<void> runVectorNearestOp(ValVariant &Val) const; + + /// ======= Relaxed SIMD instructions ======= + template <typename T> + Expect<void> runVectorRelaxedLaneselectOp(ValVariant &Val1, + const ValVariant &Val2, + const ValVariant &Mask) const; + inline Expect<void> + runVectorRelaxedIntegerDotProductOp(ValVariant &Val1, + const ValVariant &Val2) const; + inline Expect<void> runVectorRelaxedIntegerDotProductOpAdd( + ValVariant &Val1, const ValVariant &Val2, const ValVariant &C) const; /// ======= Atomic instructions ======= Expect<void> runAtomicNotifyOp(Runtime::StackManager &StackMgr, Runtime::Instance::MemoryInstance &MemInst, @@ -706,7 +873,7 @@ class Executor { template <typename FuncPtr> struct ProxyHelper; /// Callbacks for compiled modules - static const AST::Module::IntrinsicsTable Intrinsics; + static const Executable::IntrinsicsTable Intrinsics; private: template <typename T> @@ -755,8 +922,9 @@ class Executor { }; struct SavedThreadLocal { - SavedThreadLocal() : SavedThis(This), SavedCurrentStack(CurrentStack), SavedExecutionContext(ExecutionContext) { - } + SavedThreadLocal() + : SavedThis(This), SavedCurrentStack(CurrentStack), + SavedExecutionContext(ExecutionContext) {} SavedThreadLocal(const SavedThreadLocal &) = delete; SavedThreadLocal(SavedThreadLocal &&) = delete; diff --git a/include/experimental/expected.hpp b/include/experimental/expected.hpp index 1242e52332cc..e0f568941480 100644 --- a/include/experimental/expected.hpp +++ b/include/experimental/expected.hpp @@ -1380,7 +1380,6 @@ class expected : public detail::expected_move_assign_base<T, E>, template <class U> using rebind = expected<U, error_type>; // 4.1, constructors - using impl_base::impl_base; constexpr expected() = default; constexpr expected(const expected &) = default; constexpr expected(expected &&) = default; @@ -1615,7 +1614,14 @@ class expected : public detail::expected_move_assign_base<T, E>, } constexpr const_rvalue_reference_type value() const && { if (!has_value()) { +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:5272) +#endif throw(bad_expected_access<E>(std::move(error()))); +#if defined(_MSC_VER) +#pragma warning(pop) +#endif } return std::move(impl_base::val()); } @@ -1627,7 +1633,14 @@ class expected : public detail::expected_move_assign_base<T, E>, } constexpr rvalue_reference_type value() && { if (!has_value()) { +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:5272) +#endif throw(bad_expected_access<E>(std::move(error()))); +#if defined(_MSC_VER) +#pragma warning(pop) +#endif } return std::move(impl_base::val()); } diff --git a/include/experimental/scope.hpp b/include/experimental/scope.hpp index ddd07ee77e9e..16575ad9b112 100644 --- a/include/experimental/scope.hpp +++ b/include/experimental/scope.hpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/mock/log.h b/include/host/mock/log.h index d25c2cc57f04..6b42ef06250a 100644 --- a/include/host/mock/log.h +++ b/include/host/mock/log.h @@ -1,11 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once #include <string_view> -#include "common/log.h" +#include "common/spdlog.h" namespace WasmEdge { namespace Host { diff --git a/include/host/mock/wasi_crypto_func.h b/include/host/mock/wasi_crypto_func.h index 980ee016d9e0..40467463e398 100644 --- a/include/host/mock/wasi_crypto_func.h +++ b/include/host/mock/wasi_crypto_func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/mock/wasi_crypto_module.h b/include/host/mock/wasi_crypto_module.h index 621e68bd821a..ae7d228ed0d9 100644 --- a/include/host/mock/wasi_crypto_module.h +++ b/include/host/mock/wasi_crypto_module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/mock/wasi_logging_func.h b/include/host/mock/wasi_logging_func.h index c1af96fe17ee..e3c983db366f 100644 --- a/include/host/mock/wasi_logging_func.h +++ b/include/host/mock/wasi_logging_func.h @@ -22,4 +22,4 @@ class Log : public Runtime::HostFunction<Log> { } // namespace WasiLoggingMock } // namespace Host -} // namespace WasmEdge \ No newline at end of file +} // namespace WasmEdge diff --git a/include/host/mock/wasi_logging_module.h b/include/host/mock/wasi_logging_module.h index 43265cbd9de9..ed908b0b5c50 100644 --- a/include/host/mock/wasi_logging_module.h +++ b/include/host/mock/wasi_logging_module.h @@ -17,4 +17,4 @@ class WasiLoggingModuleMock : public Runtime::Instance::ModuleInstance { }; } // namespace Host -} // namespace WasmEdge \ No newline at end of file +} // namespace WasmEdge diff --git a/include/host/mock/wasi_nn_func.h b/include/host/mock/wasi_nn_func.h index ddb65ed28a79..324f7e336260 100644 --- a/include/host/mock/wasi_nn_func.h +++ b/include/host/mock/wasi_nn_func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/mock/wasi_nn_module.h b/include/host/mock/wasi_nn_module.h index b999d7ee3a0e..da982bebe6e3 100644 --- a/include/host/mock/wasi_nn_module.h +++ b/include/host/mock/wasi_nn_module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/mock/wasmedge_image_func.h b/include/host/mock/wasmedge_image_func.h index f3e429be9a5c..75355e139406 100644 --- a/include/host/mock/wasmedge_image_func.h +++ b/include/host/mock/wasmedge_image_func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/mock/wasmedge_image_module.h b/include/host/mock/wasmedge_image_module.h index 071c841c2118..6e65300e139d 100644 --- a/include/host/mock/wasmedge_image_module.h +++ b/include/host/mock/wasmedge_image_module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/mock/wasmedge_process_func.h b/include/host/mock/wasmedge_process_func.h index e61c095e9b84..94d59390de6a 100644 --- a/include/host/mock/wasmedge_process_func.h +++ b/include/host/mock/wasmedge_process_func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/mock/wasmedge_process_module.h b/include/host/mock/wasmedge_process_module.h index ab2f0a0c86fe..296a5fc4b157 100644 --- a/include/host/mock/wasmedge_process_module.h +++ b/include/host/mock/wasmedge_process_module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/mock/wasmedge_stablediffusion_func.h b/include/host/mock/wasmedge_stablediffusion_func.h new file mode 100644 index 000000000000..1623204cf935 --- /dev/null +++ b/include/host/mock/wasmedge_stablediffusion_func.h @@ -0,0 +1,64 @@ +#pragma once + +#include "common/errcode.h" +#include "host/mock/log.h" +#include "runtime/callingframe.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeStableDiffusionMock { + +using namespace std::literals; +static inline constexpr const uint32_t kStableDiffusionError = 1U; + +class CreateContext : public Runtime::HostFunction<CreateContext> { +public: + Expect<uint32_t> body(const Runtime::CallingFrame &, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t) { + printPluginMock("WasmEdge-Stable-Diffusion"sv); + return kStableDiffusionError; + } +}; + +class TextToImage : public Runtime::HostFunction<TextToImage> { +public: + Expect<uint32_t> body(const Runtime::CallingFrame &, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, float, + uint32_t, uint32_t, int32_t, float, uint32_t, uint32_t, + uint32_t, uint32_t, float, float, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) { + printPluginMock("WasmEdge-Stable-Diffusion"sv); + return kStableDiffusionError; + } +}; +class ImageToImage : public Runtime::HostFunction<ImageToImage> { +public: + Expect<uint32_t> body(const Runtime::CallingFrame &, uint32_t, uint32_t, + uint32_t, float, uint32_t, uint32_t, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t, uint32_t, int32_t, float, + uint32_t, uint32_t, float, uint32_t, uint32_t, float, + float, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, + uint32_t, uint32_t) { + printPluginMock("WasmEdge-Stable-Diffusion"sv); + return kStableDiffusionError; + } +}; +class Convert : public Runtime::HostFunction<Convert> { +public: + Expect<uint32_t> body(const Runtime::CallingFrame &, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) { + printPluginMock("WasmEdge-Stable-Diffusion"sv); + return kStableDiffusionError; + } +}; +} // namespace WasmEdgeStableDiffusionMock +} // namespace Host +} // namespace WasmEdge diff --git a/include/host/mock/wasmedge_stablediffusion_module.h b/include/host/mock/wasmedge_stablediffusion_module.h new file mode 100644 index 000000000000..e070935b48ff --- /dev/null +++ b/include/host/mock/wasmedge_stablediffusion_module.h @@ -0,0 +1,24 @@ +#pragma once + +#include "host/mock/wasmedge_stablediffusion_func.h" +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { +class WasmEdgeStableDiffusionModuleMock + : public Runtime::Instance::ModuleInstance { +public: + WasmEdgeStableDiffusionModuleMock() + : Runtime::Instance::ModuleInstance("wasmedge_stablediffusion") { + addHostFunc("create_context", + std::make_unique<WasmEdgeStableDiffusionMock::CreateContext>()); + addHostFunc("text_to_image", + std::make_unique<WasmEdgeStableDiffusionMock::TextToImage>()); + addHostFunc("image_to_image", + std::make_unique<WasmEdgeStableDiffusionMock::ImageToImage>()); + addHostFunc("convert", + std::make_unique<WasmEdgeStableDiffusionMock::Convert>()); + } +}; +} // namespace Host +} // namespace WasmEdge diff --git a/include/host/mock/wasmedge_tensorflow_func.h b/include/host/mock/wasmedge_tensorflow_func.h index 2f55ebafe763..c14db4b51b21 100644 --- a/include/host/mock/wasmedge_tensorflow_func.h +++ b/include/host/mock/wasmedge_tensorflow_func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/mock/wasmedge_tensorflow_module.h b/include/host/mock/wasmedge_tensorflow_module.h index 0101db2f63e3..87959748321e 100644 --- a/include/host/mock/wasmedge_tensorflow_module.h +++ b/include/host/mock/wasmedge_tensorflow_module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/mock/wasmedge_tensorflowlite_func.h b/include/host/mock/wasmedge_tensorflowlite_func.h index 56f266266aab..378c489b6496 100644 --- a/include/host/mock/wasmedge_tensorflowlite_func.h +++ b/include/host/mock/wasmedge_tensorflowlite_func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/mock/wasmedge_tensorflowlite_module.h b/include/host/mock/wasmedge_tensorflowlite_module.h index 880bf5a8ec74..bf741331fa7a 100644 --- a/include/host/mock/wasmedge_tensorflowlite_module.h +++ b/include/host/mock/wasmedge_tensorflowlite_module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/wasi/clock.h b/include/host/wasi/clock.h index 3617a2e30e08..79ec6e5ac90b 100644 --- a/include/host/wasi/clock.h +++ b/include/host/wasi/clock.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/wasi/environ.h b/include/host/wasi/environ.h index 19c531e020e7..b96ab8f7550d 100644 --- a/include/host/wasi/environ.h +++ b/include/host/wasi/environ.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/wasi/error.h b/include/host/wasi/error.h index 3c294d54e1fc..7ff181be29a6 100644 --- a/include/host/wasi/error.h +++ b/include/host/wasi/error.h @@ -1,10 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once #include "common/expected.h" -#include "common/log.h" +#include "common/spdlog.h" #include "wasi/api.hpp" #include <string_view> diff --git a/include/host/wasi/inode.h b/include/host/wasi/inode.h index c53ce420be3c..2192e20885c0 100644 --- a/include/host/wasi/inode.h +++ b/include/host/wasi/inode.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once @@ -53,21 +53,30 @@ struct FdHolder { FdHolder(const FdHolder &) = delete; FdHolder &operator=(const FdHolder &) = delete; FdHolder(FdHolder &&RHS) noexcept - : Fd(std::exchange(RHS.Fd, -1)), Cleanup(RHS.Cleanup) {} + : Fd(std::exchange(RHS.Fd, -1)), Cleanup(RHS.Cleanup), + Append(RHS.Append) { + RHS.Cleanup = true; + RHS.Append = false; + } FdHolder &operator=(FdHolder &&RHS) noexcept { using std::swap; swap(Fd, RHS.Fd); + Cleanup = RHS.Cleanup; + Append = RHS.Append; + RHS.Cleanup = true; + RHS.Append = false; return *this; } - constexpr FdHolder() noexcept = default; + constexpr FdHolder() noexcept : Fd(-1), Cleanup(true), Append(false) {} ~FdHolder() noexcept { if (Cleanup) { reset(); } } - explicit constexpr FdHolder(int Fd, bool Cleanup = true) noexcept - : Fd(Fd), Cleanup(Cleanup) {} + explicit constexpr FdHolder(int Fd, bool Cleanup = true, + bool Append = false) noexcept + : Fd(Fd), Cleanup(Cleanup), Append(Append) {} constexpr bool ok() const noexcept { return Fd >= 0; } void reset() noexcept; int release() noexcept { return std::exchange(Fd, -1); } @@ -77,7 +86,8 @@ struct FdHolder { } int getFd() noexcept { return Fd; } int Fd = -1; - bool Cleanup = true; + bool Cleanup : 1; + mutable bool Append : 1; }; struct DirHolder { @@ -962,6 +972,8 @@ class Poller uint64_t NextTimerId = 0; #endif #if WASMEDGE_OS_WINDOWS + std::unordered_map<winapi::HANDLE_, OptionalEvent *> ConsoleReadEvent; + std::unordered_map<winapi::HANDLE_, OptionalEvent *> ConsoleWriteEvent; OptionalEvent *TimeoutEvent = nullptr; winapi::TIMEVAL_ MinimumTimeout; #endif diff --git a/include/host/wasi/vfs.h b/include/host/wasi/vfs.h index 7f24e4becd61..c9f3e554407b 100644 --- a/include/host/wasi/vfs.h +++ b/include/host/wasi/vfs.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/wasi/vinode.h b/include/host/wasi/vinode.h index ba0d8a4ab3a1..7dcc90a48ba3 100644 --- a/include/host/wasi/vinode.h +++ b/include/host/wasi/vinode.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/wasi/wasibase.h b/include/host/wasi/wasibase.h index 1455bbd05f27..4b8793272951 100644 --- a/include/host/wasi/wasibase.h +++ b/include/host/wasi/wasibase.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/wasi/wasifunc.h b/include/host/wasi/wasifunc.h index b4f1146ec98e..a51591d6037c 100644 --- a/include/host/wasi/wasifunc.h +++ b/include/host/wasi/wasifunc.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/host/wasi/wasimodule.h b/include/host/wasi/wasimodule.h index 4388742f414e..2a95e3d4bfe2 100644 --- a/include/host/wasi/wasimodule.h +++ b/include/host/wasi/wasimodule.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/include/llvm/codegen.h b/include/llvm/codegen.h new file mode 100644 index 000000000000..670682dfe172 --- /dev/null +++ b/include/llvm/codegen.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +//===-- wasmedge/llvm/codegen.h - Code Generator class definition ---------===// +// +// Part of the WasmEdge Project. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file is the definition class of Compiler class. +/// +//===----------------------------------------------------------------------===// +#pragma once + +#include "ast/module.h" +#include "common/configure.h" +#include "common/errcode.h" +#include "common/filesystem.h" +#include "common/span.h" +#include "llvm/data.h" + +#include <mutex> + +namespace WasmEdge::LLVM { + +/// Compiling LLVM Module into loadable executable binary. +class CodeGen { +public: + CodeGen(const Configure &Conf) noexcept : Conf(Conf) {} + Expect<void> codegen(Span<const Byte> WasmData, Data D, + std::filesystem::path OutputPath) noexcept; + +private: + const Configure Conf; +}; + +} // namespace WasmEdge::LLVM diff --git a/include/aot/compiler.h b/include/llvm/compiler.h similarity index 77% rename from include/aot/compiler.h rename to include/llvm/compiler.h index 3ace24de2729..3b70d3481706 100644 --- a/include/aot/compiler.h +++ b/include/llvm/compiler.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC -//===-- wasmedge/aot/compiler.h - Compiler class definition ---------------===// +//===-- wasmedge/llvm/compiler.h - Compiler class definition --------------===// // // Part of the WasmEdge Project. // @@ -18,19 +18,18 @@ #include "common/errcode.h" #include "common/filesystem.h" #include "common/span.h" +#include "llvm/data.h" #include <mutex> -namespace WasmEdge { -namespace AOT { +namespace WasmEdge::LLVM { -/// Compiling Module into loadable executable binary. +/// Compiling Module into LLVM Module. class Compiler { public: Compiler(const Configure &Conf) noexcept : Context(nullptr), Conf(Conf) {} - Expect<void> compile(Span<const Byte> Data, const AST::Module &Module, - std::filesystem::path OutputPath) noexcept; + Expect<Data> compile(const AST::Module &Module) noexcept; struct CompileContext; @@ -51,5 +50,4 @@ class Compiler { const Configure Conf; }; -} // namespace AOT -} // namespace WasmEdge +} // namespace WasmEdge::LLVM diff --git a/include/llvm/data.h b/include/llvm/data.h new file mode 100644 index 000000000000..c2272774a454 --- /dev/null +++ b/include/llvm/data.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +//===-- wasmedge/llvm/data.h - Data class definition ----------------------===// +// +// Part of the WasmEdge Project. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file is the definition class of Data class. +/// +//===----------------------------------------------------------------------===// +#pragma once + +#include "ast/module.h" +#include "common/configure.h" +#include "common/errcode.h" +#include "common/filesystem.h" +#include "common/span.h" + +#include <mutex> + +namespace WasmEdge::LLVM { + +/// Holds llvm-relative runtime data, like llvm::Context, llvm::Module, etc. +class Data { +public: + struct DataContext; + Data() noexcept; + ~Data() noexcept; + Data(Data &&) noexcept; + Data &operator=(Data &&) noexcept; + DataContext &extract() noexcept { return *Context; } + +private: + std::unique_ptr<DataContext> Context; + const Configure Conf; +}; + +} // namespace WasmEdge::LLVM diff --git a/include/llvm/jit.h b/include/llvm/jit.h new file mode 100644 index 000000000000..5049d6b9f9db --- /dev/null +++ b/include/llvm/jit.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +//===-- wasmedge/llvm/jit.h - JIT Engine class definition -----------------===// +// +// Part of the WasmEdge Project. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file is the definition class of JIT engine class. +/// +//===----------------------------------------------------------------------===// +#pragma once + +#include "ast/module.h" +#include "common/configure.h" +#include "common/errcode.h" +#include "llvm/data.h" +#include <vector> + +namespace WasmEdge::LLVM { +class OrcLLJIT; + +class JITLibrary : public Executable { +public: + JITLibrary(OrcLLJIT JIT) noexcept; + ~JITLibrary() noexcept override; + + Symbol<const IntrinsicsTable *> getIntrinsics() noexcept override; + + std::vector<Symbol<Wrapper>> getTypes(size_t Size) noexcept override; + + std::vector<Symbol<void>> getCodes(size_t Offset, + size_t Size) noexcept override; + +private: + OrcLLJIT *J; +}; + +class JIT { +public: + JIT(const Configure &Conf) noexcept : Conf(Conf) {} + Expect<std::shared_ptr<Executable>> load(Data D) noexcept; + +private: + const Configure Conf; +}; + +} // namespace WasmEdge::LLVM diff --git a/include/loader/aot_section.h b/include/loader/aot_section.h new file mode 100644 index 000000000000..f0d2252f72b6 --- /dev/null +++ b/include/loader/aot_section.h @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +//===-- wasmedge/loader/aot_section.h - AOT Section definition ------------===// +// +// Part of the WasmEdge Project. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the declaration of the AOTSection, which holds logics to +/// load from an AOTSection +/// +//===----------------------------------------------------------------------===// +#pragma once + +#include "ast/section.h" +#include "common/executable.h" +#include "common/filesystem.h" +#include "system/winapi.h" + +#include <cstdint> +#include <memory> +#include <vector> + +namespace WasmEdge { +namespace Loader { + +/// Holder class for library handle +class AOTSection : public Executable { +public: + AOTSection() noexcept = default; + ~AOTSection() noexcept override { unload(); } + Expect<void> load(const AST::AOTSection &AOTSec) noexcept; + void unload() noexcept; + + Symbol<const IntrinsicsTable *> getIntrinsics() noexcept override { + if (Binary) { + return createSymbol<const IntrinsicsTable *>( + getPointer<const IntrinsicsTable *>(IntrinsicsAddress)); + } + return {}; + } + + std::vector<Symbol<Wrapper>> getTypes(size_t) noexcept override { + std::vector<Symbol<Wrapper>> Result; + if (Binary) { + Result.reserve(TypesAddress.size()); + for (const auto Address : TypesAddress) { + Result.push_back(createSymbol<Wrapper>(getPointer<Wrapper>(Address))); + } + } + return Result; + } + + std::vector<Symbol<void>> getCodes(size_t, size_t) noexcept override { + std::vector<Symbol<void>> Result; + if (Binary) { + Result.reserve(CodesAddress.size()); + for (const auto Address : CodesAddress) { + Result.push_back(createSymbol<void>(getPointer<void>(Address))); + } + } + return Result; + } + +private: + uintptr_t getOffset() const noexcept { + return reinterpret_cast<uintptr_t>(Binary); + } + + template <typename T> T *getPointer(uint64_t Address) const noexcept { + return reinterpret_cast<T *>(getOffset() + Address); + } + + uint8_t *Binary = nullptr; + uint64_t BinarySize = 0; + uint64_t IntrinsicsAddress = 0; + std::vector<uintptr_t> TypesAddress; + std::vector<uintptr_t> CodesAddress; +#if WASMEDGE_OS_LINUX + void *EHFrameAddress = nullptr; +#elif WASMEDGE_OS_MACOS + uint8_t *EHFrameAddress = nullptr; + uint32_t EHFrameSize = 0; +#elif WASMEDGE_OS_WINDOWS + void *PDataAddress = nullptr; + uint32_t PDataSize = 0; +#endif +}; + +} // namespace Loader +} // namespace WasmEdge diff --git a/include/loader/filemgr.h b/include/loader/filemgr.h index ab223053fcd4..8e90ed7847e9 100644 --- a/include/loader/filemgr.h +++ b/include/loader/filemgr.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/loader/filemgr.h - File Manager definition ---------------===// // @@ -86,6 +86,9 @@ class FileMgr { /// Read a string, which is size(unsigned int) + bytes. Expect<std::string> readName(); + /// Peek one byte. + Expect<Byte> peekByte(); + /// Get the file header type. FileHeader getHeaderType(); diff --git a/include/loader/ldmgr.h b/include/loader/ldmgr.h deleted file mode 100644 index 8787ab9978df..000000000000 --- a/include/loader/ldmgr.h +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC - -//===-- wasmedge/loader/ldmgr.h - Loadable Manager definition -------------===// -// -// Part of the WasmEdge Project. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This file contains the declaration of the LDMgr class, which controls flow -/// of Compiled Binary loading. -/// -//===----------------------------------------------------------------------===// -#pragma once - -#include "common/types.h" -#include "loader/shared_library.h" - -#include <cstdint> -#include <memory> -#include <vector> - -namespace WasmEdge { - -/// Loadable manager interface. -class LDMgr { -public: - LDMgr(const void *IT = nullptr) : Intrinsics(IT) {} - - /// Set the file path. - Expect<void> setPath(const std::filesystem::path &FilePath); - - /// Read embedded Wasm binary. - Expect<std::vector<Byte>> getWasm(); - - /// Read wasmedge version. - Expect<uint32_t> getVersion(); - - /// Get symbol. - template <typename T = void> auto getSymbol(const char *Name) noexcept { - return Library->get<T>(Name); - } - - /// Reset status. - void reset() noexcept { - Intrinsics = nullptr; - Library.reset(); - } - -private: - std::shared_ptr<Loader::SharedLibrary> Library; - const void *Intrinsics; -}; - -} // namespace WasmEdge diff --git a/include/loader/loader.h b/include/loader/loader.h index 0aa2b0d946c4..4ef20da354ab 100644 --- a/include/loader/loader.h +++ b/include/loader/loader.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/loader/loader.h - Loader flow control class definition ---===// // @@ -18,8 +18,8 @@ #include "common/configure.h" #include "common/errinfo.h" #include "loader/filemgr.h" -#include "loader/ldmgr.h" #include "loader/serialize.h" +#include "loader/shared_library.h" #include <cstdint> #include <memory> @@ -73,6 +73,18 @@ template <> inline ASTNodeAttr NodeAttrFromAST<AST::DataCountSection>() noexcept { return ASTNodeAttr::Sec_DataCount; } +template <> inline ASTNodeAttr NodeAttrFromAST<AST::SubType>() noexcept { + return ASTNodeAttr::Type_Rec; +} +template <> inline ASTNodeAttr NodeAttrFromAST<AST::FunctionType>() noexcept { + return ASTNodeAttr::Type_Function; +} +template <> inline ASTNodeAttr NodeAttrFromAST<AST::ElementSegment>() noexcept { + return ASTNodeAttr::Seg_Element; +} +template <> inline ASTNodeAttr NodeAttrFromAST<AST::TagSection>() noexcept { + return ASTNodeAttr::Sec_Tag; +} template <> inline ASTNodeAttr NodeAttrFromAST<AST::Component::AliasSection>() noexcept { return ASTNodeAttr::Sec_Alias; @@ -126,8 +138,8 @@ NodeAttrFromAST<AST::Component::ComponentSection>() noexcept { class Loader { public: Loader(const Configure &Conf, - const AST::Module::IntrinsicsTable *IT = nullptr) noexcept - : Conf(Conf), Ser(Conf), LMgr(IT), IntrinsicsTable(IT) {} + const Executable::IntrinsicsTable *IT = nullptr) noexcept + : Conf(Conf), Ser(Conf), IntrinsicsTable(IT) {} ~Loader() noexcept = default; /// Load data from file path. @@ -160,10 +172,11 @@ class Loader { Expect<std::vector<Byte>> serializeModule(const AST::Module &Mod); /// Reset status. - void reset() noexcept { - FMgr.reset(); - LMgr.reset(); - } + void reset() noexcept { FMgr.reset(); } + + /// Setup Symbol from an Exetuable. + Expect<void> loadExecutable(AST::Module &Mod, + std::shared_ptr<Executable> Library); private: /// \name Helper functions to print error log when loading AST nodes @@ -186,104 +199,99 @@ class Loader { } /// @} + /// \name Load AST Module functions + /// @{ Expect<std::variant<std::unique_ptr<AST::Component::Component>, std::unique_ptr<AST::Module>>> loadUnit(); Expect<std::pair<std::vector<Byte>, std::vector<Byte>>> loadPreamble(); - - /// \name Load AST Component functions - /// @{ - Expect<void> loadComponent(AST::Component::Component &Comp); - /// @} - - /// \name Load AST Module functions - /// @{ Expect<void> loadModule(AST::Module &Mod); Expect<void> loadModuleInBound(AST::Module &Mod, std::optional<uint64_t> Bound); - Expect<void> loadCompiled(AST::Module &Mod); + Expect<void> loadUniversalWASM(AST::Module &Mod); + Expect<void> loadModuleAOT(AST::AOTSection &AOTSection); + Expect<void> loadComponent(AST::Component::Component &Comp); /// @} /// \name Load AST section node helper functions /// @{ - Expect<void> loadUniversalWASM(AST::Module &Mod); - Expect<void> loadModuleAOT(AST::AOTSection &AOTSection); - - Expect<uint32_t> loadSectionSize(ASTNodeAttr Node); - template <typename T, typename L> - Expect<void> loadSectionContent(T &Sec, L &&Func) { - Sec.setStartOffset(FMgr.getOffset()); - if (auto Res = loadSectionSize(NodeAttrFromAST<T>())) { - // Set the section size. - Sec.setContentSize(*Res); - auto StartOffset = FMgr.getOffset(); - auto ResContent = Func(); - if (!ResContent) { - return Unexpect(ResContent); - } - // Check the read size match the section size. - auto EndOffset = FMgr.getOffset(); - if (EndOffset - StartOffset != Sec.getContentSize()) { - return logLoadError(ErrCode::Value::SectionSizeMismatch, EndOffset, - NodeAttrFromAST<T>()); + Expect<uint32_t> loadVecCnt() { + // Read the vector size. + if (auto Res = FMgr.readU32()) { + if ((*Res) / 2 > FMgr.getRemainSize()) { + return Unexpect(ErrCode::Value::IntegerTooLong); } + return *Res; } else { return Unexpect(Res); } - return {}; } - template <typename T, typename L> - Expect<void> loadSectionContentVec(T &Sec, L &&Func) { + + template <typename ASTType, typename T, typename ElemLoader> + Expect<void> loadVec(std::vector<T> &Vec, ElemLoader &&Func) { uint32_t VecCnt = 0; // Read the vector size. - if (auto Res = FMgr.readU32()) { + if (auto Res = loadVecCnt()) { VecCnt = *Res; - if (VecCnt / 2 > FMgr.getRemainSize()) { - return logLoadError(ErrCode::Value::IntegerTooLong, - FMgr.getLastOffset(), NodeAttrFromAST<T>()); - } - Sec.getContent().resize(VecCnt); + Vec.resize(*Res); } else { return logLoadError(Res.error(), FMgr.getLastOffset(), - NodeAttrFromAST<T>()); + NodeAttrFromAST<ASTType>()); } // Sequently create the AST node T and read data. for (uint32_t I = 0; I < VecCnt; ++I) { - if (auto Res = Func(Sec.getContent()[I]); !Res) { - spdlog::error(ErrInfo::InfoAST(NodeAttrFromAST<T>())); + if (auto Res = Func(Vec[I]); !Res) { + spdlog::error(ErrInfo::InfoAST(NodeAttrFromAST<ASTType>())); return Unexpect(Res); } } return {}; } - template <typename T, typename C, typename L> - Expect<void> loadVec(std::vector<C> &Vec, L &&Func) { - uint32_t VecCnt = 0; - // Read the vector size. + template <typename T, typename ElemLoader> + Expect<void> loadSectionContent(T &Sec, ElemLoader &&Func) { + Sec.setStartOffset(FMgr.getOffset()); if (auto Res = FMgr.readU32()) { - VecCnt = *Res; - if (VecCnt / 2 > FMgr.getRemainSize()) { - return logLoadError(ErrCode::Value::IntegerTooLong, + // Load the section size first. + if (unlikely(FMgr.getRemainSize() < (*Res))) { + return logLoadError(ErrCode::Value::LengthOutOfBounds, FMgr.getLastOffset(), NodeAttrFromAST<T>()); } - Vec.resize(VecCnt); + // Set the section size. + Sec.setContentSize(*Res); + auto StartOffset = FMgr.getOffset(); + // Invoke the callback function. + auto ResContent = Func(); + if (!ResContent) { + return Unexpect(ResContent); + } + // Check the read size matches the section size. + auto EndOffset = FMgr.getOffset(); + if (EndOffset - StartOffset != Sec.getContentSize()) { + return logLoadError(ErrCode::Value::SectionSizeMismatch, EndOffset, + NodeAttrFromAST<T>()); + } } else { return logLoadError(Res.error(), FMgr.getLastOffset(), NodeAttrFromAST<T>()); } + return {}; + } + /// @} - // Sequently create the AST node T and read data. - for (uint32_t I = 0; I < VecCnt; ++I) { - if (auto Res = Func(Vec[I]); !Res) { - spdlog::error(ErrInfo::InfoAST(NodeAttrFromAST<T>())); - return Unexpect(Res); - } - } + /// \name Helper function to set the function type for tag + /// @{ + void setTagFunctionType(AST::TagSection &TagSec, + AST::ImportSection &ImportSec, + AST::TypeSection &TypeSec); + /// @} - return {}; + template <typename T, typename ElemLoader> + Expect<void> loadSectionContentVec(T &Sec, ElemLoader &&Func) { + return loadVec<T>(Sec.getContent(), std::move(Func)); } + /// @} /// \name Load AST nodes functions /// @{ @@ -300,6 +308,7 @@ class Loader { Expect<void> loadSection(AST::CodeSection &Sec); Expect<void> loadSection(AST::DataSection &Sec); Expect<void> loadSection(AST::DataCountSection &Sec); + Expect<void> loadSection(AST::TagSection &Sec); Expect<void> loadSection(AST::Component::ComponentSection &Sec); Expect<void> loadSection(AST::CoreModuleSection &Sec); Expect<void> loadSection(AST::Component::CoreInstanceSection &Sec); @@ -307,6 +316,7 @@ class Loader { Expect<void> loadSection(AST::Component::AliasSection &Sec); Expect<void> loadSection(AST::Component::CoreTypeSection &Sec); Expect<void> loadSection(AST::Component::TypeSection &Sec); + Expect<void> loadSection(AST::Component::StartSection &Sec); Expect<void> loadSection(AST::Component::CanonSection &Sec); Expect<void> loadSection(AST::Component::ImportSection &Sec); Expect<void> loadSection(AST::Component::ExportSection &Sec); @@ -326,12 +336,17 @@ class Loader { Expect<void> loadDesc(AST::ExportDesc &ExpDesc); Expect<ValType> loadHeapType(TypeCode TC, ASTNodeAttr From); Expect<ValType> loadRefType(ASTNodeAttr From); - Expect<ValType> loadValType(ASTNodeAttr From); + Expect<ValType> loadValType(ASTNodeAttr From, bool IsStorageType = false); + Expect<ValMut> loadMutability(ASTNodeAttr From); + Expect<void> loadFieldType(AST::FieldType &FType); + Expect<void> loadCompositeType(AST::CompositeType &CType); Expect<void> loadLimit(AST::Limit &Lim); + Expect<void> loadType(AST::SubType &SType); Expect<void> loadType(AST::FunctionType &FuncType); Expect<void> loadType(AST::MemoryType &MemType); Expect<void> loadType(AST::TableType &TabType); Expect<void> loadType(AST::GlobalType &GlobType); + Expect<void> loadType(AST::TagType &TgType); Expect<void> loadType(AST::Component::DefType &Ty); Expect<void> loadType(AST::Component::FuncType &Ty); @@ -415,8 +430,7 @@ class Loader { const Configure Conf; const Serializer Ser; FileMgr FMgr; - LDMgr LMgr; - const AST::Module::IntrinsicsTable *IntrinsicsTable; + const Executable::IntrinsicsTable *IntrinsicsTable; std::recursive_mutex Mutex; bool HasDataSection; diff --git a/include/loader/serialize.h b/include/loader/serialize.h index 95e41c3ad0b2..4a9550a88635 100644 --- a/include/loader/serialize.h +++ b/include/loader/serialize.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/loader/serialize.h - Serializer class definition ---------===// // @@ -88,6 +88,8 @@ class Serializer { std::vector<uint8_t> &OutVec) const noexcept; Expect<void> serializeLimit(const AST::Limit &Lim, std::vector<uint8_t> &OutVec) const noexcept; + Expect<void> serializeType(const AST::SubType &SType, + std::vector<uint8_t> &OutVec) const noexcept; Expect<void> serializeType(const AST::FunctionType &Type, std::vector<uint8_t> &OutVec) const noexcept; Expect<void> serializeType(const AST::TableType &Type, diff --git a/include/loader/shared_library.h b/include/loader/shared_library.h index ea765d13b1fc..54623e2530e3 100644 --- a/include/loader/shared_library.h +++ b/include/loader/shared_library.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/loader/shared_library.h - Shared library definition ------===// // @@ -15,10 +15,8 @@ #pragma once #include "ast/section.h" -#include "common/defines.h" -#include "common/errcode.h" +#include "common/executable.h" #include "common/filesystem.h" -#include "common/symbol.h" #include "system/winapi.h" #include <cstdint> @@ -29,12 +27,7 @@ namespace WasmEdge { namespace Loader { /// Holder class for library handle -class SharedLibrary : public std::enable_shared_from_this<SharedLibrary> { - SharedLibrary(const SharedLibrary &) = delete; - SharedLibrary &operator=(const SharedLibrary &) = delete; - SharedLibrary(SharedLibrary &&) = delete; - SharedLibrary &operator=(SharedLibrary &&) = delete; - +class SharedLibrary : public Executable { public: #if WASMEDGE_OS_WINDOWS using NativeHandle = winapi::HMODULE_; @@ -43,64 +36,78 @@ class SharedLibrary : public std::enable_shared_from_this<SharedLibrary> { #endif SharedLibrary() noexcept = default; - ~SharedLibrary() noexcept { unload(); } + ~SharedLibrary() noexcept override { unload(); } Expect<void> load(const std::filesystem::path &Path) noexcept; - Expect<void> load(const AST::AOTSection &AOTSec) noexcept; void unload() noexcept; - template <typename T> Symbol<T> get(const char *Name) { - return Symbol<T>(shared_from_this(), - reinterpret_cast<T *>(getSymbolAddr(Name))); + Symbol<const IntrinsicsTable *> getIntrinsics() noexcept override { + return get<const IntrinsicsTable *>("intrinsics"); } - uintptr_t getOffset() const noexcept; + std::vector<Symbol<Wrapper>> getTypes(size_t Size) noexcept override { + using namespace std::literals; + std::vector<Symbol<Wrapper>> Result; + Result.reserve(Size); + for (size_t I = 0; I < Size; ++I) { + // "t" prefix is for type helper function + const std::string Name = fmt::format("t{}"sv, I); + if (auto Symbol = get<Wrapper>(Name.c_str())) { + Result.push_back(std::move(Symbol)); + } + } - template <typename T> T *getPointer(uint64_t Address) const noexcept { - return reinterpret_cast<T *>(getOffset() + Address); + return Result; } - template <typename T> Symbol<T> getIntrinsics() noexcept { - if (Binary) { - return Symbol<T>(shared_from_this(), getPointer<T>(IntrinsicsAddress)); + std::vector<Symbol<void>> getCodes(size_t Offset, + size_t Size) noexcept override { + using namespace std::literals; + std::vector<Symbol<void>> Result; + Result.reserve(Size); + for (size_t I = 0; I < Size; ++I) { + // "f" prefix is for code function + const std::string Name = fmt::format("f{}"sv, I + Offset); + if (auto Symbol = get<void>(Name.c_str())) { + Result.push_back(std::move(Symbol)); + } } - return {}; + + return Result; } - template <typename T> std::vector<Symbol<T>> getTypes() noexcept { - std::vector<Symbol<T>> Result; - if (Binary) { - Result.reserve(TypesAddress.size()); - for (const auto Address : TypesAddress) { - Result.push_back(Symbol<T>(shared_from_this(), getPointer<T>(Address))); - } + /// Read embedded Wasm binary. + Expect<std::vector<Byte>> getWasm() noexcept { + const auto Size = get<uint32_t>("wasm.size"); + if (unlikely(!Size)) { + spdlog::error(ErrCode::Value::IllegalGrammar); + return Unexpect(ErrCode::Value::IllegalGrammar); } - return Result; + const auto Code = get<uint8_t>("wasm.code"); + if (unlikely(!Code)) { + spdlog::error(ErrCode::Value::IllegalGrammar); + return Unexpect(ErrCode::Value::IllegalGrammar); + } + + return std::vector<Byte>(Code.get(), Code.get() + *Size); } - template <typename T> std::vector<Symbol<T>> getCodes() noexcept { - std::vector<Symbol<T>> Result; - if (Binary) { - Result.reserve(CodesAddress.size()); - for (const auto Address : CodesAddress) { - Result.push_back(Symbol<T>(shared_from_this(), getPointer<T>(Address))); - } + /// Read wasmedge version. + Expect<uint32_t> getVersion() noexcept { + const auto Version = get<uint32_t>("version"); + if (unlikely(!Version)) { + spdlog::error(ErrCode::Value::IllegalGrammar); + return Unexpect(ErrCode::Value::IllegalGrammar); } - return Result; + return *Version; + } + + template <typename T> Symbol<T> get(const char *Name) { + return createSymbol<T>(reinterpret_cast<T *>(getSymbolAddr(Name))); } private: void *getSymbolAddr(const char *Name) const noexcept; NativeHandle Handle{}; - - uint8_t *Binary = nullptr; - uint64_t BinarySize = 0; - uint64_t IntrinsicsAddress = 0; - std::vector<uintptr_t> TypesAddress; - std::vector<uintptr_t> CodesAddress; -#if WASMEDGE_OS_WINDOWS - void *PDataAddress = 0; - uint32_t PDataSize = 0; -#endif }; } // namespace Loader diff --git a/include/plugin/plugin.h b/include/plugin/plugin.h index c91478b7d499..e5fa1d8a007c 100644 --- a/include/plugin/plugin.h +++ b/include/plugin/plugin.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugin/plugin.h - Plugin class definition ----------------===// // @@ -18,9 +18,12 @@ #include "common/version.h" #include "loader/shared_library.h" #include "po/argument_parser.h" +#include "runtime/instance/component.h" #include "runtime/instance/module.h" + #include <cstdint> #include <memory> +#include <mutex> #include <vector> #if WASMEDGE_OS_WINDOWS @@ -29,6 +32,12 @@ #define WASMEDGE_EXPORT [[gnu::visibility("default")]] #endif +#define EXPORT_GET_DESCRIPTOR(Descriptor) \ + extern "C" WASMEDGE_EXPORT decltype(&Descriptor) GetDescriptor(); \ + extern "C" WASMEDGE_EXPORT decltype(&Descriptor) GetDescriptor() { \ + return &Descriptor; \ + } + namespace WasmEdge { namespace Plugin { @@ -72,6 +81,47 @@ class PluginModule { friend class Plugin; }; +class PluginComponent { +public: + PluginComponent(const PluginComponent &) = delete; + PluginComponent &operator=(const PluginComponent &) = delete; + PluginComponent(PluginComponent &&) noexcept = default; + PluginComponent &operator=(PluginComponent &&) noexcept = default; + + struct ComponentDescriptor { + const char *Name; + const char *Description; + Runtime::Instance::ComponentInstance *(*Create)( + const ComponentDescriptor *) noexcept; + }; + + constexpr PluginComponent() noexcept {} + + constexpr const char *name() const noexcept { + assuming(Desc); + return Desc->Name; + } + + constexpr const char *description() const noexcept { + assuming(Desc); + return Desc->Description; + } + + std::unique_ptr<Runtime::Instance::ComponentInstance> + create() const noexcept { + assuming(Desc); + return std::unique_ptr<Runtime::Instance::ComponentInstance>( + Desc->Create(Desc)); + } + +private: + const ComponentDescriptor *Desc = nullptr; + + constexpr explicit PluginComponent(const ComponentDescriptor *D) noexcept + : Desc(D) {} + friend class Plugin; +}; + class Plugin { public: struct VersionData { @@ -87,16 +137,35 @@ class Plugin { VersionData Version; size_t ModuleCount; PluginModule::ModuleDescriptor *ModuleDescriptions; + size_t ComponentCount = 0; + PluginComponent::ComponentDescriptor *ComponentDescriptions = nullptr; void (*AddOptions)(const PluginDescriptor *D, PO::ArgumentParser &Parser) noexcept; }; + // Const value of current plugin API version. static inline constexpr const uint32_t CurrentAPIVersion [[maybe_unused]] = kPluginCurrentAPIVersion; + + // Static function to load plugins from default paths. + WASMEDGE_EXPORT static void loadFromDefaultPaths() noexcept; + + // Static function to get default plugin paths. static std::vector<std::filesystem::path> getDefaultPluginPaths() noexcept; + + // Static function to load all plugins from given path. WASMEDGE_EXPORT static bool load(const std::filesystem::path &Path) noexcept; + + // Static function to register plugin with descriptor. + static bool registerPlugin(const PluginDescriptor *Desc) noexcept; + + // Static function to add plugin options from arguments. static void addPluginOptions(PO::ArgumentParser &Parser) noexcept; + + // Static function to find loaded plugin by name. WASMEDGE_EXPORT static const Plugin *find(std::string_view Name) noexcept; + + // Static function to list loaded plugins. static Span<const Plugin> plugins() noexcept; Plugin(const Plugin &) = delete; @@ -105,6 +174,7 @@ class Plugin { Plugin &operator=(Plugin &&) noexcept = default; Plugin() noexcept = default; + explicit Plugin(const PluginDescriptor *D) noexcept; constexpr const char *name() const noexcept { assuming(Desc); @@ -132,35 +202,38 @@ class Plugin { assuming(Desc); return ModuleRegistry; } + Span<const PluginComponent> components() const noexcept { + assuming(Desc); + return ComponentRegistry; + } WASMEDGE_EXPORT const PluginModule * findModule(std::string_view Name) const noexcept; + WASMEDGE_EXPORT const PluginComponent * + findComponent(std::string_view Name) const noexcept; + std::filesystem::path path() const noexcept { return Path; } private: - static std::vector<Plugin> &PluginRegistry; - static std::unordered_map<std::string_view, std::size_t> &PluginNameLookup; + static std::mutex Mutex; + static std::vector<Plugin> PluginRegistry; + static std::unordered_map<std::string_view, std::size_t> PluginNameLookup; + + // Static function to load plugin from file. Thread-safe. + static bool loadFile(const std::filesystem::path &Path) noexcept; + + // Static function to register built-in plugins. Thread-safe. + static void registerBuiltInPlugins() noexcept; + // Plugin contents. std::filesystem::path Path; const PluginDescriptor *Desc = nullptr; std::shared_ptr<Loader::SharedLibrary> Lib; std::vector<PluginModule> ModuleRegistry; + std::vector<PluginComponent> ComponentRegistry; std::unordered_map<std::string_view, std::size_t> ModuleNameLookup; - - static bool loadFile(const std::filesystem::path &Path) noexcept; - - explicit Plugin(const PluginDescriptor *D) noexcept; - -public: - WASMEDGE_EXPORT static void - registerPlugin(const PluginDescriptor *Desc) noexcept; -}; - -struct PluginRegister { - WASMEDGE_EXPORT PluginRegister(const Plugin::PluginDescriptor *Desc) noexcept; - - WASMEDGE_EXPORT ~PluginRegister() noexcept; + std::unordered_map<std::string_view, std::size_t> ComponentNameLookup; }; } // namespace Plugin diff --git a/include/plugin/wasi_logging/base.h b/include/plugin/wasi_logging/base.h new file mode 100644 index 000000000000..39a90fd57ce1 --- /dev/null +++ b/include/plugin/wasi_logging/base.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +// BUILTIN-PLUGIN: Temporary move the wasi-logging plugin sources here until +// the new plugin architecture ready in 0.15.0. + +#pragma once + +#include "env.h" + +#include "common/errcode.h" +#include "runtime/callingframe.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { +namespace WASILogging { + +enum class LogLevel : uint32_t { Trace, Debug, Info, Warn, Error, Critical }; + +template <typename T> class Func : public Runtime::HostFunction<T> { +public: + Func(LogEnv &HostEnv) : Runtime::HostFunction<T>(0), Env(HostEnv) {} + +protected: + LogEnv &Env; +}; + +} // namespace WASILogging +} // namespace Host +} // namespace WasmEdge diff --git a/include/plugin/wasi_logging/env.h b/include/plugin/wasi_logging/env.h new file mode 100644 index 000000000000..f33e8b664f45 --- /dev/null +++ b/include/plugin/wasi_logging/env.h @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +// BUILTIN-PLUGIN: Temporary move the wasi-logging plugin sources here until +// the new plugin architecture ready in 0.15.0. + +#pragma once + +#include "common/hexstr.h" +#include "common/spdlog.h" + +#include <spdlog/sinks/basic_file_sink.h> +#include <spdlog/sinks/stdout_color_sinks.h> +#include <spdlog/spdlog.h> + +#include <limits> +#include <memory> +#include <mutex> +#include <random> +#include <string> +#include <string_view> +#include <unordered_set> + +namespace WasmEdge { +namespace Host { +namespace WASILogging { + +class LogEnv { +public: + LogEnv() noexcept { + // Get the stdout and stderr logger. + StdoutLogger = spdlog::get("wasi_logging_stdout"); + if (!StdoutLogger) { + StdoutLogger = spdlog::stdout_color_mt("wasi_logging_stdout"); + StdoutLogger->set_level(spdlog::level::trace); + StdoutLogger->set_pattern(DefFormat); + } + StderrLogger = spdlog::get("wasi_logging_stderr"); + if (!StderrLogger) { + StderrLogger = spdlog::stderr_color_mt("wasi_logging_stderr"); + StderrLogger->set_level(spdlog::level::trace); + StderrLogger->set_pattern(DefFormat); + } + + std::random_device RandDev; + std::mt19937 RandGen(RandDev()); + std::uniform_int_distribution<uint64_t> RandDist( + 0, std::numeric_limits<uint64_t>::max()); + + std::unique_lock Lock(Mutex); + do { + InstanceID = RandDist(RandGen); + } while (RegisteredID.find(InstanceID) != RegisteredID.cend()); + LogRegName = "wasi_logging_file_" + convertUIntToHexStr(InstanceID); + RegisteredID.insert(InstanceID); + } + + ~LogEnv() noexcept { + std::unique_lock Lock(Mutex); + spdlog::drop(LogFileName); + RegisteredID.erase(InstanceID); + } + + std::string_view getLogFileName() const noexcept { return LogFileName; } + void setLogFileName(std::string_view Name) noexcept { + LogFileName = std::string(Name); + } + + const std::string &getLogRegName() const noexcept { return LogRegName; } + + uint64_t getInstanceID() const noexcept { return InstanceID; } + + static std::mutex Mutex; + static std::unordered_set<uint64_t> RegisteredID; + static const std::string DefFormat; + std::shared_ptr<spdlog::logger> StdoutLogger; + std::shared_ptr<spdlog::logger> StderrLogger; + std::shared_ptr<spdlog::logger> FileLogger; + +private: + std::string LogFileName; + std::string LogRegName; + uint64_t InstanceID; +}; + +} // namespace WASILogging +} // namespace Host +} // namespace WasmEdge diff --git a/include/plugin/wasi_logging/func.h b/include/plugin/wasi_logging/func.h new file mode 100644 index 000000000000..eecf92f8e29e --- /dev/null +++ b/include/plugin/wasi_logging/func.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +// BUILTIN-PLUGIN: Temporary move the wasi-logging plugin sources here until +// the new plugin architecture ready in 0.15.0. + +#pragma once + +#include "base.h" + +namespace WasmEdge { +namespace Host { +namespace WASILogging { + +class Log : public Func<Log> { +public: + Log(LogEnv &HostEnv) : Func(HostEnv) {} + Expect<void> body(const Runtime::CallingFrame &Frame, uint32_t Level, + uint32_t CxtPtr, uint32_t CxtLen, uint32_t MsgPtr, + uint32_t MsgLen); +}; + +} // namespace WASILogging +} // namespace Host +} // namespace WasmEdge diff --git a/include/plugin/wasi_logging/module.h b/include/plugin/wasi_logging/module.h new file mode 100644 index 000000000000..5a533e7571ae --- /dev/null +++ b/include/plugin/wasi_logging/module.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +// BUILTIN-PLUGIN: Temporary move the wasi-logging plugin sources here until +// the new plugin architecture ready in 0.15.0. + +#pragma once + +#include "env.h" + +#include "plugin/plugin.h" +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { + +class WasiLoggingModule : public Runtime::Instance::ModuleInstance { +public: + WasiLoggingModule(); + + WASILogging::LogEnv &getEnv() { return Env; } + + static Plugin::Plugin::PluginDescriptor PluginDescriptor; + static Plugin::PluginModule::ModuleDescriptor ModuleDescriptor[]; + +private: + WASILogging::LogEnv Env; +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/include/po/argument_parser.h b/include/po/argument_parser.h index 54d30925abe3..224e2eb01042 100644 --- a/include/po/argument_parser.h +++ b/include/po/argument_parser.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/po/argument_parser.h - Argument parser -------------------===// // @@ -140,8 +140,6 @@ class ArgumentParser { const ArgumentDescriptor &CurrentDesc = ArgumentDescriptors[Iter->second]; if (CurrentDesc.max_nargs() == 0) { return false; - CurrentDesc.default_value(); - return true; } CurrentDesc.raw_value(Value); diff --git a/include/po/error.h b/include/po/error.h index 474d24c665e4..7837d5550574 100644 --- a/include/po/error.h +++ b/include/po/error.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/po/parser.h - Argument error -----------------------------===// // diff --git a/include/po/helper.h b/include/po/helper.h index 7b7597d70542..5e59c312411a 100644 --- a/include/po/helper.h +++ b/include/po/helper.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/po/helper.h - Helper for Initialize Option ---------------===// // diff --git a/include/po/list.h b/include/po/list.h index 27d4ac006ecf..50b840a30c76 100644 --- a/include/po/list.h +++ b/include/po/list.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/po/list.h - Option list ----------------------------------===// // diff --git a/include/po/option.h b/include/po/option.h index 38564728e192..50b5b98de487 100644 --- a/include/po/option.h +++ b/include/po/option.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/po/option.h - Option -------------------------------------===// // diff --git a/include/po/parser.h b/include/po/parser.h index dab5d9351d05..b143510e184a 100644 --- a/include/po/parser.h +++ b/include/po/parser.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/po/parser.h - Single Argument parser ---------------------===// // @@ -20,7 +20,7 @@ namespace PO { inline void tolower(std::string &String) noexcept { std::transform( String.begin(), String.end(), String.begin(), - [](char c) noexcept { return static_cast<char>(std::tolower(c)); }); + [](char C) noexcept { return static_cast<char>(std::tolower(C)); }); } template <typename ConvResultT, typename ResultT = ConvResultT> diff --git a/include/po/subcommand.h b/include/po/subcommand.h index dc9a76c77359..d405c86b9371 100644 --- a/include/po/subcommand.h +++ b/include/po/subcommand.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/po/subcommand.h - SubCommand -----------------------------===// // diff --git a/include/runtime/callingframe.h b/include/runtime/callingframe.h index 04cb762a99b2..638ebd093a0f 100644 --- a/include/runtime/callingframe.h +++ b/include/runtime/callingframe.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/runtime/callingframe.h - Calling frame definition --------===// // diff --git a/include/runtime/hostfunc.h b/include/runtime/hostfunc.h index 783aa8e3013a..fd05b2dafe3b 100644 --- a/include/runtime/hostfunc.h +++ b/include/runtime/hostfunc.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/runtime/hostfunc.h - host function interface -------------===// // @@ -30,7 +30,8 @@ class CallingFrame; class HostFunctionBase { public: HostFunctionBase() = delete; - HostFunctionBase(const uint64_t FuncCost) : Cost(FuncCost) {} + HostFunctionBase(const uint64_t FuncCost) + : DefType(AST::FunctionType()), Cost(FuncCost) {} virtual ~HostFunctionBase() = default; /// Run host function body. @@ -39,13 +40,18 @@ class HostFunctionBase { Span<ValVariant> Rets) = 0; /// Getter of function type. - const AST::FunctionType &getFuncType() const { return FuncType; } + const AST::FunctionType &getFuncType() const noexcept { + return DefType.getCompositeType().getFuncType(); + } /// Getter of host function cost. uint64_t getCost() const { return Cost; } + /// Getter of defined type. + const AST::SubType &getDefinedType() const noexcept { return DefType; } + protected: - AST::FunctionType FuncType; + AST::SubType DefType; const uint64_t Cost; }; @@ -93,6 +99,7 @@ template <typename T> class HostFunction : public HostFunctionBase { } void initializeFuncType() { + auto &FuncType = DefType.getCompositeType().getFuncType(); using F = FuncTraits<decltype(&T::body)>; using ArgsT = typename F::ArgsT; FuncType.getParamTypes().reserve(F::ArgsN); @@ -145,6 +152,7 @@ template <typename T> class HostFunction : public HostFunctionBase { template <typename Tuple, std::size_t... Indices> void pushValType(std::index_sequence<Indices...>) { + auto &FuncType = DefType.getCompositeType().getFuncType(); (FuncType.getParamTypes().push_back( ValTypeFromType<std::tuple_element_t<Indices, Tuple>>()), ...); @@ -152,6 +160,7 @@ template <typename T> class HostFunction : public HostFunctionBase { template <typename Tuple, std::size_t... Indices> void pushRetType(std::index_sequence<Indices...>) { + auto &FuncType = DefType.getCompositeType().getFuncType(); (FuncType.getReturnTypes().push_back( ValTypeFromType<std::tuple_element_t<Indices, Tuple>>()), ...); diff --git a/include/runtime/instance/array.h b/include/runtime/instance/array.h new file mode 100644 index 000000000000..6087cae7ef6e --- /dev/null +++ b/include/runtime/instance/array.h @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +//===-- wasmedge/runtime/instance/array.h - Array Instance definition -----===// +// +// Part of the WasmEdge Project. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the array instance definition in store manager. +/// +//===----------------------------------------------------------------------===// +#pragma once + +#include "ast/type.h" +#include "common/span.h" +#include "common/types.h" +#include "runtime/instance/composite.h" + +#include <vector> + +namespace WasmEdge { +namespace Runtime { +namespace Instance { + +class ArrayInstance : public CompositeBase { +public: + ArrayInstance() = delete; + ArrayInstance(const ModuleInstance *Mod, const uint32_t Idx, + const uint32_t Size, const ValVariant &Init) noexcept + : CompositeBase(Mod, Idx), Data(Size, Init) { + assuming(ModInst); + } + ArrayInstance(const ModuleInstance *Mod, const uint32_t Idx, + std::vector<ValVariant> &&Init) noexcept + : CompositeBase(Mod, Idx), Data(std::move(Init)) { + assuming(ModInst); + } + + /// Get field data in array instance. + ValVariant &getData(uint32_t Idx) noexcept { return Data[Idx]; } + const ValVariant &getData(uint32_t Idx) const noexcept { return Data[Idx]; } + + /// Get full array. + Span<ValVariant> getArray() noexcept { return Data; } + Span<const ValVariant> getArray() const noexcept { return Data; } + + /// Get array length. + uint32_t getLength() const noexcept { + return static_cast<uint32_t>(Data.size()); + } + + /// Get boundary index. + uint32_t getBoundIdx() const noexcept { + return std::max(static_cast<uint32_t>(Data.size()), UINT32_C(1)) - + UINT32_C(1); + } + +private: + /// \name Data of array instance. + /// @{ + std::vector<ValVariant> Data; + /// @} +}; + +} // namespace Instance +} // namespace Runtime +} // namespace WasmEdge diff --git a/include/runtime/instance/component.h b/include/runtime/instance/component.h new file mode 100644 index 000000000000..3ec0f5a9076d --- /dev/null +++ b/include/runtime/instance/component.h @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +//===-- wasmedge/runtime/instance/component.h - Component Instance definition // +// +// Part of the WasmEdge Project. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the component instance definition. +/// +//===----------------------------------------------------------------------===// +#pragma once + +#include "ast/component/type.h" +#include "ast/module.h" +#include "ast/type.h" +#include "common/errcode.h" +#include "runtime/instance/module.h" + +#include <atomic> +#include <functional> +#include <map> +#include <memory> +#include <mutex> +#include <set> +#include <shared_mutex> +#include <string> +#include <type_traits> +#include <vector> + +namespace WasmEdge { + +namespace Runtime { + +namespace Instance { + +using namespace AST::Component; + +namespace { +void typeConvert(ValueType &VT, const ValType &ValTy) noexcept { + switch (ValTy.getCode()) { + case TypeCode::I32: + VT.emplace<PrimValType>(PrimValType::S32); + break; + + default: + break; + } +} + +void typeConvert(FuncType &FT, const AST::FunctionType &Ty) noexcept { + auto &PL = FT.getParamList(); + for (auto const &PT : Ty.getParamTypes()) { + LabelValType L{}; + typeConvert(L.getValType(), PT); + PL.emplace_back(L); + } + auto &RL = FT.getResultList(); + if (Ty.getReturnTypes().size() == 1) { + typeConvert(RL.emplace<ValueType>(), Ty.getReturnTypes()[0]); + } else { + auto &LL = RL.emplace<std::vector<LabelValType>>(); + for (auto const &RT : Ty.getReturnTypes()) { + LabelValType L{}; + typeConvert(L.getValType(), RT); + LL.emplace_back(L); + } + } +} +} // namespace + +class ComponentInstance { +public: + ComponentInstance(std::string_view Name) : CompName(Name) {} + + std::string_view getComponentName() const noexcept { return CompName; } + + void addModule(const AST::Module &M) noexcept { ModList.emplace_back(M); } + const AST::Module &getModule(uint32_t Index) const noexcept { + return ModList[Index]; + } + + void addComponent(const AST::Component::Component &C) noexcept { + CompList.emplace_back(C); + } + const AST::Component::Component &getComponent(uint32_t Index) const noexcept { + return CompList[Index]; + } + + void addModuleInstance(ModuleInstance *Inst) noexcept { + ModInstList.push_back(std::move(Inst)); + } + void addModuleInstance(std::unique_ptr<ModuleInstance> Inst) noexcept { + ModInstList.push_back(Inst.get()); + OwnedModInstList.push_back(std::move(Inst)); + } + const ModuleInstance *getModuleInstance(uint32_t Index) const noexcept { + return ModInstList[Index]; + } + + void addComponentInstance(const ComponentInstance *Inst) noexcept { + CompInstList.push_back(Inst); + } + void addComponentInstance(std::unique_ptr<ComponentInstance> Inst) noexcept { + CompInstList.push_back(Inst.get()); + OwnedCompInstList.push_back(std::move(Inst)); + } + const ComponentInstance *getComponentInstance(uint32_t Index) const noexcept { + return CompInstList[Index]; + } + + void addHostFunc(std::string_view Name, + std::unique_ptr<HostFunctionBase> &&Func) { + addType(Func->getFuncType()); + auto FuncInst = std::make_unique<FunctionInstance>( + this, static_cast<uint32_t>(Types.size()) - 1, std::move(Func)); + unsafeAddHostFunc(Name, std::move(FuncInst)); + } + void addHostFunc(std::string_view Name, + std::unique_ptr<FunctionInstance> &&Func) { + assuming(Func->isHostFunction()); + addType(Func->getFuncType()); + Func->linkDefinedType(this, static_cast<uint32_t>(Types.size()) - 1); + unsafeAddHostFunc(Name, std::move(Func)); + } + + void + addCoreFunctionInstance(std::unique_ptr<FunctionInstance> &&Inst) noexcept { + addCoreFunctionInstance(Inst.get()); + OwnedCoreFuncInstList.emplace_back(std::move(Inst)); + } + void addCoreFunctionInstance(FunctionInstance *Inst) noexcept { + CoreFuncInstList.push_back(Inst); + } + FunctionInstance *getCoreFunctionInstance(uint32_t Index) const noexcept { + return CoreFuncInstList[Index]; + } + + void addFunctionInstance(std::unique_ptr<FunctionInstance> Inst) noexcept { + addFunctionInstance(Inst.get()); + OwnedFuncInstList.emplace_back(std::move(Inst)); + } + void addFunctionInstance(FunctionInstance *Inst) noexcept { + FuncInstList.push_back(Inst); + } + FunctionInstance *getFunctionInstance(uint32_t Index) const noexcept { + return FuncInstList[Index]; + } + + void addExport(std::string_view Name, const ModuleInstance *Inst) { + ExportModuleMap.emplace(Name, Inst); + } + const ModuleInstance * + findModuleExports(std::string_view Name) const noexcept { + return ExportModuleMap.at(std::string(Name)); + } + void addExport(std::string_view Name, FunctionInstance *Inst) { + ExportFuncMap.emplace(Name, Inst); + } + FunctionInstance *findFuncExports(std::string_view Name) const noexcept { + return ExportFuncMap.at(std::string(Name)); + } + std::vector<std::pair<std::string, const AST::FunctionType &>> + getFuncExports() { + std::vector<std::pair<std::string, const AST::FunctionType &>> R; + for (auto &&[Name, Func] : ExportFuncMap) { + const auto &FuncType = Func->getFuncType(); + R.emplace_back(Name, FuncType); + } + return R; + } + + void addCoreTableInstance(TableInstance *Inst) noexcept { + CoreTabInstList.push_back(Inst); + } + TableInstance *getCoreTableInstance(uint32_t Index) const noexcept { + return CoreTabInstList[Index]; + } + void addCoreMemoryInstance(MemoryInstance *Inst) noexcept { + CoreMemInstList.push_back(Inst); + } + MemoryInstance *getCoreMemoryInstance(uint32_t Index) const noexcept { + return CoreMemInstList[Index]; + } + void addCoreGlobalInstance(GlobalInstance *Inst) noexcept { + CoreGlobInstList.push_back(Inst); + } + GlobalInstance *getCoreGlobalInstance(uint32_t Index) const noexcept { + return CoreGlobInstList[Index]; + } + + void addCoreType(const CoreDefType &Ty) noexcept { + CoreTypes.emplace_back(Ty); + } + const CoreDefType &getCoreType(uint32_t Idx) const noexcept { + return CoreTypes[Idx]; + } + + void addType(const AST::FunctionType &Ty) noexcept { + FuncType FT{}; + typeConvert(FT, Ty); + addType(FT); + } + void addType(const DefType &Ty) noexcept { Types.emplace_back(Ty); } + const DefType &getType(uint32_t Idx) const noexcept { return Types[Idx]; } + +private: + void unsafeAddHostFunc(std::string_view Name, + std::unique_ptr<FunctionInstance> Inst) noexcept { + addFunctionInstance(Inst.get()); + ExportFuncMap.insert_or_assign(std::string(Name), FuncInstList.back()); + OwnedFuncInstList.push_back(std::move(Inst)); + } + +private: + std::string CompName; + + std::vector<AST::Module> ModList; + std::vector<AST::Component::Component> CompList; + + std::vector<std::unique_ptr<ModuleInstance>> OwnedModInstList; + std::vector<const ModuleInstance *> ModInstList; + std::vector<std::unique_ptr<ComponentInstance>> OwnedCompInstList; + std::vector<const ComponentInstance *> CompInstList; + + // core function + // + // The owned core functions are created by lowering process + std::vector<std::unique_ptr<FunctionInstance>> OwnedCoreFuncInstList; + std::vector<FunctionInstance *> CoreFuncInstList; + + // component function + std::vector<std::unique_ptr<FunctionInstance>> OwnedFuncInstList; + std::vector<FunctionInstance *> FuncInstList; + std::map<std::string, FunctionInstance *, std::less<>> ExportFuncMap; + + std::map<std::string, const ModuleInstance *, std::less<>> ExportModuleMap; + + // core memory, this is prepared for canonical ABI + // + // when a function is lowering or lifting, it can have options + // 1. memory of a module instance + // 2. realloc of the same module instance + // these data will help a component function encode its high-level data to + // core module data, for example, `string` converted to `(i32, i32)`. Which is + // a pair of pointer and length, where pointer stored in the memory + // instance from option. + std::vector<TableInstance *> CoreTabInstList; + std::vector<MemoryInstance *> CoreMemInstList; + std::vector<GlobalInstance *> CoreGlobInstList; + + std::vector<AST::Component::CoreDefType> CoreTypes; + std::vector<AST::Component::DefType> Types; +}; + +} // namespace Instance +} // namespace Runtime +} // namespace WasmEdge diff --git a/include/runtime/instance/composite.h b/include/runtime/instance/composite.h new file mode 100644 index 000000000000..396636d56cad --- /dev/null +++ b/include/runtime/instance/composite.h @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +//===-- wasmedge/runtime/instance/composite.h - Composite base definition -===// +// +// Part of the WasmEdge Project. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the base class definition of composite instances +/// (function, struct, and array). +/// +//===----------------------------------------------------------------------===// +#pragma once + +#include "ast/type.h" +#include "common/types.h" + +#include <vector> + +namespace WasmEdge { +namespace Runtime { +namespace Instance { + +class ModuleInstance; +class ComponentInstance; + +class CompositeBase { +public: + /// Constructor for only host function instance case. + CompositeBase() noexcept : ModInst(nullptr), CompInst(nullptr), TypeIdx(0) {} + /// Constructor for function, array, and struct instances. + CompositeBase(const ModuleInstance *Mod, const uint32_t Idx) noexcept + : ModInst(Mod), TypeIdx(Idx) { + assuming(ModInst); + } + CompositeBase(const ComponentInstance *Comp, const uint32_t Idx) noexcept + : CompInst(Comp), TypeIdx(Idx) { + assuming(CompInst); + } + + /// Getter of module instance of this instance. + const ModuleInstance *getModule() const noexcept { return ModInst; } + const ComponentInstance *getComponent() const noexcept { return CompInst; } + + /// Getter of closed type index of this instance in the module. + uint32_t getTypeIndex() const noexcept { return TypeIdx; } + + /// Getter of value type in defined type form. + ValType getDefType() const noexcept { + if (ModInst || CompInst) { + return ValType(TypeCode::Ref, TypeIdx); + } else { + // nullptr `ModInst` and `CompInst` case is only for host function + // instance case. + return ValType(TypeCode::Ref, TypeCode::FuncRef); + } + } + +protected: + friend class ModuleInstance; + friend class ComponentInstance; + void linkDefinedType(const ModuleInstance *Mod, + const uint32_t Index) noexcept { + assuming(Mod); + ModInst = Mod; + TypeIdx = Index; + } + void linkDefinedType(const ComponentInstance *Comp, + const uint32_t Index) noexcept { + assuming(Comp); + CompInst = Comp; + TypeIdx = Index; + } + + /// \name Data of composite instances. + /// @{ + const ModuleInstance *ModInst; + const ComponentInstance *CompInst; + uint32_t TypeIdx; + /// @} +}; + +} // namespace Instance +} // namespace Runtime +} // namespace WasmEdge diff --git a/include/runtime/instance/data.h b/include/runtime/instance/data.h index 119d94b97052..70f3007b8b51 100644 --- a/include/runtime/instance/data.h +++ b/include/runtime/instance/data.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/runtime/instance/data.h - Data Instance definition -------===// // @@ -34,6 +34,20 @@ class DataInstance { /// Get data in data instance. Span<const Byte> getData() const noexcept { return Data; } + /// Load bytes to value. + ValVariant loadValue(uint32_t Offset, uint32_t N) const noexcept { + assuming(N <= 16); + // Check the data boundary. + if (unlikely(static_cast<uint64_t>(Offset) + static_cast<uint64_t>(N) > + Data.size())) { + return 0; + } + // Load the data to the value. + uint128_t Value; + std::memcpy(&Value, &Data[Offset], N); + return Value; + } + /// Clear data in data instance. void clear() { Data.clear(); } diff --git a/include/runtime/instance/elem.h b/include/runtime/instance/elem.h index c35676b4c8c2..7de6ec6232a8 100644 --- a/include/runtime/instance/elem.h +++ b/include/runtime/instance/elem.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/runtime/instance/elem.h - Element Instance definition ----===// // diff --git a/include/runtime/instance/function.h b/include/runtime/instance/function.h index 5730e91afe5f..782965f51b3b 100644 --- a/include/runtime/instance/function.h +++ b/include/runtime/instance/function.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/runtime/instance/function.h - Function Instance definition ==// // @@ -16,6 +16,7 @@ #include "ast/instruction.h" #include "common/symbol.h" #include "runtime/hostfunc.h" +#include "runtime/instance/composite.h" #include <memory> #include <numeric> @@ -28,30 +29,51 @@ namespace Instance { class ModuleInstance; -class FunctionInstance { +class FunctionInstance : public CompositeBase { public: using CompiledFunction = void; FunctionInstance() = delete; /// Move constructor. FunctionInstance(FunctionInstance &&Inst) noexcept - : ModInst(Inst.ModInst), FuncType(Inst.FuncType), - Data(std::move(Inst.Data)) {} + : CompositeBase(Inst.ModInst, Inst.TypeIdx), FuncType(Inst.FuncType), + Data(std::move(Inst.Data)) { + assuming(ModInst); + } /// Constructor for native function. - FunctionInstance(const ModuleInstance *Mod, const AST::FunctionType &Type, + FunctionInstance(const ModuleInstance *Mod, const uint32_t TIdx, + const AST::FunctionType &Type, Span<const std::pair<uint32_t, ValType>> Locs, AST::InstrView Expr) noexcept - : ModInst(Mod), FuncType(Type), - Data(std::in_place_type_t<WasmFunction>(), Locs, Expr) {} + : CompositeBase(Mod, TIdx), FuncType(Type), + Data(std::in_place_type_t<WasmFunction>(), Locs, Expr) { + assuming(ModInst); + } /// Constructor for compiled function. - FunctionInstance(const ModuleInstance *Mod, const AST::FunctionType &Type, + FunctionInstance(const ModuleInstance *Mod, const uint32_t TIdx, + const AST::FunctionType &Type, Symbol<CompiledFunction> S) noexcept - : ModInst(Mod), FuncType(Type), - Data(std::in_place_type_t<Symbol<CompiledFunction>>(), std::move(S)) {} - /// Constructor for host function. - FunctionInstance(const ModuleInstance *Mod, + : CompositeBase(Mod, TIdx), FuncType(Type), + Data(std::in_place_type_t<Symbol<CompiledFunction>>(), std::move(S)) { + assuming(ModInst); + } + /// Constructors for host function. + FunctionInstance(const ModuleInstance *Mod, const uint32_t TIdx, + std::unique_ptr<HostFunctionBase> &&Func) noexcept + : CompositeBase(Mod, TIdx), FuncType(Func->getFuncType()), + Data(std::in_place_type_t<std::unique_ptr<HostFunctionBase>>(), + std::move(Func)) { + assuming(ModInst); + } + FunctionInstance(const ComponentInstance *Comp, const uint32_t TIdx, std::unique_ptr<HostFunctionBase> &&Func) noexcept - : ModInst(Mod), FuncType(Func->getFuncType()), + : CompositeBase(Comp, TIdx), FuncType(Func->getFuncType()), + Data(std::in_place_type_t<std::unique_ptr<HostFunctionBase>>(), + std::move(Func)) { + assuming(CompInst); + } + FunctionInstance(std::unique_ptr<HostFunctionBase> &&Func) noexcept + : CompositeBase(), FuncType(Func->getFuncType()), Data(std::in_place_type_t<std::unique_ptr<HostFunctionBase>>(), std::move(Func)) {} @@ -70,9 +92,6 @@ class FunctionInstance { return std::holds_alternative<std::unique_ptr<HostFunctionBase>>(Data); } - /// Getter of module instance of this function instance. - const ModuleInstance *getModule() const noexcept { return ModInst; } - /// Getter of function type. const AST::FunctionType &getFuncType() const noexcept { return FuncType; } @@ -124,12 +143,9 @@ class FunctionInstance { } }; - friend class ModuleInstance; - void setModule(const ModuleInstance *Mod) noexcept { ModInst = Mod; } - /// \name Data of function instance. /// @{ - const ModuleInstance *ModInst; + const AST::FunctionType &FuncType; std::variant<WasmFunction, Symbol<CompiledFunction>, std::unique_ptr<HostFunctionBase>> diff --git a/include/runtime/instance/global.h b/include/runtime/instance/global.h index fcbf590ba97f..d5f0008adfa6 100644 --- a/include/runtime/instance/global.h +++ b/include/runtime/instance/global.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/runtime/instance/global.h - Global Instance definition ---===// // @@ -35,10 +35,11 @@ class GlobalInstance { /// Getter of value. const ValVariant &getValue() const noexcept { return Value; } - - /// Getter of value. ValVariant &getValue() noexcept { return Value; } + /// Setter of value. + void setValue(const ValVariant &Val) noexcept { Value = Val; } + private: /// \name Data of global instance. /// @{ diff --git a/include/runtime/instance/memory.h b/include/runtime/instance/memory.h index b6a414c3dc23..6f72441d0963 100644 --- a/include/runtime/instance/memory.h +++ b/include/runtime/instance/memory.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/runtime/instance/memory.h - Memory Instance definition ---===// // @@ -16,7 +16,7 @@ #include "ast/type.h" #include "common/errcode.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" #include "system/allocator.h" #include <algorithm> @@ -46,14 +46,14 @@ class MemoryInstance { uint32_t PageLim = UINT32_C(65536)) noexcept : MemType(MType), PageLimit(PageLim) { if (MemType.getLimit().getMin() > PageLimit) { - spdlog::error( - "Create memory instance failed -- exceeded limit page size: {}", - PageLimit); - return; + spdlog::error("Memory Instance: Limited {} page in configuration.", + PageLimit); + MemType.getLimit().setMin(PageLimit); } DataPtr = Allocator::allocate(MemType.getLimit().getMin()); if (DataPtr == nullptr) { - spdlog::error("Unable to find usable memory address"); + spdlog::error("Memory Instance: Unable to find usable memory address."); + MemType.getLimit().setMin(0U); return; } } @@ -105,7 +105,8 @@ class MemoryInstance { } assuming(PageLimit >= Min); if (Count > PageLimit - Min) { - spdlog::error("Memory grow page failed -- exceeded limit page size: {}", + spdlog::error("Memory Instance: Memory grow page failed, exceeded " + "limited {} page size in configuration.", PageLimit); return false; } diff --git a/include/runtime/instance/module.h b/include/runtime/instance/module.h index d9b3a1a440a8..8e8a5c7a43c2 100644 --- a/include/runtime/instance/module.h +++ b/include/runtime/instance/module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/runtime/instance/module.h - Module Instance definition ---===// // @@ -13,15 +13,20 @@ //===----------------------------------------------------------------------===// #pragma once +#include "ast/component/type.h" +#include "ast/module.h" #include "ast/type.h" #include "common/errcode.h" #include "runtime/hostfunc.h" +#include "runtime/instance/array.h" #include "runtime/instance/data.h" #include "runtime/instance/elem.h" #include "runtime/instance/function.h" #include "runtime/instance/global.h" #include "runtime/instance/memory.h" +#include "runtime/instance/struct.h" #include "runtime/instance/table.h" +#include "runtime/instance/tag.h" #include <atomic> #include <functional> @@ -54,7 +59,8 @@ inline constexpr const bool IsEntityV = std::is_same_v<T, Instance::FunctionInstance> || std::is_same_v<T, Instance::TableInstance> || std::is_same_v<T, Instance::MemoryInstance> || - std::is_same_v<T, Instance::GlobalInstance>; + std::is_same_v<T, Instance::GlobalInstance> || + std::is_same_v<T, Instance::TagInstance>; /// Return true if T is an instance. template <typename T> @@ -63,6 +69,8 @@ inline constexpr const bool IsInstanceV = std::is_same_v<T, Instance::DataInstance>; } // namespace +class ComponentInstance; + class ModuleInstance { public: ModuleInstance(std::string_view Name, void *Data = nullptr, @@ -91,31 +99,36 @@ class ModuleInstance { void addHostFunc(std::string_view Name, std::unique_ptr<HostFunctionBase> &&Func) { std::unique_lock Lock(Mutex); - unsafeAddHostInstance(Name, OwnedFuncInsts, FuncInsts, ExpFuncs, - std::make_unique<Runtime::Instance::FunctionInstance>( - this, std::move(Func))); + unsafeImportDefinedType(Func->getDefinedType()); + unsafeAddHostInstance( + Name, OwnedFuncInsts, FuncInsts, ExpFuncs, + std::make_unique<FunctionInstance>( + this, static_cast<uint32_t>(Types.size()) - 1, std::move(Func))); } void addHostFunc(std::string_view Name, - std::unique_ptr<Instance::FunctionInstance> &&Func) { + std::unique_ptr<FunctionInstance> &&Func) { std::unique_lock Lock(Mutex); - Func->setModule(this); + assuming(Func->isHostFunction()); + unsafeImportDefinedType(Func->getHostFunc().getDefinedType()); + Func->linkDefinedType(this, static_cast<uint32_t>(Types.size()) - 1); unsafeAddHostInstance(Name, OwnedFuncInsts, FuncInsts, ExpFuncs, std::move(Func)); } + void addHostTable(std::string_view Name, - std::unique_ptr<Instance::TableInstance> &&Tab) { + std::unique_ptr<TableInstance> &&Tab) { std::unique_lock Lock(Mutex); unsafeAddHostInstance(Name, OwnedTabInsts, TabInsts, ExpTables, std::move(Tab)); } void addHostMemory(std::string_view Name, - std::unique_ptr<Instance::MemoryInstance> &&Mem) { + std::unique_ptr<MemoryInstance> &&Mem) { std::unique_lock Lock(Mutex); unsafeAddHostInstance(Name, OwnedMemInsts, MemInsts, ExpMems, std::move(Mem)); } void addHostGlobal(std::string_view Name, - std::unique_ptr<Instance::GlobalInstance> &&Glob) { + std::unique_ptr<GlobalInstance> &&Glob) { std::unique_lock Lock(Mutex); unsafeAddHostInstance(Name, OwnedGlobInsts, GlobInsts, ExpGlobals, std::move(Glob)); @@ -134,6 +147,10 @@ class ModuleInstance { std::shared_lock Lock(Mutex); return unsafeFindExports(ExpMems, ExtName); } + TagInstance *findTagExports(std::string_view ExtName) const noexcept { + std::shared_lock Lock(Mutex); + return unsafeFindExports(ExpTags, ExtName); + } GlobalInstance *findGlobalExports(std::string_view ExtName) const noexcept { std::shared_lock Lock(Mutex); return unsafeFindExports(ExpGlobals, ExtName); @@ -152,6 +169,10 @@ class ModuleInstance { std::shared_lock Lock(Mutex); return static_cast<uint32_t>(ExpMems.size()); } + uint32_t getTagExportNum() const noexcept { + std::shared_lock Lock(Mutex); + return static_cast<uint32_t>(ExpTags.size()); + } uint32_t getGlobalExportNum() const noexcept { std::shared_lock Lock(Mutex); return static_cast<uint32_t>(ExpGlobals.size()); @@ -174,19 +195,68 @@ class ModuleInstance { return std::forward<CallbackT>(CallBack)(ExpMems); } template <typename CallbackT> + auto getTagExports(CallbackT &&CallBack) const noexcept { + std::shared_lock Lock(Mutex); + return std::forward<CallbackT>(CallBack)(ExpTags); + } + template <typename CallbackT> auto getGlobalExports(CallbackT &&CallBack) const noexcept { std::shared_lock Lock(Mutex); return std::forward<CallbackT>(CallBack)(ExpGlobals); } + /// Component model concepts + /// + /// Export functions with name, these functions are suppose not owned by this + /// module, because the module is just a wrapper for component functions. + /// + /// See the example below, with statement below shows why we need this kind of + /// exporting + /// + /// (component + /// (core module $A + /// (func (export "one") (result i32) (i32.const 1)) + /// ) + /// (core module $B + /// (func (import "a" "one") (result i32)) + /// ) + /// (core instance $a (instantiate $A)) + /// (core instance $b (instantiate $B (with "a" (instance $a)))) + /// ) + void exportFunction(std::string_view Name, FunctionInstance *Func) { + std::unique_lock Lock(Mutex); + assuming(Func->isHostFunction()); + unsafeImportDefinedType(Func->getHostFunc().getDefinedType()); + Func->linkDefinedType(this, static_cast<uint32_t>(Types.size()) - 1); + FuncInsts.push_back(Func); + ExpFuncs.insert_or_assign(std::string(Name), FuncInsts.back()); + } + void exportTable(std::string_view Name, TableInstance *Tab) { + std::unique_lock Lock(Mutex); + TabInsts.push_back(Tab); + ExpTables.insert_or_assign(std::string(Name), TabInsts.back()); + } + void exportMemory(std::string_view Name, MemoryInstance *Mem) { + std::unique_lock Lock(Mutex); + MemInsts.push_back(Mem); + ExpMems.insert_or_assign(std::string(Name), MemInsts.back()); + } + void exportGlobal(std::string_view Name, GlobalInstance *Glob) { + std::unique_lock Lock(Mutex); + GlobInsts.push_back(Glob); + ExpGlobals.insert_or_assign(std::string(Name), GlobInsts.back()); + } + protected: friend class Executor::Executor; + friend class ComponentInstance; friend class Runtime::CallingFrame; - /// Copy the function types in type section to this module instance. - void addFuncType(const AST::FunctionType &FuncType) { + /// Create and copy the defined type to this module instance. + void addDefinedType(const AST::SubType &SType) { std::unique_lock Lock(Mutex); - FuncTypes.emplace_back(FuncType); + OwnedTypes.push_back(std::make_unique<AST::SubType>(SType)); + Types.push_back(OwnedTypes.back().get()); } /// Create and add instances into this module instance. @@ -203,6 +273,10 @@ class ModuleInstance { std::unique_lock Lock(Mutex); unsafeAddInstance(OwnedMemInsts, MemInsts, std::forward<Args>(Values)...); } + template <typename... Args> void addTag(Args &&...Values) { + std::unique_lock Lock(Mutex); + unsafeAddInstance(OwnedTagInsts, TagInsts, std::forward<Args>(Values)...); + } template <typename... Args> void addGlobal(Args &&...Values) { std::unique_lock Lock(Mutex); unsafeAddInstance(OwnedGlobInsts, GlobInsts, std::forward<Args>(Values)...); @@ -215,6 +289,18 @@ class ModuleInstance { std::unique_lock Lock(Mutex); unsafeAddInstance(OwnedDataInsts, DataInsts, std::forward<Args>(Values)...); } + template <typename... Args> ArrayInstance *newArray(Args &&...Values) { + std::unique_lock Lock(Mutex); + OwnedArrayInsts.push_back( + std::make_unique<ArrayInstance>(this, std::forward<Args>(Values)...)); + return OwnedArrayInsts.back().get(); + } + template <typename... Args> StructInstance *newStruct(Args &&...Values) { + std::unique_lock Lock(Mutex); + OwnedStructInsts.push_back( + std::make_unique<StructInstance>(this, std::forward<Args>(Values)...)); + return OwnedStructInsts.back().get(); + } /// Import instances into this module instance. void importFunction(FunctionInstance *Func) { @@ -229,6 +315,10 @@ class ModuleInstance { std::unique_lock Lock(Mutex); unsafeImportInstance(MemInsts, Mem); } + void importTag(TagInstance *Tg) { + std::unique_lock Lock(Mutex); + unsafeImportInstance(TagInsts, Tg); + } void importGlobal(GlobalInstance *Glob) { std::unique_lock Lock(Mutex); ImpGlobalNum++; @@ -252,18 +342,26 @@ class ModuleInstance { std::unique_lock Lock(Mutex); ExpGlobals.insert_or_assign(std::string(Name), GlobInsts[Idx]); } + void exportTag(std::string_view Name, uint32_t Idx) { + std::unique_lock Lock(Mutex); + ExpTags.insert_or_assign(std::string(Name), TagInsts[Idx]); + } + + /// Get defined type list. + Span<const AST::SubType *const> getTypeList() const noexcept { return Types; } - /// Get function type by index. - Expect<const AST::FunctionType *> getFuncType(uint32_t Idx) const noexcept { + /// Get instance pointer by index. + Expect<const AST::SubType *> getType(uint32_t Idx) const noexcept { std::shared_lock Lock(Mutex); - if (unlikely(Idx >= FuncTypes.size())) { + if (unlikely(Idx >= Types.size())) { // Error logging need to be handled in caller. return Unexpect(ErrCode::Value::WrongInstanceIndex); } - return &FuncTypes[Idx]; + return unsafeGetType(Idx); + } + const AST::SubType *unsafeGetType(uint32_t Idx) const noexcept { + return Types[Idx]; } - - /// Get instance pointer by index. Expect<FunctionInstance *> getFunc(uint32_t Idx) const noexcept { std::shared_lock Lock(Mutex); if (Idx >= FuncInsts.size()) { @@ -297,6 +395,9 @@ class ModuleInstance { MemoryInstance *unsafeGetMemory(uint32_t Idx) const noexcept { return MemInsts[Idx]; } + TagInstance *unsafeGetTag(uint32_t Idx) const noexcept { + return TagInsts[Idx]; + } Expect<GlobalInstance *> getGlobal(uint32_t Idx) const noexcept { std::shared_lock Lock(Mutex); if (Idx >= GlobInsts.size()) { @@ -360,13 +461,20 @@ class ModuleInstance { return StartFunc; } - /// Add the instances under the module by pointers. + /// Unsafe import instance into this module. template <typename T> std::enable_if_t<IsEntityV<T>, void> unsafeImportInstance(std::vector<T *> &Vec, T *Ptr) { Vec.push_back(Ptr); } + /// Unsafe import defined type from host function into this module. + void unsafeImportDefinedType(const AST::SubType &SType) { + Types.push_back(&SType); + const_cast<AST::SubType *>(Types.back()) + ->setTypeIndex(static_cast<uint32_t>(Types.size()) - 1); + } + /// Unsafe create and add the instance into this module. template <typename T, typename... Args> std::enable_if_t<IsInstanceV<T>, void> @@ -429,21 +537,26 @@ class ModuleInstance { /// Module name. const std::string ModName; - /// Function types. - std::vector<AST::FunctionType> FuncTypes; + /// Defined types. + std::vector<const AST::SubType *> Types; + std::vector<std::unique_ptr<const AST::SubType>> OwnedTypes; /// Owned instances in this module. - std::vector<std::unique_ptr<Instance::FunctionInstance>> OwnedFuncInsts; - std::vector<std::unique_ptr<Instance::TableInstance>> OwnedTabInsts; - std::vector<std::unique_ptr<Instance::MemoryInstance>> OwnedMemInsts; - std::vector<std::unique_ptr<Instance::GlobalInstance>> OwnedGlobInsts; - std::vector<std::unique_ptr<Instance::ElementInstance>> OwnedElemInsts; - std::vector<std::unique_ptr<Instance::DataInstance>> OwnedDataInsts; + std::vector<std::unique_ptr<FunctionInstance>> OwnedFuncInsts; + std::vector<std::unique_ptr<TableInstance>> OwnedTabInsts; + std::vector<std::unique_ptr<MemoryInstance>> OwnedMemInsts; + std::vector<std::unique_ptr<TagInstance>> OwnedTagInsts; + std::vector<std::unique_ptr<GlobalInstance>> OwnedGlobInsts; + std::vector<std::unique_ptr<ElementInstance>> OwnedElemInsts; + std::vector<std::unique_ptr<DataInstance>> OwnedDataInsts; + std::vector<std::unique_ptr<ArrayInstance>> OwnedArrayInsts; + std::vector<std::unique_ptr<StructInstance>> OwnedStructInsts; /// Imported and added instances in this module. std::vector<FunctionInstance *> FuncInsts; std::vector<TableInstance *> TabInsts; std::vector<MemoryInstance *> MemInsts; + std::vector<TagInstance *> TagInsts; std::vector<GlobalInstance *> GlobInsts; std::vector<ElementInstance *> ElemInsts; std::vector<DataInstance *> DataInsts; @@ -455,6 +568,7 @@ class ModuleInstance { std::map<std::string, FunctionInstance *, std::less<>> ExpFuncs; std::map<std::string, TableInstance *, std::less<>> ExpTables; std::map<std::string, MemoryInstance *, std::less<>> ExpMems; + std::map<std::string, TagInstance *, std::less<>> ExpTags; std::map<std::string, GlobalInstance *, std::less<>> ExpGlobals; /// Start function instance. diff --git a/include/runtime/instance/struct.h b/include/runtime/instance/struct.h new file mode 100644 index 000000000000..d65b701b7060 --- /dev/null +++ b/include/runtime/instance/struct.h @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +//===-- wasmedge/runtime/instance/struct.h - Struct Instance definition ---===// +// +// Part of the WasmEdge Project. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the struct instance definition in store manager. +/// +//===----------------------------------------------------------------------===// +#pragma once + +#include "ast/type.h" +#include "common/span.h" +#include "common/types.h" +#include "runtime/instance/composite.h" + +#include <vector> + +namespace WasmEdge { +namespace Runtime { +namespace Instance { + +class StructInstance : public CompositeBase { +public: + StructInstance() = delete; + StructInstance(const ModuleInstance *Mod, const uint32_t Idx, + std::vector<ValVariant> &&Init) noexcept + : CompositeBase(Mod, Idx), Data(std::move(Init)) { + assuming(ModInst); + } + + /// Get field data in struct instance. + ValVariant &getField(uint32_t Idx) noexcept { return Data[Idx]; } + const ValVariant &getField(uint32_t Idx) const noexcept { return Data[Idx]; } + +private: + /// \name Data of struct instance. + /// @{ + std::vector<ValVariant> Data; + /// @} +}; + +} // namespace Instance +} // namespace Runtime +} // namespace WasmEdge diff --git a/include/runtime/instance/table.h b/include/runtime/instance/table.h index e2fc29630fa6..b3dae05a47eb 100644 --- a/include/runtime/instance/table.h +++ b/include/runtime/instance/table.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/runtime/instance/table.h - Table Instance definition -----===// // @@ -17,7 +17,7 @@ #include "ast/type.h" #include "common/errcode.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" #include <algorithm> #include <cstdint> diff --git a/include/runtime/instance/tag.h b/include/runtime/instance/tag.h new file mode 100644 index 000000000000..e8b3fc55d88f --- /dev/null +++ b/include/runtime/instance/tag.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +//===-- wasmedge/runtime/instance/tag.h - Tag Instance definition ---===// +// +// Part of the WasmEdge Project. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the tag instance definition in store manager. +/// +//===----------------------------------------------------------------------===// +#pragma once + +#include "ast/type.h" + +namespace WasmEdge { +namespace Runtime { +namespace Instance { + +class TagInstance { +public: + TagInstance() = delete; + TagInstance(const AST::TagType &T, const AST::SubType *F) noexcept + : TgType(T.getTypeIdx(), F) {} + + /// Getter of tag type. + const AST::TagType &getTagType() const noexcept { return TgType; } + +private: + /// \name Data of tag instance. + /// @{ + AST::TagType TgType; + /// @} +}; + +} // namespace Instance +} // namespace Runtime +} // namespace WasmEdge diff --git a/include/runtime/stackmgr.h b/include/runtime/stackmgr.h index 1d28b1e91233..dc246d7f6c3d 100644 --- a/include/runtime/stackmgr.h +++ b/include/runtime/stackmgr.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/runtime/stackmgr.h - Stack Manager definition ------------===// // @@ -16,6 +16,7 @@ #include "ast/instruction.h" #include "runtime/instance/module.h" +#include <optional> #include <vector> namespace WasmEdge { @@ -23,6 +24,17 @@ namespace Runtime { class StackManager { public: + using Value = ValVariant; + + struct Handler { + Handler(AST::InstrView::iterator TryIt, uint32_t V, + Span<const AST::Instruction::CatchDescriptor> C) + : Try(TryIt), VPos(V), CatchClause(C) {} + AST::InstrView::iterator Try; + uint32_t VPos; + Span<const AST::Instruction::CatchDescriptor> CatchClause; + }; + struct Frame { Frame() = delete; Frame(const Instance::ModuleInstance *Mod, AST::InstrView::iterator FromIt, @@ -33,10 +45,9 @@ class StackManager { uint32_t Locals; uint32_t Arity; uint32_t VPos; + std::vector<Handler> HandlerStack; }; - using Value = ValVariant; - /// Stack manager provides the stack control for Wasm execution with VALIDATED /// modules. All operations of instructions passed validation, therefore no /// unexpect operations will occur. @@ -49,16 +60,16 @@ class StackManager { /// Getter of stack size. size_t size() const noexcept { return ValueStack.size(); } - /// Unsafe Getter of top entry of stack. + /// Unsafe getter of top entry of stack. Value &getTop() { return ValueStack.back(); } - /// Unsafe Getter of top N-th value entry of stack. + /// Unsafe getter of top N-th value entry of stack. Value &getTopN(uint32_t Offset) noexcept { assuming(0 < Offset && Offset <= ValueStack.size()); return ValueStack[ValueStack.size() - Offset]; } - /// Unsafe Getter of top N value entries of stack. + /// Unsafe getter of top N value entries of stack. Span<Value> getTopSpan(uint32_t N) { return Span<Value>(ValueStack.end() - N, N); } @@ -68,18 +79,32 @@ class StackManager { ValueStack.push_back(std::forward<T>(Val)); } - /// Unsafe Pop and return the top entry. + /// Push a vector of value to stack + void pushValVec(const std::vector<Value> &ValVec) { + ValueStack.insert(ValueStack.end(), ValVec.begin(), ValVec.end()); + } + + /// Unsafe pop and return the top entry. Value pop() { Value V = std::move(ValueStack.back()); ValueStack.pop_back(); return V; } + /// Unsafe pop and return the top N entries. + std::vector<Value> pop(uint32_t N) { + std::vector<Value> Vec; + Vec.reserve(N); + std::move(ValueStack.end() - N, ValueStack.end(), std::back_inserter(Vec)); + ValueStack.erase(ValueStack.end() - N, ValueStack.end()); + return Vec; + } + /// Push a new frame entry to stack. void pushFrame(const Instance::ModuleInstance *Module, AST::InstrView::iterator From, uint32_t LocalNum = 0, uint32_t Arity = 0, bool IsTailCall = false) noexcept { - if (likely(!IsTailCall)) { + if (!IsTailCall) { FrameStack.emplace_back(Module, From, LocalNum, Arity, static_cast<uint32_t>(ValueStack.size())); } else { @@ -94,6 +119,7 @@ class StackManager { FrameStack.back().Locals = LocalNum; FrameStack.back().Arity = Arity; FrameStack.back().VPos = static_cast<uint32_t>(ValueStack.size()); + FrameStack.back().HandlerStack.clear(); } } @@ -111,19 +137,66 @@ class StackManager { return From; } - /// Unsafe erase stack. - void stackErase(uint32_t EraseBegin, uint32_t EraseEnd) noexcept { + /// Push handler for try-catch block. + void + pushHandler(AST::InstrView::iterator TryIt, uint32_t BlockParamNum, + Span<const AST::Instruction::CatchDescriptor> Catch) noexcept { + assuming(!FrameStack.empty()); + FrameStack.back().HandlerStack.emplace_back( + TryIt, static_cast<uint32_t>(ValueStack.size()) - BlockParamNum, Catch); + } + + /// Pop the top handler on the stack. + std::optional<Handler> popTopHandler(uint32_t AssocValSize) noexcept { + while (!FrameStack.empty()) { + auto &Frame = FrameStack.back(); + if (!Frame.HandlerStack.empty()) { + auto TopHandler = std::move(Frame.HandlerStack.back()); + Frame.HandlerStack.pop_back(); + assuming(TopHandler.VPos <= ValueStack.size() - AssocValSize); + ValueStack.erase(ValueStack.begin() + TopHandler.VPos, + ValueStack.end() - AssocValSize); + return TopHandler; + } + FrameStack.pop_back(); + } + return std::nullopt; + } + + /// Unsafe remove inactive handler. + void removeInactiveHandler(AST::InstrView::iterator PC) noexcept { + assuming(!FrameStack.empty()); + // First pop the inactive handlers. Br instructions may cause the handlers + // in current frame becomes inactive. + auto &HandlerStack = FrameStack.back().HandlerStack; + while (!HandlerStack.empty()) { + auto &Handler = HandlerStack.back(); + if (PC < Handler.Try || + PC > Handler.Try + Handler.Try->getTryCatch().JumpEnd) { + HandlerStack.pop_back(); + } else { + break; + } + } + } + + /// Unsafe erase value stack. + void eraseValueStack(uint32_t EraseBegin, uint32_t EraseEnd) noexcept { assuming(EraseEnd <= EraseBegin && EraseBegin <= ValueStack.size()); ValueStack.erase(ValueStack.end() - EraseBegin, ValueStack.end() - EraseEnd); } /// Unsafe leave top label. - AST::InstrView::iterator maybePopFrame(AST::InstrView::iterator PC) noexcept { - if (FrameStack.size() > 1 && PC->isLast()) { + AST::InstrView::iterator + maybePopFrameOrHandler(AST::InstrView::iterator PC) noexcept { + if (FrameStack.size() > 1 && PC->isExprLast()) { // Noted that there's always a base frame in stack. return popFrame(); } + if (PC->isTryBlockLast()) { + FrameStack.back().HandlerStack.pop_back(); + } return PC; } diff --git a/include/runtime/storemgr.h b/include/runtime/storemgr.h index 2a281165b040..55af898b9a10 100644 --- a/include/runtime/storemgr.h +++ b/include/runtime/storemgr.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/runtime/storemgr.h - Store Manager definition ------------===// // @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #pragma once +#include "runtime/instance/component.h" #include "runtime/instance/module.h" #include <mutex> @@ -51,8 +52,19 @@ class StoreManager { /// Find module by name. const Instance::ModuleInstance *findModule(std::string_view Name) const { std::shared_lock Lock(Mutex); - auto Iter = NamedMod.find(Name); - if (likely(Iter != NamedMod.cend())) { + if (auto Iter = SoftNamedMod.find(Name); + likely(Iter != SoftNamedMod.cend())) { + return Iter->second; + } + if (auto Iter = NamedMod.find(Name); likely(Iter != NamedMod.cend())) { + return Iter->second; + } + return nullptr; + } + const Instance::ComponentInstance * + findComponent(std::string_view Name) const { + std::shared_lock Lock(Mutex); + if (auto Iter = NamedComp.find(Name); likely(Iter != NamedComp.cend())) { return Iter->second; } return nullptr; @@ -67,12 +79,6 @@ class StoreManager { NamedMod.clear(); } -private: - /// \name Mutex for thread-safe. - mutable std::shared_mutex Mutex; - - friend class Executor::Executor; - /// Register named module into this store. Expect<void> registerModule(const Instance::ModuleInstance *ModInst) { std::unique_lock Lock(Mutex); @@ -92,6 +98,32 @@ class StoreManager { return {}; } + void addNamedModule(std::string_view Name, + const Instance::ModuleInstance *Inst) { + std::unique_lock Lock(Mutex); + SoftNamedMod.emplace(Name, Inst); + } + + Expect<void> registerComponent(std::string_view Name, + const Instance::ComponentInstance *Inst) { + std::unique_lock Lock(Mutex); + auto Iter = NamedComp.find(Name); + if (likely(Iter != NamedComp.cend())) { + return Unexpect(ErrCode::Value::ModuleNameConflict); + } + NamedComp.emplace(Name, Inst); + return {}; + } + Expect<void> registerComponent(const Instance::ComponentInstance *Inst) { + return registerComponent(Inst->getComponentName(), Inst); + } + +private: + /// \name Mutex for thread-safe. + mutable std::shared_mutex Mutex; + + friend class Executor::Executor; + /// Collect the instantiation failed module. void recycleModule(std::unique_ptr<Instance::ModuleInstance> &&Mod) { FailedMod = std::move(Mod); @@ -99,6 +131,11 @@ class StoreManager { /// \name Module name mapping. std::map<std::string, const Instance::ModuleInstance *, std::less<>> NamedMod; + /// \name Soft module are those temporary added by component linking process + std::map<std::string, const Instance::ModuleInstance *, std::less<>> + SoftNamedMod; + std::map<std::string, const Instance::ComponentInstance *, std::less<>> + NamedComp; /// \name Last instantiation failed module. /// According to the current spec, the instances should be able to be diff --git a/include/system/allocator.h b/include/system/allocator.h index d49483c03619..395cd9e7f772 100644 --- a/include/system/allocator.h +++ b/include/system/allocator.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/system/allocator.h - large memory allocator --------------===// // diff --git a/include/system/fault.h b/include/system/fault.h index 6b92bec08dac..864c0fe40fb8 100644 --- a/include/system/fault.h +++ b/include/system/fault.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/system/fault.h - Memory and arithmetic exception ---------===// // @@ -15,7 +15,6 @@ #pragma once #include "common/errcode.h" - #include <csetjmp> namespace WasmEdge { diff --git a/include/system/mmap.h b/include/system/mmap.h index 55b78a9fa3aa..05f7d63f9629 100644 --- a/include/system/mmap.h +++ b/include/system/mmap.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/system/mmap.h - Memory mapped file -----------------------===// // diff --git a/include/system/path.h b/include/system/path.h index 300396dac66d..4299e017ef93 100644 --- a/include/system/path.h +++ b/include/system/path.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/system/path.h - Get system directory path ----------------===// // diff --git a/include/system/winapi.h b/include/system/winapi.h index ee60c6355493..b904dcc2a424 100644 --- a/include/system/winapi.h +++ b/include/system/winapi.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/system/winapi.h - Wrapper for Windows API-----------------===// // @@ -247,6 +247,14 @@ using CREATEFILE2_EXTENDED_PARAMETERS_ = using LPCREATEFILE2_EXTENDED_PARAMETERS_ = CREATEFILE2_EXTENDED_PARAMETERS_ *; #endif +#if WINAPI_PARTITION_DESKTOP || NTDDI_VERSION >= NTDDI_WIN10 +using LPPROGRESS_ROUTINE_ = DWORD_(WASMEDGE_WINAPI_WINAPI_CC *)( + LARGE_INTEGER_ TotalFileSize, LARGE_INTEGER_ TotalBytesTransferred, + LARGE_INTEGER_ StreamSize, LARGE_INTEGER_ StreamBytesTransferred, + DWORD_ dwStreamNumber, DWORD_ dwCallbackReason, HANDLE_ hSourceFile, + HANDLE_ hDestinationFile, LPVOID_ lpData); +#endif + using FILETIME_ = struct _FILETIME { DWORD_ dwLowDateTime; DWORD_ dwHighDateTime; @@ -382,6 +390,33 @@ using LPOVERLAPPED_COMPLETION_ROUTINE_ = VOID_(WASMEDGE_WINAPI_WINAPI_CC *)( DWORD_ dwErrorCode, DWORD_ dwNumberOfBytesTransfered, LPOVERLAPPED_ lpOverlapped) noexcept; +using REPARSE_DATA_BUFFER_ = struct _REPARSE_DATA_BUFFER { + ULONG_ ReparseTag; + USHORT_ ReparseDataLength; + USHORT_ Reserved; + WASMEDGE_WINAPI_DETAIL_EXTENSION union { + WASMEDGE_WINAPI_DETAIL_EXTENSION struct { + USHORT_ SubstituteNameOffset; + USHORT_ SubstituteNameLength; + USHORT_ PrintNameOffset; + USHORT_ PrintNameLength; + ULONG_ Flags; + WCHAR_ PathBuffer[1]; + } SymbolicLinkReparseBuffer; + WASMEDGE_WINAPI_DETAIL_EXTENSION struct { + USHORT_ SubstituteNameOffset; + USHORT_ SubstituteNameLength; + USHORT_ PrintNameOffset; + USHORT_ PrintNameLength; + WCHAR_ PathBuffer[1]; + } MountPointReparseBuffer; + WASMEDGE_WINAPI_DETAIL_EXTENSION struct { + UCHAR_ DataBuffer[1]; + } GenericReparseBuffer; + }; +}; +using PREPARSE_DATA_BUFFER = REPARSE_DATA_BUFFER_ *; + #if WINAPI_PARTITION_DESKTOP using IO_STATUS_BLOCK_ = struct _IO_STATUS_BLOCK { union { @@ -512,8 +547,12 @@ static inline constexpr const DWORD_ ERROR_HANDLE_EOF_ = 38; static inline constexpr const DWORD_ ERROR_FILE_EXISTS_ = 80; static inline constexpr const DWORD_ ERROR_INVALID_PARAMETER_ = 87; static inline constexpr const DWORD_ ERROR_INSUFFICIENT_BUFFER_ = 122; +static inline constexpr const DWORD_ ERROR_INVALID_NAME_ = 123; +static inline constexpr const DWORD_ ERROR_NEGATIVE_SEEK_ = 131; +static inline constexpr const DWORD_ ERROR_DIR_NOT_EMPTY_ = 145; static inline constexpr const DWORD_ ERROR_ALREADY_EXISTS_ = 183; static inline constexpr const DWORD_ ERROR_PIPE_BUSY_ = 231; +static inline constexpr const DWORD_ ERROR_DIRECTORY_ = 267; static inline constexpr const DWORD_ ERROR_IO_PENDING_ = 997; static inline constexpr const DWORD_ ERROR_INVALID_FLAGS_ = 1004; static inline constexpr const DWORD_ ERROR_NO_UNICODE_TRANSLATION_ = 1113; @@ -523,6 +562,14 @@ static inline constexpr const DWORD_ ERROR_PRIVILEGE_NOT_HELD_ = 1314; static inline const HANDLE_ INVALID_HANDLE_VALUE_ = reinterpret_cast<HANDLE_>(-1); +static inline constexpr const DWORD_ INFINITE_ = + static_cast<DWORD_>(0xffffffff); +static inline constexpr const DWORD_ WAIT_TIMEOUT_ = 258; +static inline constexpr const DWORD_ WAIT_OBJECT_0_ = 0; +static inline constexpr const DWORD_ WAIT_FAILED_ = + static_cast<DWORD_>(0xffffffff); +static inline constexpr const DWORD_ MAXIMUM_WAIT_OBJECTS_ = 64; + static inline constexpr const DWORD_ VOLUME_NAME_DOS_ = 0x0; static inline constexpr const DWORD_ FILE_NAME_NORMALIZED_ = 0x0; @@ -573,6 +620,22 @@ static inline constexpr const DWORD_ TOKEN_ADJUST_GROUPS_ = 0x0040; static inline constexpr const DWORD_ TOKEN_ADJUST_DEFAULT_ = 0x0080; static inline constexpr const DWORD_ TOKEN_ADJUST_SESSIONID_ = 0x0100; +static inline constexpr const DWORD_ FILE_DEVICE_FILE_SYSTEM_ = 0x9; +static inline constexpr const DWORD_ METHOD_BUFFERED_ = 0; +static inline constexpr const DWORD_ FILE_ANY_ACCESS_ = 0; +static inline constexpr DWORD_ CTL_CODE_(const DWORD_ DeviceType, + const DWORD_ Function, + const DWORD_ Method, + const DWORD_ Access) noexcept { + return (DeviceType << 16) | (Access << 14) | (Function << 2) | Method; +} +static inline constexpr const DWORD_ FSCTL_GET_REPARSE_POINT_ = + CTL_CODE_(FILE_DEVICE_FILE_SYSTEM_, 42, METHOD_BUFFERED_, FILE_ANY_ACCESS_); +static inline constexpr const ULONG_ SYMLINK_FLAG_RELATIVE_ = 1; + +static inline constexpr const DWORD_ IO_REPARSE_TAG_SYMLINK_ = 0xA000000CL; +static inline constexpr const DWORD_ IO_REPARSE_TAG_MOUNT_POINT_ = 0xA0000003L; + static inline constexpr const DWORD_ TOKEN_ALL_ACCESS_P_ = (STANDARD_RIGHTS_REQUIRED_ | TOKEN_ASSIGN_PRIMARY_ | TOKEN_DUPLICATE_ | TOKEN_IMPERSONATE_ | TOKEN_QUERY_ | TOKEN_QUERY_SOURCE_ | @@ -598,6 +661,7 @@ static inline constexpr const DWORD_ INVALID_FILE_ATTRIBUTES_ = static inline constexpr const DWORD_ FILE_SHARE_READ_ = 0x00000001; static inline constexpr const DWORD_ FILE_SHARE_WRITE_ = 0x00000002; static inline constexpr const DWORD_ FILE_SHARE_DELETE_ = 0x00000004; +static inline constexpr const DWORD_ FILE_SHARE_VALID_FLAGS_ = 0x00000007; static inline constexpr const DWORD_ FILE_BEGIN_ = 0; static inline constexpr const DWORD_ FILE_CURRENT_ = 1; @@ -606,6 +670,7 @@ static inline constexpr const DWORD_ FILE_END_ = 2; static inline constexpr const DWORD_ FILE_MAP_READ_ = 0x00000004; static inline constexpr const DWORD_ MOVEFILE_REPLACE_EXISTING_ = 0x00000001; +static inline constexpr const DWORD_ MOVEFILE_COPY_ALLOWED_ = 0x00000002; #if NTDDI_VERSION >= NTDDI_VISTA static inline constexpr const DWORD_ SYMBOLIC_LINK_FLAG_DIRECTORY_ = 0x1; @@ -658,6 +723,16 @@ WASMEDGE_WINAPI_SYMBOL_IMPORT WasmEdge::winapi::BOOL_ WASMEDGE_WINAPI_WINAPI_CC DeleteFileW(WasmEdge::winapi::LPCWSTR_ lpFileName); +WASMEDGE_WINAPI_SYMBOL_IMPORT WasmEdge::winapi::BOOL_ WASMEDGE_WINAPI_WINAPI_CC +DeviceIoControl(WasmEdge::winapi::HANDLE_ hDevice, + WasmEdge::winapi::DWORD_ dwIoControlCode, + WasmEdge::winapi::LPVOID_ lpInBuffer, + WasmEdge::winapi::DWORD_ nInBufferSize, + WasmEdge::winapi::LPVOID_ lpOutBuffer, + WasmEdge::winapi::DWORD_ nOutBufferSize, + WasmEdge::winapi::LPDWORD_ lpBytesReturned, + WasmEdge::winapi::LPOVERLAPPED_ lpOverlapped); + WASMEDGE_WINAPI_SYMBOL_IMPORT WasmEdge::winapi::BOOL_ WASMEDGE_WINAPI_WINAPI_CC FindClose(WasmEdge::winapi::HANDLE_ hFindFile); @@ -756,6 +831,11 @@ WASMEDGE_WINAPI_SYMBOL_IMPORT WasmEdge::winapi::BOOL_ WASMEDGE_WINAPI_SYMBOL_IMPORT WasmEdge::winapi::BOOL_ WASMEDGE_WINAPI_WINAPI_CC UnmapViewOfFile(WasmEdge::winapi::LPCVOID_ lpBaseAddress); +WASMEDGE_WINAPI_SYMBOL_IMPORT WasmEdge::winapi::DWORD_ WASMEDGE_WINAPI_WINAPI_CC +WaitForMultipleObjects(WasmEdge::winapi::DWORD_ nCount, + const WasmEdge::winapi::HANDLE_ *lpHandles, + bool bWaitAll, WasmEdge::winapi::DWORD_ dwMilliseconds); + WASMEDGE_WINAPI_SYMBOL_IMPORT int WASMEDGE_WINAPI_WINAPI_CC WideCharToMultiByte( WasmEdge::winapi::UINT_ CodePage, WasmEdge::winapi::DWORD_ dwFlags, @@ -856,12 +936,29 @@ SetConsoleOutputCP(WasmEdge::winapi::UINT_ wCodePageID); #endif #if NTDDI_VERSION >= NTDDI_VISTA +WASMEDGE_WINAPI_SYMBOL_IMPORT bool WASMEDGE_WINAPI_WINAPI_CC +CommitTransaction(WasmEdge::winapi::HANDLE_ TransactionHandle); + WASMEDGE_WINAPI_SYMBOL_IMPORT WasmEdge::winapi::BOOLEAN_ WASMEDGE_WINAPI_WINAPI_CC CreateSymbolicLinkW(WasmEdge::winapi::LPCWSTR_ lpSymlinkFileName, WasmEdge::winapi::LPCWSTR_ lpTargetFileName, WasmEdge::winapi::DWORD_ dwFlags); +WASMEDGE_WINAPI_SYMBOL_IMPORT WasmEdge::winapi::HANDLE_ + WASMEDGE_WINAPI_WINAPI_CC + CreateTransaction( + WasmEdge::winapi::LPSECURITY_ATTRIBUTES_ lpTransactionAttributes, + void *UOW, WasmEdge::winapi::DWORD_ CreateOptions, + WasmEdge::winapi::DWORD_ IsolationLevel, + WasmEdge::winapi::DWORD_ IsolationFlags, + WasmEdge::winapi::DWORD_ Timeout, + WasmEdge::winapi::LPWSTR_ Description); + +WASMEDGE_WINAPI_SYMBOL_IMPORT bool WASMEDGE_WINAPI_WINAPI_CC +RemoveDirectoryTransactedW(WasmEdge::winapi::LPCWSTR_ lpPathName, + WasmEdge::winapi::HANDLE_ hTransaction); + WASMEDGE_WINAPI_SYMBOL_IMPORT WasmEdge::winapi::HANDLE_ WASMEDGE_WINAPI_WINAPI_CC ReOpenFile(WasmEdge::winapi::HANDLE_ hOriginalFile, @@ -870,6 +967,16 @@ ReOpenFile(WasmEdge::winapi::HANDLE_ hOriginalFile, WasmEdge::winapi::DWORD_ dwFlagsAndAttributes); #endif +#if WINAPI_PARTITION_DESKTOP && NTDDI_VERSION >= NTDDI_VISTA +WASMEDGE_WINAPI_SYMBOL_IMPORT bool WASMEDGE_WINAPI_WINAPI_CC +MoveFileTransactedW(WasmEdge::winapi::LPCWSTR_ lpExistingFileName, + WasmEdge::winapi::LPCWSTR_ lpNewFileName, + WasmEdge::winapi::LPPROGRESS_ROUTINE_ lpProgressRoutine, + WasmEdge::winapi::LPVOID_ lpData, + WasmEdge::winapi::DWORD_ dwFlags, + WasmEdge::winapi::HANDLE_ hTransaction); +#endif + #if !WINAPI_PARTITION_DESKTOP || NTDDI_VERSION >= NTDDI_VISTA WASMEDGE_WINAPI_SYMBOL_IMPORT WasmEdge::winapi::BOOL_ WASMEDGE_WINAPI_WINAPI_CC GetFileInformationByHandleEx( @@ -928,6 +1035,7 @@ using ::CancelIo; using ::CloseHandle; using ::CreateDirectoryW; using ::DeleteFileW; +using ::DeviceIoControl; using ::FindClose; using ::FindFirstFileW; using ::FindNextFileW; @@ -950,6 +1058,7 @@ using ::SetFilePointerEx; using ::SetFileTime; using ::SwitchToThread; using ::UnmapViewOfFile; +using ::WaitForMultipleObjects; using ::WideCharToMultiByte; using ::WriteFileEx; @@ -970,10 +1079,17 @@ using ::SetConsoleOutputCP; #endif #if NTDDI_VERSION >= NTDDI_VISTA +using ::CommitTransaction; using ::CreateSymbolicLinkW; +using ::CreateTransaction; +using ::RemoveDirectoryTransactedW; using ::ReOpenFile; #endif +#if WINAPI_PARTITION_DESKTOP && NTDDI_VERSION >= NTDDI_VISTA +using ::MoveFileTransactedW; +#endif + #if !WINAPI_PARTITION_DESKTOP || NTDDI_VERSION >= NTDDI_VISTA using ::GetFileInformationByHandleEx; using ::GetFinalPathNameByHandleW; @@ -1694,4 +1810,30 @@ inline ULONG_ RtlNtStatusToDosError(NTSTATUS_ Status) noexcept { } // namespace WasmEdge::winapi #endif +extern "C" { +WASMEDGE_WINAPI_SYMBOL_IMPORT +WasmEdge::winapi::BOOL_ WASMEDGE_WINAPI_WINAPI_CC GetModuleHandleExW( + WasmEdge::winapi::DWORD_ dwFlags, WasmEdge::winapi::LPCWSTR_ lpModuleName, + WasmEdge::winapi::HMODULE_ *phModule); + +WASMEDGE_WINAPI_SYMBOL_IMPORT +WasmEdge::winapi::DWORD_ WASMEDGE_WINAPI_WINAPI_CC GetModuleFileNameW( + WasmEdge::winapi::HMODULE_ hModule, WasmEdge::winapi::LPWSTR_ lpFilename, + WasmEdge::winapi::DWORD_ nSize); +} // extern "C" + +namespace WasmEdge::winapi { +using ::GetModuleFileNameW; +using ::GetModuleHandleExW; +} // namespace WasmEdge::winapi + +namespace WasmEdge::winapi { +static inline constexpr const DWORD_ GET_MODULE_HANDLE_EX_FLAG_PIN_ = + 0x00000001L; +static inline constexpr const DWORD_ + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT_ = 0x00000002L; +static inline constexpr const DWORD_ GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS_ = + 0x00000004L; +} // namespace WasmEdge::winapi + #endif diff --git a/include/validator/formchecker.h b/include/validator/formchecker.h index cfacaf4fd6a5..9467c14bf639 100644 --- a/include/validator/formchecker.h +++ b/include/validator/formchecker.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/validator/formchecker.h - Form checking class definition -===// // @@ -32,14 +32,6 @@ typedef std::optional<ValType> VType; static inline constexpr VType unreachableVType() { return VType(); } -static inline constexpr bool isNumType(const VType V) { - return !V || V->isNumType(); -} - -static inline constexpr bool isRefType(const VType V) { - return !V || V->isRefType(); -} - class FormChecker { public: FormChecker() = default; @@ -50,7 +42,7 @@ class FormChecker { Expect<void> validate(const ValType &VT) const noexcept; /// Adder of contexts - void addType(const AST::FunctionType &Func); + void addType(const AST::SubType &Type); void addFunc(const uint32_t TypeIdx, const bool IsImport = false); void addTable(const AST::TableType &Tab); void addMemory(const AST::MemoryType &Mem); @@ -59,6 +51,7 @@ class FormChecker { void addData(const AST::DataSegment &Data); void addRef(const uint32_t FuncIdx); void addLocal(const ValType &V, bool Initialized); + void addTag(const uint32_t TypeIdx); std::vector<VType> result() { return ValStack; } auto &getTypes() { return Types; } @@ -66,17 +59,14 @@ class FormChecker { auto &getTables() { return Tables; } auto &getMemories() { return Mems; } auto &getGlobals() { return Globals; } + auto &getTags() { return Tags; } uint32_t getNumImportFuncs() const { return NumImportFuncs; } uint32_t getNumImportGlobals() const { return NumImportGlobals; } /// Helper function ValType VTypeToAST(const VType &V); - /// ValType matcher - bool matchType(const ValType &Exp, const ValType &Got) const noexcept; - bool matchTypes(Span<const ValType> Exp, - Span<const ValType> Got) const noexcept; - + /// Control frame struct CtrlFrame { CtrlFrame() = default; CtrlFrame(struct CtrlFrame &&F) @@ -136,7 +126,7 @@ class FormChecker { Expect<void> StackPopAny(); /// Contexts. - std::vector<std::pair<std::vector<ValType>, std::vector<ValType>>> Types; + std::vector<const AST::SubType *> Types; std::vector<uint32_t> Funcs; std::vector<ValType> Tables; uint32_t Mems = 0; @@ -149,6 +139,7 @@ class FormChecker { std::vector<LocalType> Locals; std::vector<uint32_t> LocalInits; std::vector<ValType> Returns; + std::vector<uint32_t> Tags; /// Running stack. std::vector<CtrlFrame> CtrlStack; diff --git a/include/validator/validator.h b/include/validator/validator.h index a508ad9af7c4..a3f7686ac974 100644 --- a/include/validator/validator.h +++ b/include/validator/validator.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/validator/validator.h - validator class definition -------===// // @@ -37,6 +37,7 @@ class Validator { private: /// Validate AST::Types + Expect<void> validate(const AST::SubType &Type); Expect<void> validate(const AST::Limit &Lim); Expect<void> validate(const AST::TableType &Tab); Expect<void> validate(const AST::MemoryType &Mem); @@ -66,6 +67,7 @@ class Validator { Expect<void> validate(const AST::DataSection &DataSec); Expect<void> validate(const AST::StartSection &StartSec); Expect<void> validate(const AST::ExportSection &ExportSec); + Expect<void> validate(const AST::TagSection &TagSec); /// Validate const expression Expect<void> validateConstExpr(AST::InstrView Instrs, diff --git a/include/vm/vm.h b/include/vm/vm.h index b790e0242305..40ea884f004a 100644 --- a/include/vm/vm.h +++ b/include/vm/vm.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/vm/vm.h - VM execution flow class definition -------------===// // @@ -277,6 +277,11 @@ class VM { std::string_view Func, Span<const ValVariant> Params = {}, Span<const ValType> ParamTypes = {}); + Expect<std::vector<std::pair<ValVariant, ValType>>> + unsafeExecute(const Runtime::Instance::ComponentInstance *CompInst, + std::string_view Func, Span<const ValVariant> Params = {}, + Span<const ValType> ParamTypes = {}); + /// \name VM environment. /// @{ const Configure Conf; @@ -296,8 +301,10 @@ class VM { /// @{ /// Loaded AST module. std::unique_ptr<AST::Module> Mod; + std::unique_ptr<AST::Component::Component> Comp; /// Active module instance. std::unique_ptr<Runtime::Instance::ModuleInstance> ActiveModInst; + std::unique_ptr<Runtime::Instance::ComponentInstance> ActiveCompInst; /// Registered module instances by user. std::vector<std::unique_ptr<Runtime::Instance::ModuleInstance>> RegModInsts; /// Built-in module instances mapped to the configurations. For WASI. @@ -307,6 +314,8 @@ class VM { /// Loaded module instances from plug-ins. std::vector<std::unique_ptr<Runtime::Instance::ModuleInstance>> PlugInModInsts; + std::vector<std::unique_ptr<Runtime::Instance::ComponentInstance>> + PlugInCompInsts; /// Self-owned store (nullptr if an outside store is assigned in constructor). std::unique_ptr<Runtime::StoreManager> Store; /// Reference to the store. diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index a7f09e1c6ada..6209f4c2f386 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,8 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC -if(WASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) add_subdirectory(aot) + add_subdirectory(llvm) endif() add_subdirectory(common) add_subdirectory(system) diff --git a/lib/aot/CMakeLists.txt b/lib/aot/CMakeLists.txt index 1ba8247b49bf..b6d65cf456e9 100644 --- a/lib/aot/CMakeLists.txt +++ b/lib/aot/CMakeLists.txt @@ -1,77 +1,18 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC -find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_PATH}") -get_filename_component(LLVM_DIR "${LLVM_DIR}" ABSOLUTE) -list(APPEND CMAKE_MODULE_PATH ${LLVM_DIR}) -include(LLVMConfig) -include(AddLLVM) - -get_filename_component(LLD_DIR "${LLVM_LIBRARY_DIR}/cmake/lld" ABSOLUTE) -find_package(LLD REQUIRED HINTS ${LLD_DIR}) - -if(WASMEDGE_LINK_LLVM_STATIC) - wasmedge_add_library(wasmedgeAOT - blake3.cpp - cache.cpp - compiler.cpp - ) - - target_link_libraries(wasmedgeAOT - PUBLIC - wasmedgeCommon - wasmedgeSystem - utilBlake3 - std::filesystem - ${WASMEDGE_LLVM_LINK_STATIC_COMPONENTS} - ${WASMEDGE_LLVM_LINK_SHARED_COMPONENTS} - ) -else() - if(APPLE) - list(APPEND LLD_LIBS lldMachO) - elseif(WIN32) - list(APPEND LLD_LIBS lldCOFF) - set(EXTRA_COMPONENTS DebugInfoPDB LibDriver WindowsManifest) - else() - list(APPEND LLD_LIBS lldELF) - endif() - - list(APPEND LLD_LIBS lldCommon) - if(LLVM_VERSION_MAJOR LESS_EQUAL 13) - list(APPEND LLD_LIBS lldDriver) - endif() - - # Command line warning D9025 : overriding '/EHs' with '/EHs-' - # prevent LLVM from adding /EHs-c-. - if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - set(LLVM_REQUIRES_EH ON) - endif() - - llvm_add_library(wasmedgeAOT - blake3.cpp - cache.cpp - compiler.cpp - LINK_LIBS - wasmedgeCommon - wasmedgeSystem - utilBlake3 - ${LLD_LIBS} - std::filesystem - ${CMAKE_THREAD_LIBS_INIT} - LINK_COMPONENTS - core - lto - native - nativecodegen - option - passes - support - transformutils - ${EXTRA_COMPONENTS} - ) -endif() +wasmedge_add_library(wasmedgeAOT + blake3.cpp + cache.cpp +) -wasmedge_setup_target(wasmedgeAOT) +target_link_libraries(wasmedgeAOT + PUBLIC + wasmedgeCommon + wasmedgeSystem + utilBlake3 + std::filesystem +) target_include_directories(wasmedgeAOT SYSTEM @@ -84,17 +25,3 @@ target_include_directories(wasmedgeAOT ${PROJECT_BINARY_DIR}/include ${PROJECT_SOURCE_DIR}/thirdparty/blake3 ) - -include(CheckCXXSourceCompiles) -set(CMAKE_REQUIRED_LINK_OPTIONS "-Wl,-lc,--exclude-libs=libc.a") -check_cxx_source_compiles("int main(){}" SUPPORT_EXCLUDE_LIBS) - -if(SUPPORT_EXCLUDE_LIBS) - file(GLOB LLD_ALL_LIBS ${LLVM_LIBRARY_DIR}/liblld*.a) - list(TRANSFORM LLD_ALL_LIBS REPLACE "^.*/" "") - string(JOIN : LLD_ALL_LIBS_COLON ${LLD_ALL_LIBS}) - target_link_options(wasmedgeAOT - PUBLIC - "SHELL:-Wl,--exclude-libs=${LLD_ALL_LIBS_COLON}" - ) -endif() diff --git a/lib/aot/blake3.cpp b/lib/aot/blake3.cpp index 8241ac970a47..288a191f95a6 100644 --- a/lib/aot/blake3.cpp +++ b/lib/aot/blake3.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "aot/blake3.h" diff --git a/lib/aot/cache.cpp b/lib/aot/cache.cpp index 13958cd8dc6b..7425ea0ea6f9 100644 --- a/lib/aot/cache.cpp +++ b/lib/aot/cache.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "aot/cache.h" diff --git a/lib/api/CMakeLists.txt b/lib/api/CMakeLists.txt index 9ad7e285a9fc..f4123488537b 100644 --- a/lib/api/CMakeLists.txt +++ b/lib/api/CMakeLists.txt @@ -1,10 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC find_package(spdlog QUIET) add_definitions(-DWASMEDGE_COMPILE_LIBRARY) -if(WASMEDGE_BUILD_AOT_RUNTIME) - add_definitions(-DWASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) + add_definitions(-DWASMEDGE_USE_LLVM) endif() if(WASMEDGE_BUILD_WASI_NN_RPC) add_definitions(-DWASMEDGE_BUILD_WASI_NN_RPC) @@ -82,10 +82,11 @@ target_link_libraries(wasmedgeCAPI wasmedgeDriver ) -if (WASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) target_link_libraries(wasmedgeCAPI PUBLIC wasmedgeAOT + wasmedgeLLVM ) endif() @@ -96,7 +97,6 @@ target_include_directories(wasmedgeCAPI ) if(WASMEDGE_BUILD_SHARED_LIB) - wasmedge_add_library(wasmedge_shared SHARED ../../include/api/wasmedge/wasmedge.h ) @@ -137,7 +137,6 @@ if(WASMEDGE_BUILD_SHARED_LIB) LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/wasmedge ) - endif() if(WASMEDGE_BUILD_STATIC_LIB) @@ -152,15 +151,19 @@ if(WASMEDGE_BUILD_STATIC_LIB) wasmedge_add_static_lib_component_command(wasmedgeExecutor) wasmedge_add_static_lib_component_command(wasmedgeHostModuleWasi) wasmedge_add_static_lib_component_command(wasmedgePlugin) + # BUILTIN-PLUGIN: Temporary add the wasi-logging plugin here until the new + # plugin architecture ready in 0.15.0. + wasmedge_add_static_lib_component_command(wasmedgePluginWasiLogging) wasmedge_add_static_lib_component_command(wasmedgeVM) wasmedge_add_static_lib_component_command(wasmedgeDriver) - if(WASMEDGE_BUILD_AOT_RUNTIME) + if(WASMEDGE_USE_LLVM) foreach(LIB_NAME IN LISTS WASMEDGE_LLVM_LINK_STATIC_COMPONENTS) wasmedge_add_libs_component_command(${LIB_NAME}) endforeach() wasmedge_add_static_lib_component_command(utilBlake3) wasmedge_add_static_lib_component_command(wasmedgeAOT) + wasmedge_add_static_lib_component_command(wasmedgeLLVM) endif() if (${CMAKE_BUILD_TYPE} STREQUAL "Debug") @@ -199,10 +202,12 @@ if(WASMEDGE_BUILD_STATIC_LIB) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${WASMEDGE_LIBRARY_NAME}" DESTINATION ${CMAKE_INSTALL_LIBDIR} ) - install(FILES ${WASMEDGE_CAPI_HEADERS} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/wasmedge - ) - install(FILES ${PROJECT_SOURCE_DIR}/cmake/wasmedge-config.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wasmedge) endif() + +install(FILES ${WASMEDGE_CAPI_HEADERS} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/wasmedge +) + +install(FILES ${PROJECT_SOURCE_DIR}/cmake/wasmedge-config.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wasmedge) diff --git a/lib/api/libwasmedge.lds b/lib/api/libwasmedge.lds index b186937777bd..afc57677c545 100644 --- a/lib/api/libwasmedge.lds +++ b/lib/api/libwasmedge.lds @@ -4,7 +4,7 @@ extern "C++" { WasmEdge::* }; - + llvm_orc_*; local: *; }; diff --git a/lib/api/wasmedge.cpp b/lib/api/wasmedge.cpp index abcde5bd376c..5fba0a2eb7ce 100644 --- a/lib/api/wasmedge.cpp +++ b/lib/api/wasmedge.cpp @@ -1,10 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "wasmedge/wasmedge.h" -#include "aot/compiler.h" #include "common/defines.h" +#include "common/enum_errcode.hpp" #include "driver/compiler.h" #include "driver/tool.h" #include "driver/unitool.h" @@ -12,6 +12,9 @@ #include "plugin/plugin.h" #include "system/winapi.h" #include "vm/vm.h" +#include "llvm/codegen.h" +#include "llvm/compiler.h" +#include "llvm/jit.h" #ifdef WASMEDGE_BUILD_FUZZING #include "driver/fuzzPO.h" @@ -55,6 +58,9 @@ struct WasmEdge_TableTypeContext {}; // WasmEdge_MemoryTypeContext implementation. struct WasmEdge_MemoryTypeContext {}; +// WasmEdge_TagTypeContext implementation. +struct WasmEdge_TagTypeContext {}; + // WasmEdge_GlobalTypeContext implementation. struct WasmEdge_GlobalTypeContext {}; @@ -66,10 +72,11 @@ struct WasmEdge_ExportTypeContext {}; // WasmEdge_CompilerContext implementation. struct WasmEdge_CompilerContext { -#ifdef WASMEDGE_BUILD_AOT_RUNTIME +#ifdef WASMEDGE_USE_LLVM WasmEdge_CompilerContext(const WasmEdge::Configure &Conf) noexcept - : Compiler(Conf), Load(Conf), Valid(Conf) {} - WasmEdge::AOT::Compiler Compiler; + : Compiler(Conf), CodeGen(Conf), Load(Conf), Valid(Conf) {} + WasmEdge::LLVM::Compiler Compiler; + WasmEdge::LLVM::CodeGen CodeGen; WasmEdge::Loader::Loader Load; WasmEdge::Validator::Validator Valid; #endif @@ -99,6 +106,9 @@ struct WasmEdge_TableInstanceContext {}; // WasmEdge_MemoryInstanceContext implementation. struct WasmEdge_MemoryInstanceContext {}; +// WasmEdge_TagInstanceContext implementation. +struct WasmEdge_TagInstanceContext {}; + // WasmEdge_GlobalInstanceContext implementation. struct WasmEdge_GlobalInstanceContext {}; @@ -330,6 +340,7 @@ CONVTO(TabType, AST::TableType, TableType, ) CONVTO(TabType, AST::TableType, TableType, const) CONVTO(MemType, AST::MemoryType, MemoryType, ) CONVTO(MemType, AST::MemoryType, MemoryType, const) +CONVTO(TagType, AST::TagType, TagType, const) CONVTO(GlobType, AST::GlobalType, GlobalType, ) CONVTO(GlobType, AST::GlobalType, GlobalType, const) CONVTO(ImpType, AST::ImportDesc, ImportType, const) @@ -344,6 +355,7 @@ CONVTO(Func, Runtime::Instance::FunctionInstance, FunctionInstance, ) CONVTO(Func, Runtime::Instance::FunctionInstance, FunctionInstance, const) CONVTO(Tab, Runtime::Instance::TableInstance, TableInstance, ) CONVTO(Mem, Runtime::Instance::MemoryInstance, MemoryInstance, ) +CONVTO(Tag, Runtime::Instance::TagInstance, TagInstance, ) CONVTO(Glob, Runtime::Instance::GlobalInstance, GlobalInstance, ) CONVTO(CallFrame, Runtime::CallingFrame, CallingFrame, const) CONVTO(Plugin, Plugin::Plugin, Plugin, const) @@ -364,6 +376,7 @@ CONVFROM(TabType, AST::TableType, TableType, ) CONVFROM(TabType, AST::TableType, TableType, const) CONVFROM(MemType, AST::MemoryType, MemoryType, ) CONVFROM(MemType, AST::MemoryType, MemoryType, const) +CONVFROM(TagType, AST::TagType, TagType, const) CONVFROM(GlobType, AST::GlobalType, GlobalType, ) CONVFROM(GlobType, AST::GlobalType, GlobalType, const) CONVFROM(ImpType, AST::ImportDesc, ImportType, const) @@ -381,6 +394,7 @@ CONVFROM(Tab, Runtime::Instance::TableInstance, TableInstance, ) CONVFROM(Tab, Runtime::Instance::TableInstance, TableInstance, const) CONVFROM(Mem, Runtime::Instance::MemoryInstance, MemoryInstance, ) CONVFROM(Mem, Runtime::Instance::MemoryInstance, MemoryInstance, const) +CONVFROM(Tag, Runtime::Instance::TagInstance, TagInstance, const) CONVFROM(Glob, Runtime::Instance::GlobalInstance, GlobalInstance, ) CONVFROM(Glob, Runtime::Instance::GlobalInstance, GlobalInstance, const) CONVFROM(CallFrame, Runtime::CallingFrame, CallingFrame, const) @@ -394,20 +408,21 @@ class CAPIHostFunc : public Runtime::HostFunctionBase { void *ExtData, const uint64_t FuncCost = 0) noexcept : Runtime::HostFunctionBase(FuncCost), Func(FuncPtr), Wrap(nullptr), Binding(nullptr), Data(ExtData) { - FuncType = *Type; + DefType.getCompositeType().getFuncType() = *Type; } CAPIHostFunc(const AST::FunctionType *Type, WasmEdge_WrapFunc_t WrapPtr, void *BindingPtr, void *ExtData, const uint64_t FuncCost = 0) noexcept : Runtime::HostFunctionBase(FuncCost), Func(nullptr), Wrap(WrapPtr), Binding(BindingPtr), Data(ExtData) { - FuncType = *Type; + DefType.getCompositeType().getFuncType() = *Type; } ~CAPIHostFunc() noexcept override = default; Expect<void> run(const Runtime::CallingFrame &CallFrame, Span<const ValVariant> Args, Span<ValVariant> Rets) override { + auto &FuncType = DefType.getCompositeType().getFuncType(); std::vector<WasmEdge_Value> Params(FuncType.getParamTypes().size()), Returns(FuncType.getReturnTypes().size()); for (uint32_t I = 0; I < Args.size(); I++) { @@ -1303,6 +1318,21 @@ WasmEdge_MemoryTypeDelete(WasmEdge_MemoryTypeContext *Cxt) { // <<<<<<<< WasmEdge memory type functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +// >>>>>>>> WasmEdge tag type functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +WASMEDGE_CAPI_EXPORT const WasmEdge_FunctionTypeContext * +WasmEdge_TagTypeGetFunctionType(const WasmEdge_TagTypeContext *Cxt) { + if (Cxt) { + const auto &CompType = fromTagTypeCxt(Cxt)->getDefType().getCompositeType(); + if (CompType.isFunc()) { + return toFuncTypeCxt(&CompType.getFuncType()); + } + } + return nullptr; +} + +// <<<<<<<< WasmEdge tag type functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + // >>>>>>>> WasmEdge global type functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> WASMEDGE_CAPI_EXPORT WasmEdge_GlobalTypeContext * @@ -1373,12 +1403,10 @@ WasmEdge_ImportTypeGetFunctionType(const WasmEdge_ASTModuleContext *ASTCxt, fromImpTypeCxt(Cxt)->getExternalType() == WasmEdge::ExternalType::Function) { uint32_t Idx = fromImpTypeCxt(Cxt)->getExternalFuncTypeIdx(); - const auto &FuncTypes = - fromASTModCxt(ASTCxt)->getTypeSection().getContent(); - if (Idx >= FuncTypes.size()) { - return nullptr; + auto SubTypes = fromASTModCxt(ASTCxt)->getTypeSection().getContent(); + if (Idx < SubTypes.size() && SubTypes[Idx].getCompositeType().isFunc()) { + return toFuncTypeCxt(&(SubTypes[Idx].getCompositeType().getFuncType())); } - return toFuncTypeCxt(&FuncTypes[Idx]); } return nullptr; } @@ -1404,6 +1432,16 @@ WasmEdge_ImportTypeGetMemoryType(const WasmEdge_ASTModuleContext *ASTCxt, return nullptr; } +WASMEDGE_CAPI_EXPORT const WasmEdge_TagTypeContext * +WasmEdge_ImportTypeGetTagType(const WasmEdge_ASTModuleContext *ASTCxt, + const WasmEdge_ImportTypeContext *Cxt) { + if (ASTCxt && Cxt && + fromImpTypeCxt(Cxt)->getExternalType() == WasmEdge::ExternalType::Tag) { + return toTagTypeCxt(&fromImpTypeCxt(Cxt)->getExternalTagType()); + } + return nullptr; +} + WASMEDGE_CAPI_EXPORT const WasmEdge_GlobalTypeContext * WasmEdge_ImportTypeGetGlobalType(const WasmEdge_ASTModuleContext *ASTCxt, const WasmEdge_ImportTypeContext *Cxt) { @@ -1446,7 +1484,6 @@ WasmEdge_ExportTypeGetFunctionType(const WasmEdge_ASTModuleContext *ASTCxt, WasmEdge::ExternalType::Function) { auto ImpDescs = fromASTModCxt(ASTCxt)->getImportSection().getContent(); auto FuncIdxs = fromASTModCxt(ASTCxt)->getFunctionSection().getContent(); - auto FuncTypes = fromASTModCxt(ASTCxt)->getTypeSection().getContent(); uint32_t ExtIdx = fromExpTypeCxt(Cxt)->getExternalIndex(); // Indexing the import descriptions. @@ -1469,11 +1506,13 @@ WasmEdge_ExportTypeGetFunctionType(const WasmEdge_ASTModuleContext *ASTCxt, // Invalid function index. return nullptr; } - // Get the function type by index. - if (TypeIdx >= FuncTypes.size()) { - return nullptr; + // Get the function type. + auto SubTypes = fromASTModCxt(ASTCxt)->getTypeSection().getContent(); + if (TypeIdx < SubTypes.size() && + SubTypes[TypeIdx].getCompositeType().isFunc()) { + return toFuncTypeCxt( + &(SubTypes[TypeIdx].getCompositeType().getFuncType())); } - return toFuncTypeCxt(&FuncTypes[TypeIdx]); } return nullptr; } @@ -1543,6 +1582,30 @@ WasmEdge_ExportTypeGetMemoryType(const WasmEdge_ASTModuleContext *ASTCxt, return nullptr; } +WASMEDGE_CAPI_EXPORT const WasmEdge_TagTypeContext * +WasmEdge_ExportTypeGetTagType(const WasmEdge_ASTModuleContext *ASTCxt, + const WasmEdge_ExportTypeContext *Cxt) { + if (ASTCxt && Cxt && + fromExpTypeCxt(Cxt)->getExternalType() == WasmEdge::ExternalType::Tag) { + // `external_index` = `tag_type_index` + `import_tag_nums` + uint32_t ExtIdx = fromExpTypeCxt(Cxt)->getExternalIndex(); + const auto &ImpDescs = + fromASTModCxt(ASTCxt)->getImportSection().getContent(); + for (auto &&ImpDesc : ImpDescs) { + if (ImpDesc.getExternalType() == WasmEdge::ExternalType::Tag) { + ExtIdx--; + } + } + // Get the tag type + const auto &TagDescs = fromASTModCxt(ASTCxt)->getTagSection().getContent(); + if (ExtIdx >= TagDescs.size()) { + return nullptr; + } + return toTagTypeCxt(&TagDescs[ExtIdx]); + } + return nullptr; +} + WASMEDGE_CAPI_EXPORT const WasmEdge_GlobalTypeContext * WasmEdge_ExportTypeGetGlobalType(const WasmEdge_ASTModuleContext *ASTCxt, const WasmEdge_ExportTypeContext *Cxt) { @@ -1584,7 +1647,7 @@ WasmEdge_ExportTypeGetGlobalType(const WasmEdge_ASTModuleContext *ASTCxt, WASMEDGE_CAPI_EXPORT WasmEdge_CompilerContext * WasmEdge_CompilerCreate(const WasmEdge_ConfigureContext *ConfCxt [[maybe_unused]]) { -#ifdef WASMEDGE_BUILD_AOT_RUNTIME +#ifdef WASMEDGE_USE_LLVM // Set force interpreter here to load instructions of function body forcibly. if (ConfCxt) { WasmEdge::Configure CopyConf(ConfCxt->Conf); @@ -1603,27 +1666,27 @@ WasmEdge_CompilerCreate(const WasmEdge_ConfigureContext *ConfCxt WASMEDGE_CAPI_EXPORT WasmEdge_Result WasmEdge_CompilerCompile( WasmEdge_CompilerContext *Cxt [[maybe_unused]], const char *InPath [[maybe_unused]], const char *OutPath [[maybe_unused]]) { -#ifdef WASMEDGE_BUILD_AOT_RUNTIME +#ifdef WASMEDGE_USE_LLVM return wrap( [&]() -> WasmEdge::Expect<void> { std::filesystem::path InputPath = std::filesystem::absolute(InPath); std::filesystem::path OutputPath = std::filesystem::absolute(OutPath); std::vector<WasmEdge::Byte> Data; std::unique_ptr<WasmEdge::AST::Module> Module; - if (auto Res = Cxt->Load.loadFile(InputPath)) { - Data = std::move(*Res); - } else { - return Unexpect(Res); - } - if (auto Res = Cxt->Load.parseModule(Data)) { - Module = std::move(*Res); - } else { - return Unexpect(Res); - } - if (auto Res = Cxt->Valid.validate(*Module.get()); !Res) { - return Unexpect(Res); - } - return Cxt->Compiler.compile(Data, *Module.get(), OutputPath); + return Cxt->Load.loadFile(InputPath) + .and_then([&](auto Result) noexcept { + Data = std::move(Result); + return Cxt->Load.parseModule(Data); + }) + .and_then([&](auto Result) noexcept { + Module = std::move(Result); + return Cxt->Valid.validate(*Module.get()); + }) + .and_then( + [&]() noexcept { return Cxt->Compiler.compile(*Module.get()); }) + .and_then([&](auto Result) noexcept { + return Cxt->CodeGen.codegen(Data, std::move(Result), OutputPath); + }); }, EmptyThen, Cxt); #else @@ -1643,21 +1706,21 @@ WASMEDGE_CAPI_EXPORT WasmEdge_Result WasmEdge_CompilerCompileFromBytes( WasmEdge_CompilerContext *Cxt [[maybe_unused]], const WasmEdge_Bytes Bytes [[maybe_unused]], const char *OutPath [[maybe_unused]]) { -#ifdef WASMEDGE_BUILD_AOT_RUNTIME +#ifdef WASMEDGE_USE_LLVM return wrap( [&]() -> WasmEdge::Expect<void> { std::filesystem::path OutputPath = std::filesystem::absolute(OutPath); auto Data = genSpan(Bytes.Buf, Bytes.Length); std::unique_ptr<WasmEdge::AST::Module> Module; - if (auto Res = Cxt->Load.parseModule(Data)) { - Module = std::move(*Res); - } else { - return Unexpect(Res); - } - if (auto Res = Cxt->Valid.validate(*Module.get()); !Res) { - return Unexpect(Res); - } - return Cxt->Compiler.compile(Data, *Module.get(), OutputPath); + return Cxt->Load.parseModule(Data) + .and_then([&](auto Result) noexcept { + Module = std::move(Result); + return Cxt->Valid.validate(*Module); + }) + .and_then([&]() noexcept { return Cxt->Compiler.compile(*Module); }) + .and_then([&](auto Result) noexcept { + return Cxt->CodeGen.codegen(Data, std::move(Result), OutputPath); + }); }, EmptyThen, Cxt); #else @@ -1732,6 +1795,29 @@ WASMEDGE_CAPI_EXPORT WasmEdge_Result WasmEdge_LoaderSerializeASTModule( Cxt, ASTCxt, Buf); } +WASMEDGE_CAPI_EXPORT extern WasmEdge_Result +WasmEdge_LoaderPrepareForJIT(WasmEdge_LoaderContext *Ctx, + WasmEdge_ASTModuleContext *ASTCxt, + const WasmEdge_ConfigureContext *ConfCxt) { +#ifdef WASMEDGE_USE_LLVM + LLVM::Compiler Compiler(ConfCxt->Conf); + LLVM::JIT JIT(ConfCxt->Conf); + auto *Mod = fromASTModCxt(ASTCxt); + if (auto Res = Compiler.compile(*Mod); !Res) { + const auto Err = static_cast<uint32_t>(Res.error()); + return genWasmEdge_Result(Err); + } else if (auto Res2 = JIT.load(std::move(*Res)); !Res2) { + const auto Err = static_cast<uint32_t>(Res2.error()); + return genWasmEdge_Result(Err); + } else { + fromLoaderCxt(Ctx)->loadExecutable(*Mod, std::move(*Res2)); + } + return genWasmEdge_Result(ErrCode::Value::Success); +#else + return genWasmEdge_Result(ErrCode::Value::JITDisabled); +#endif +} + WASMEDGE_CAPI_EXPORT void WasmEdge_LoaderDelete(WasmEdge_LoaderContext *Cxt) { delete fromLoaderCxt(Cxt); } @@ -2012,7 +2098,9 @@ WasmEdge_ModuleInstanceInitWasmEdgeProcess(const char *const *AllowedCmds, Parser.set_raw_value<std::vector<std::string>>( "allow-command"sv, std::vector<std::string>(AllowedCmds, AllowedCmds + CmdsLen)); - Parser.set_raw_value<bool>("allow-command-all"sv, AllowAll); + if (AllowAll) { + Parser.set_raw_value("allow-command-all"sv); + } } } @@ -2061,6 +2149,15 @@ WasmEdge_ModuleInstanceFindMemory(const WasmEdge_ModuleInstanceContext *Cxt, return nullptr; } +WASMEDGE_CAPI_EXPORT WasmEdge_TagInstanceContext * +WasmEdge_ModuleInstanceFindTag(const WasmEdge_ModuleInstanceContext *Cxt, + const WasmEdge_String Name) { + if (Cxt) { + return toTagCxt(fromModCxt(Cxt)->findTagExports(genStrView(Name))); + } + return nullptr; +} + WASMEDGE_CAPI_EXPORT WasmEdge_GlobalInstanceContext * WasmEdge_ModuleInstanceFindGlobal(const WasmEdge_ModuleInstanceContext *Cxt, const WasmEdge_String Name) { @@ -2125,6 +2222,24 @@ WasmEdge_ModuleInstanceListMemory(const WasmEdge_ModuleInstanceContext *Cxt, return 0; } +WASMEDGE_CAPI_EXPORT uint32_t WasmEdge_ModuleInstanceListTagLength( + const WasmEdge_ModuleInstanceContext *Cxt) { + if (Cxt) { + return fromModCxt(Cxt)->getTagExportNum(); + } + return 0; +} + +WASMEDGE_CAPI_EXPORT uint32_t +WasmEdge_ModuleInstanceListTag(const WasmEdge_ModuleInstanceContext *Cxt, + WasmEdge_String *Names, const uint32_t Len) { + if (Cxt) { + return fromModCxt(Cxt)->getTagExports( + [&](auto &Map) { return fillMap(Map, Names, Len); }); + } + return 0; +} + WASMEDGE_CAPI_EXPORT uint32_t WasmEdge_ModuleInstanceListGlobalLength( const WasmEdge_ModuleInstanceContext *Cxt) { if (Cxt) { @@ -2206,8 +2321,8 @@ WasmEdge_FunctionInstanceCreate(const WasmEdge_FunctionTypeContext *Type, const uint64_t Cost) { if (Type && HostFunc) { return toFuncCxt(new WasmEdge::Runtime::Instance::FunctionInstance( - nullptr, std::make_unique<CAPIHostFunc>(fromFuncTypeCxt(Type), HostFunc, - Data, Cost))); + std::make_unique<CAPIHostFunc>(fromFuncTypeCxt(Type), HostFunc, Data, + Cost))); } return nullptr; } @@ -2219,8 +2334,8 @@ WasmEdge_FunctionInstanceCreateBinding(const WasmEdge_FunctionTypeContext *Type, const uint64_t Cost) { if (Type && WrapFunc) { return toFuncCxt(new WasmEdge::Runtime::Instance::FunctionInstance( - nullptr, std::make_unique<CAPIHostFunc>(fromFuncTypeCxt(Type), WrapFunc, - Binding, Data, Cost))); + std::make_unique<CAPIHostFunc>(fromFuncTypeCxt(Type), WrapFunc, Binding, + Data, Cost))); } return nullptr; } @@ -2467,6 +2582,18 @@ WasmEdge_MemoryInstanceDelete(WasmEdge_MemoryInstanceContext *Cxt) { // <<<<<<<< WasmEdge memory instance functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +// >>>>>>>> WasmEdge tag instance functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +WASMEDGE_CAPI_EXPORT const WasmEdge_TagTypeContext * +WasmEdge_TagInstanceGetTagType(const WasmEdge_TagInstanceContext *Cxt) { + if (Cxt) { + return toTagTypeCxt(&fromTagCxt(Cxt)->getTagType()); + } + return nullptr; +} + +// <<<<<<<< WasmEdge tag instance functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + // >>>>>>>> WasmEdge global instance functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> WASMEDGE_CAPI_EXPORT WasmEdge_GlobalInstanceContext * @@ -2570,7 +2697,7 @@ WASMEDGE_CAPI_EXPORT WasmEdge_Result WasmEdge_GlobalInstanceSetValue( return Unexpect(WasmEdge::ErrCode::Value::SetValueErrorType); } } - fromGlobCxt(Cxt)->getValue() = Val; + fromGlobCxt(Cxt)->setValue(Val); return {}; }, EmptyThen, Cxt); @@ -3168,9 +3295,7 @@ WASMEDGE_CAPI_EXPORT extern "C" int WasmEdge_Driver_FuzzPO(const uint8_t *Data, // >>>>>>>> WasmEdge Plugin functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> WASMEDGE_CAPI_EXPORT void WasmEdge_PluginLoadWithDefaultPaths(void) { - for (const auto &Path : WasmEdge::Plugin::Plugin::getDefaultPluginPaths()) { - WasmEdge::Plugin::Plugin::load(Path); - } + WasmEdge::Plugin::Plugin::loadFromDefaultPaths(); } WASMEDGE_CAPI_EXPORT void WasmEdge_PluginLoadFromPath(const char *Path) { diff --git a/lib/common/CMakeLists.txt b/lib/common/CMakeLists.txt index 7207ec0813e8..5837ad344cd2 100644 --- a/lib/common/CMakeLists.txt +++ b/lib/common/CMakeLists.txt @@ -1,41 +1,15 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC -find_package(spdlog QUIET) -if(spdlog_FOUND) -else() - FetchContent_Declare( - spdlog - GIT_REPOSITORY https://github.com/gabime/spdlog.git - GIT_TAG v1.11.0 - GIT_SHALLOW TRUE - ) - set(SPDLOG_BUILD_SHARED OFF CACHE BOOL "Build shared library" FORCE) - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - get_property( - compile_options - DIRECTORY - PROPERTY COMPILE_OPTIONS - ) - set_property( - DIRECTORY - APPEND - PROPERTY COMPILE_OPTIONS - ${WASMEDGE_CFLAGS} - -Wno-missing-noreturn - -Wno-missing-variable-declarations - ) - unset(compile_options) - endif() - FetchContent_MakeAvailable(spdlog) - wasmedge_setup_target(spdlog) -endif() +hunter_add_package(fmt) +hunter_add_package(spdlog) + +find_package(spdlog CONFIG REQUIRED) wasmedge_add_library(wasmedgeCommon hexstr.cpp - log.cpp + spdlog.cpp errinfo.cpp - int128.cpp ) target_link_libraries(wasmedgeCommon diff --git a/lib/common/errinfo.cpp b/lib/common/errinfo.cpp index f2bd01bfea24..c18f78e30606 100644 --- a/lib/common/errinfo.cpp +++ b/lib/common/errinfo.cpp @@ -1,10 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/errinfo.h" #include "common/errcode.h" #include "common/hexstr.h" +#include <spdlog/fmt/fmt.h> +#include <spdlog/fmt/ranges.h> + using namespace std::literals; fmt::format_context::iterator @@ -305,7 +308,7 @@ fmt::formatter<WasmEdge::ErrInfo::InfoProposal>::format( Iter != WasmEdge::ProposalStr.end()) { fmt::format_to( std::back_inserter(Buffer), - " This instruction or syntax requires enabling proposal {}"sv, + " This instruction or syntax requires enabling {} proposal"sv, Iter->second); } else { fmt::format_to(std::back_inserter(Buffer), diff --git a/lib/common/hexstr.cpp b/lib/common/hexstr.cpp index 36ab7072bf69..d43407bc6765 100644 --- a/lib/common/hexstr.cpp +++ b/lib/common/hexstr.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/hexstr.h" diff --git a/lib/common/int128.cpp b/lib/common/int128.cpp deleted file mode 100644 index 919f9ac897a4..000000000000 --- a/lib/common/int128.cpp +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC - -#include "common/int128.h" - -#include <algorithm> -#include <cstdint> -#include <iomanip> -#include <limits> -#include <ostream> -#include <sstream> - -namespace WasmEdge { -static inline uint128_t mod(uint128_t LHS, uint128_t RHS) noexcept; -static inline uint128_t div(uint128_t LHS, uint128_t RHS) noexcept; - -// https://developercommunity.visualstudio.com/t/no-symbol-udivti3-in-clang-rtbuiltins-x86-64lib/1510286 -// uint128_t on MSVC clang has bugs. We can not use div and mod with uint128_t. - -#if defined(__clang__) && defined(_MSC_VER) -constexpr static inline uint64_t low(uint128_t Value) noexcept { - const uint128_t Mask = std::numeric_limits<uint64_t>::max(); - return Value & Mask; -} -constexpr static inline uint64_t high(uint128_t Value) noexcept { - return Value >> 64; -} -constexpr static inline uint32_t clz(uint128_t Value) noexcept { - uint64_t Hi = high(Value); - uint64_t Lo = low(Value); - - if (Hi) { - return uint32_t(__builtin_clzll(Hi)); - } - if (Lo) { - return uint32_t(__builtin_clzll(Lo) + 64); - } - return 128; -} - -static inline uint128_t mod(uint128_t LHS, uint128_t RHS) noexcept { - if (RHS > LHS) { - return LHS; - } - if (RHS == LHS) { - return 0; - } - uint128_t Denominator = RHS; - const unsigned int Shift = clz(RHS) - clz(LHS); - Denominator <<= Shift; - for (unsigned int I = 0; I <= Shift; ++I) { - if (LHS >= Denominator) { - LHS -= Denominator; - } - Denominator >>= 1U; - } - return LHS; -} - -static inline uint128_t div(uint128_t LHS, uint128_t RHS) noexcept { - if (RHS > LHS) { - return 0; - } - if (RHS == LHS) { - return 1; - } - uint128_t Denominator = RHS; - uint128_t Quotient = 0; - const unsigned int Shift = clz(RHS) - clz(LHS); - Denominator <<= Shift; - for (unsigned int I = 0; I <= Shift; ++I) { - Quotient <<= 1U; - if (LHS >= Denominator) { - LHS -= Denominator; - Quotient |= 1U; - } - Denominator >>= 1U; - } - return Quotient; -} - -#else -static inline uint128_t mod(uint128_t LHS, uint128_t RHS) noexcept { - return LHS % RHS; -} -static inline uint128_t div(uint128_t LHS, uint128_t RHS) noexcept { - return LHS / RHS; -} -#endif - -std::ostream &operator<<(std::ostream &OS, uint128_t Value) { - std::ostringstream Buf; - - if (Value <= uint128_t(std::numeric_limits<uint64_t>::max())) { - OS << uint64_t(Value); - return OS; - } - - // 2**128 < 3.5e38 < (1e13) ^3 - const uint64_t P10 = 10000000000000; - const uint64_t LEN = 13; /*Zeros in P10*/ - - uint64_t Lo, Mi, Hi; - Lo = uint64_t(mod(Value, P10)); - Value = div(Value, P10); - Mi = uint64_t(mod(Value, P10)); - Value = div(Value, P10); - Hi = uint64_t(Value); - - bool NeedLeadingZero = false; - - if (Hi) { - Buf << Hi; - NeedLeadingZero = true; - } - - if (Mi || NeedLeadingZero) { - if (NeedLeadingZero) { - Buf << std::setw(LEN) << std::setfill('0'); - } - Buf << Mi; - NeedLeadingZero = true; - } - - if (Lo || NeedLeadingZero) { - if (NeedLeadingZero) { - Buf << std::setw(LEN) << std::setfill('0'); - } - Buf << Lo; - NeedLeadingZero = true; - } - - return OS << Buf.str(); -} -} // namespace WasmEdge diff --git a/lib/common/log.cpp b/lib/common/spdlog.cpp similarity index 85% rename from lib/common/log.cpp rename to lib/common/spdlog.cpp index c3af5bfe8d06..2d5965b6a93c 100644 --- a/lib/common/log.cpp +++ b/lib/common/spdlog.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC -#include "common/log.h" +#include "common/spdlog.h" namespace WasmEdge { namespace Log { diff --git a/lib/driver/CMakeLists.txt b/lib/driver/CMakeLists.txt index 127366a67e34..bfe9e1a709d8 100644 --- a/lib/driver/CMakeLists.txt +++ b/lib/driver/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC set(SOURCES compilerTool.cpp @@ -24,7 +24,7 @@ if(WASMEDGE_BUILD_WASI_NN_RPC) ) endif() -if(WASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) target_link_libraries(wasmedgeDriver PRIVATE wasmedgeLoader @@ -32,6 +32,7 @@ if(WASMEDGE_BUILD_AOT_RUNTIME) wasmedgePO wasmedgeVM wasmedgeAOT + wasmedgeLLVM ) else() target_link_libraries(wasmedgeDriver @@ -43,9 +44,9 @@ else() ) endif() -if(WASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) target_compile_definitions(wasmedgeDriver PRIVATE - -DWASMEDGE_BUILD_AOT_RUNTIME + -DWASMEDGE_USE_LLVM ) endif() diff --git a/lib/driver/compilerTool.cpp b/lib/driver/compilerTool.cpp index 9d8b4a5d94ab..2292f840f135 100644 --- a/lib/driver/compilerTool.cpp +++ b/lib/driver/compilerTool.cpp @@ -1,7 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC -#include "aot/compiler.h" #include "common/configure.h" #include "common/defines.h" #include "common/filesystem.h" @@ -9,9 +8,10 @@ #include "driver/compiler.h" #include "loader/loader.h" #include "validator/validator.h" +#include "llvm/codegen.h" +#include "llvm/compiler.h" #include <cstdint> #include <cstdlib> -#include <iostream> #include <memory> #include <string> #include <utility> @@ -26,7 +26,7 @@ int Compiler([[maybe_unused]] struct DriverCompilerOptions &Opt) noexcept { std::ios::sync_with_stdio(false); Log::setInfoLoggingLevel(); -#ifdef WASMEDGE_BUILD_AOT_RUNTIME +#ifdef WASMEDGE_USE_LLVM Configure Conf; if (Opt.PropMutGlobals.value()) { @@ -50,6 +50,9 @@ int Compiler([[maybe_unused]] struct DriverCompilerOptions &Opt) noexcept { if (Opt.PropSIMD.value()) { Conf.removeProposal(Proposal::SIMD); } + if (Opt.PropRelaxedSIMD.value()) { + Conf.addProposal(Proposal::RelaxSIMD); + } if (Opt.PropMultiMem.value()) { Conf.addProposal(Proposal::MultiMemories); } @@ -154,11 +157,17 @@ int Compiler([[maybe_unused]] struct DriverCompilerOptions &Opt) noexcept { Conf.getCompilerConfigure().setOutputFormat( CompilerConfigure::OutputFormat::Native); } - AOT::Compiler Compiler(Conf); - if (auto Res = Compiler.compile(Data, *Module, OutputPath); !Res) { + LLVM::Compiler Compiler(Conf); + LLVM::CodeGen CodeGen(Conf); + if (auto Res = Compiler.compile(*Module); !Res) { const auto Err = static_cast<uint32_t>(Res.error()); spdlog::error("Compilation failed. Error code: {}", Err); return EXIT_FAILURE; + } else if (auto Res2 = CodeGen.codegen(Data, std::move(*Res), OutputPath); + !Res2) { + const auto Err = static_cast<uint32_t>(Res2.error()); + spdlog::error("Code Generation failed. Error code: {}", Err); + return EXIT_FAILURE; } } diff --git a/lib/driver/fuzzPO.cpp b/lib/driver/fuzzPO.cpp index ef50657e08c3..5accc4c977e3 100644 --- a/lib/driver/fuzzPO.cpp +++ b/lib/driver/fuzzPO.cpp @@ -1,19 +1,19 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifdef WASMEDGE_BUILD_FUZZING #include "driver/fuzzPO.h" -#include "common/log.h" +#include "common/spdlog.h" #include "common/version.h" #include "po/argument_parser.h" #include <algorithm> #include <array> #include <cstdio> -#include <iostream> #include <type_traits> #include <utility> #include <vector> + namespace { template <class Key, class Value, class Hash, class BinaryPredicate> class SkipTable { diff --git a/lib/driver/fuzzTool.cpp b/lib/driver/fuzzTool.cpp index 83ffcc8bcc89..8d21729aad13 100644 --- a/lib/driver/fuzzTool.cpp +++ b/lib/driver/fuzzTool.cpp @@ -1,12 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #ifdef WASMEDGE_BUILD_FUZZING #include "driver/fuzzTool.h" -#include "aot/compiler.h" #include "common/configure.h" #include "loader/loader.h" #include "validator/validator.h" +#include "llvm/codegen.h" +#include "llvm/compiler.h" namespace WasmEdge { namespace Driver { @@ -38,13 +39,18 @@ int FuzzTool(const uint8_t *Data, size_t Size) noexcept { } } - AOT::Compiler Compiler(Conf); - if (auto Res = Compiler.compile(Span<const uint8_t>(Data, Size), *Module, - "/dev/null"sv); - !Res) { + LLVM::Compiler Compiler(Conf); + LLVM::CodeGen CodeGen(Conf); + if (auto Res = Compiler.compile(*Module); !Res) { const auto Err = static_cast<uint32_t>(Res.error()); spdlog::error("Compilation failed. Error code: {}"sv, Err); return EXIT_FAILURE; + } else if (auto Res2 = CodeGen.codegen(Span<const uint8_t>(Data, Size), + std::move(*Res), "/dev/null"sv); + !Res2) { + const auto Err = static_cast<uint32_t>(Res2.error()); + spdlog::error("Code Generation failed. Error code: {}"sv, Err); + return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/lib/driver/runtimeTool.cpp b/lib/driver/runtimeTool.cpp index ccbf4db20339..069b2aa7fc29 100644 --- a/lib/driver/runtimeTool.cpp +++ b/lib/driver/runtimeTool.cpp @@ -1,9 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/configure.h" #include "common/filesystem.h" -#include "common/log.h" +#include "common/spdlog.h" #include "common/types.h" #include "common/version.h" #include "driver/tool.h" @@ -13,7 +13,6 @@ #include <chrono> #include <cstdint> #include <cstdlib> -#include <iostream> #include <optional> #include <string> #include <string_view> @@ -53,6 +52,9 @@ int Tool(struct DriverToolOptions &Opt) noexcept { if (Opt.PropSIMD.value()) { Conf.removeProposal(Proposal::SIMD); } + if (Opt.PropRelaxedSIMD.value()) { + Conf.addProposal(Proposal::RelaxSIMD); + } if (Opt.PropMultiMem.value()) { Conf.addProposal(Proposal::MultiMemories); } @@ -68,15 +70,27 @@ int Tool(struct DriverToolOptions &Opt) noexcept { if (Opt.PropFunctionReference.value()) { Conf.addProposal(Proposal::FunctionReferences); } + if (Opt.PropGC.value()) { + Conf.addProposal(Proposal::GC); + spdlog::warn("GC proposal is enabled, this is experimental."); + } if (Opt.PropComponent.value()) { Conf.addProposal(Proposal::Component); spdlog::warn("component model is enabled, this is experimental."); } + if (Opt.PropExceptionHandling.value()) { + Conf.addProposal(Proposal::ExceptionHandling); + } if (Opt.PropAll.value()) { Conf.addProposal(Proposal::MultiMemories); Conf.addProposal(Proposal::TailCall); Conf.addProposal(Proposal::ExtendedConst); Conf.addProposal(Proposal::Threads); + Conf.addProposal(Proposal::GC); + Conf.addProposal(Proposal::Component); + spdlog::warn("GC proposal is enabled, this is experimental."); + spdlog::warn("component model is enabled, this is experimental."); + Conf.addProposal(Proposal::ExceptionHandling); } std::optional<std::chrono::system_clock::time_point> Timeout; @@ -108,6 +122,11 @@ int Tool(struct DriverToolOptions &Opt) noexcept { Conf.getStatisticsConfigure().setTimeMeasuring(true); } } + if (Opt.ConfEnableJIT.value()) { + Conf.getRuntimeConfigure().setEnableJIT(true); + Conf.getCompilerConfigure().setOptimizationLevel( + WasmEdge::CompilerConfigure::OptimizationLevel::O1); + } if (Opt.ConfForceInterpreter.value()) { Conf.getRuntimeConfigure().setForceInterpreter(true); } @@ -185,8 +204,9 @@ int Tool(struct DriverToolOptions &Opt) noexcept { } else { // reactor mode if (Opt.Args.value().empty()) { - std::cerr - << "A function name is required when reactor mode is enabled.\n"; + fmt::print( + stderr, + "A function name is required when reactor mode is enabled.\n"sv); return EXIT_FAILURE; } const auto &FuncName = Opt.Args.value().front(); @@ -250,6 +270,12 @@ int Tool(struct DriverToolOptions &Opt) noexcept { FuncArgTypes.emplace_back(TypeCode::F64); break; } + case TypeCode::String: { + std::string &Value = Opt.Args.value()[I + 1]; + FuncArgs.emplace_back(StrVariant(std::move(Value))); + FuncArgTypes.emplace_back(TypeCode::String); + break; + } /// TODO: FuncRef and ExternRef default: break; @@ -276,19 +302,19 @@ int Tool(struct DriverToolOptions &Opt) noexcept { for (size_t I = 0; I < Result->size(); ++I) { switch ((*Result)[I].second.getCode()) { case TypeCode::I32: - std::cout << (*Result)[I].first.get<uint32_t>() << '\n'; + fmt::print("{}\n"sv, (*Result)[I].first.get<uint32_t>()); break; case TypeCode::I64: - std::cout << (*Result)[I].first.get<uint64_t>() << '\n'; + fmt::print("{}\n"sv, (*Result)[I].first.get<uint64_t>()); break; case TypeCode::F32: - std::cout << (*Result)[I].first.get<float>() << '\n'; + fmt::print("{}\n"sv, (*Result)[I].first.get<float>()); break; case TypeCode::F64: - std::cout << (*Result)[I].first.get<double>() << '\n'; + fmt::print("{}\n"sv, (*Result)[I].first.get<double>()); break; case TypeCode::V128: - std::cout << (*Result)[I].first.get<uint128_t>() << '\n'; + fmt::print("{}\n"sv, (*Result)[I].first.get<uint128_t>()); break; /// TODO: FuncRef and ExternRef default: diff --git a/lib/driver/uniTool.cpp b/lib/driver/uniTool.cpp index 03f4af7c3ccb..18ce6d3bcbbb 100644 --- a/lib/driver/uniTool.cpp +++ b/lib/driver/uniTool.cpp @@ -1,13 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "driver/unitool.h" -#include "common/log.h" +#include "common/spdlog.h" #include "driver/compiler.h" #include "driver/tool.h" #include "po/argument_parser.h" -#include <iostream> #include <string_view> namespace WasmEdge { @@ -52,13 +51,12 @@ int UniTool(int Argc, const char *Argv[], const ToolType ToolSelect) noexcept { return EXIT_FAILURE; } if (Parser.isVersion()) { - std::cout << Argv[0] << " version "sv << kVersionString << '\n'; + fmt::print("{} version {}\n"sv, Argv[0], kVersionString); for (const auto &Plugin : Plugin::Plugin::plugins()) { auto PluginVersion = Plugin.version(); - std::cout << Plugin.path().string() << " (plugin \""sv << Plugin.name() - << "\") version "sv << PluginVersion.Major << '.' - << PluginVersion.Minor << '.' << PluginVersion.Patch << '.' - << PluginVersion.Build << '\n'; + fmt::print("{} (plugin \"{}\") version {}.{}.{}.{}\n"sv, + Plugin.path().string(), Plugin.name(), PluginVersion.Major, + PluginVersion.Minor, PluginVersion.Patch, PluginVersion.Build); } return EXIT_SUCCESS; } diff --git a/lib/driver/wasiNNRPCServerTool.cpp b/lib/driver/wasiNNRPCServerTool.cpp index a760f06d9673..c3da46d8a59e 100644 --- a/lib/driver/wasiNNRPCServerTool.cpp +++ b/lib/driver/wasiNNRPCServerTool.cpp @@ -1,4 +1,4 @@ -#include "common/log.h" +#include "common/spdlog.h" #include "driver/wasi_nn_rpc/wasi_nn_rpcserver/wasi_nn_rpcserver.h" #include "plugin/plugin.h" #include "po/argument_parser.h" @@ -13,16 +13,10 @@ namespace WasmEdge { namespace Driver { void loadPlugins(void) { - for (const auto &Path : Plugin::Plugin::getDefaultPluginPaths()) { - spdlog::info("Loading plugin path {}"sv, Path); - if (Plugin::Plugin::load(Path)) { - spdlog::info("Loaded plugin path {}"sv, Path); - } else { - spdlog::info("Nothing was loaded from plugin path {}"sv, Path); - } - } + Plugin::Plugin::loadFromDefaultPaths(); for (const auto &Plugin : Plugin::Plugin::plugins()) { - spdlog::info("Plugin: {}", Plugin.name()); + spdlog::info("Loaded Plugin: {} from path: {}", Plugin.name(), + Plugin.path()); } } diff --git a/lib/executor/CMakeLists.txt b/lib/executor/CMakeLists.txt index 79c3b978fddf..39b38c674295 100644 --- a/lib/executor/CMakeLists.txt +++ b/lib/executor/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_library(wasmedgeExecutor instantiate/import.cpp @@ -11,12 +11,22 @@ wasmedge_add_library(wasmedgeExecutor instantiate/data.cpp instantiate/export.cpp instantiate/module.cpp + instantiate/component.cpp + instantiate/component/instantiate_component_alias.cpp + instantiate/component/instantiate_component_canon.cpp + instantiate/component/instantiate_component_export.cpp + instantiate/component/instantiate_component_import.cpp + instantiate/component/instantiate_component_instance.cpp + instantiate/component/instantiate_component_start.cpp + instantiate/component/instantiate_component_type.cpp + instantiate/tag.cpp engine/proxy.cpp engine/controlInstr.cpp engine/tableInstr.cpp engine/threadInstr.cpp engine/memoryInstr.cpp engine/variableInstr.cpp + engine/refInstr.cpp engine/engine.cpp helper.cpp executor.cpp diff --git a/lib/executor/engine/controlInstr.cpp b/lib/executor/engine/controlInstr.cpp index 1b18974f8b6d..53830e3d2eac 100644 --- a/lib/executor/engine/controlInstr.cpp +++ b/lib/executor/engine/controlInstr.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" @@ -33,12 +33,32 @@ Expect<void> Executor::runIfElseOp(Runtime::StackManager &StackMgr, return {}; } +Expect<void> Executor::runThrowOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept { + auto *TagInst = getTagInstByIdx(StackMgr, Instr.getTargetIndex()); + // The args will be popped from stack in the throw function. + return throwException(StackMgr, *TagInst, PC); +} + +Expect<void> Executor::runThrowRefOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept { + const auto Ref = StackMgr.pop().get<RefVariant>(); + if (Ref.isNull()) { + spdlog::error(ErrCode::Value::AccessNullException); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullException); + } + auto *TagInst = Ref.getPtr<Runtime::Instance::TagInstance>(); + return throwException(StackMgr, *TagInst, PC); +} + Expect<void> Executor::runBrOp(Runtime::StackManager &StackMgr, const AST::Instruction &Instr, AST::InstrView::iterator &PC) noexcept { - return branchToLabel(StackMgr, Instr.getJump().StackEraseBegin, - Instr.getJump().StackEraseEnd, Instr.getJump().PCOffset, - PC); + return branchToLabel(StackMgr, Instr.getJump(), PC); } Expect<void> Executor::runBrIfOp(Runtime::StackManager &StackMgr, @@ -50,9 +70,9 @@ Expect<void> Executor::runBrIfOp(Runtime::StackManager &StackMgr, return {}; } -Expect<void> Executor::runBrOnNull(Runtime::StackManager &StackMgr, - const AST::Instruction &Instr, - AST::InstrView::iterator &PC) noexcept { +Expect<void> Executor::runBrOnNullOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept { if (StackMgr.getTop().get<RefVariant>().isNull()) { StackMgr.pop(); return runBrOp(StackMgr, Instr, PC); @@ -60,9 +80,9 @@ Expect<void> Executor::runBrOnNull(Runtime::StackManager &StackMgr, return {}; } -Expect<void> Executor::runBrOnNonNull(Runtime::StackManager &StackMgr, - const AST::Instruction &Instr, - AST::InstrView::iterator &PC) noexcept { +Expect<void> Executor::runBrOnNonNullOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept { if (!StackMgr.getTop().get<RefVariant>().isNull()) { return runBrOp(StackMgr, Instr, PC); } @@ -80,13 +100,35 @@ Expect<void> Executor::runBrTableOp(Runtime::StackManager &StackMgr, auto LabelTable = Instr.getLabelList(); const auto LabelTableSize = static_cast<uint32_t>(LabelTable.size() - 1); if (Value < LabelTableSize) { - return branchToLabel(StackMgr, LabelTable[Value].StackEraseBegin, - LabelTable[Value].StackEraseEnd, - LabelTable[Value].PCOffset, PC); + return branchToLabel(StackMgr, LabelTable[Value], PC); } - return branchToLabel(StackMgr, LabelTable[LabelTableSize].StackEraseBegin, - LabelTable[LabelTableSize].StackEraseEnd, - LabelTable[LabelTableSize].PCOffset, PC); + return branchToLabel(StackMgr, LabelTable[LabelTableSize], PC); +} + +Expect<void> Executor::runBrOnCastOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC, + bool IsReverse) noexcept { + // Get value on top of stack. + const auto *ModInst = StackMgr.getModule(); + const auto &Val = StackMgr.getTop().get<RefVariant>(); + const auto &VT = Val.getType(); + Span<const AST::SubType *const> GotTypeList = ModInst->getTypeList(); + if (!VT.isAbsHeapType()) { + auto *Inst = Val.getPtr<Runtime::Instance::CompositeBase>(); + // Reference must not be nullptr here because the null references are typed + // with the least abstract heap type. + if (Inst->getModule()) { + GotTypeList = Inst->getModule()->getTypeList(); + } + } + + if (AST::TypeMatcher::matchType(ModInst->getTypeList(), + Instr.getBrCast().RType2, GotTypeList, + VT) != IsReverse) { + return branchToLabel(StackMgr, Instr.getBrCast().Jump, PC); + } + return {}; } Expect<void> Executor::runReturnOp(Runtime::StackManager &StackMgr, @@ -105,8 +147,7 @@ Expect<void> Executor::runCallOp(Runtime::StackManager &StackMgr, AST::InstrView::iterator &PC, bool IsTailCall) noexcept { // Get Function address. - const auto *ModInst = StackMgr.getModule(); - const auto *FuncInst = *ModInst->getFunc(Instr.getTargetIndex()); + const auto *FuncInst = getFuncInstByIdx(StackMgr, Instr.getTargetIndex()); if (auto Res = enterFunction(StackMgr, *FuncInst, PC + 1, IsTailCall); !Res) { return Unexpect(Res); } else { @@ -119,7 +160,6 @@ Expect<void> Executor::runCallRefOp(Runtime::StackManager &StackMgr, const AST::Instruction &Instr, AST::InstrView::iterator &PC, bool IsTailCall) noexcept { - const auto Ref = StackMgr.pop().get<RefVariant>(); if (Ref.isNull()) { spdlog::error(ErrCode::Value::AccessNullFunc); @@ -147,7 +187,7 @@ Expect<void> Executor::runCallIndirectOp(Runtime::StackManager &StackMgr, // Get function type at index x. const auto *ModInst = StackMgr.getModule(); - const auto *TargetFuncType = *ModInst->getFuncType(Instr.getTargetIndex()); + const auto &ExpDefType = **ModInst->getType(Instr.getTargetIndex()); // Pop the value i32.const i from the Stack. uint32_t Idx = StackMgr.pop().get<uint32_t>(); @@ -173,18 +213,28 @@ Expect<void> Executor::runCallIndirectOp(Runtime::StackManager &StackMgr, // Check function type. const auto *FuncInst = retrieveFuncRef(Ref); - const auto &FuncType = FuncInst->getFuncType(); - if (!matchTypes(*ModInst, TargetFuncType->getParamTypes(), - *FuncInst->getModule(), FuncType.getParamTypes()) || - !matchTypes(*ModInst, TargetFuncType->getReturnTypes(), - *FuncInst->getModule(), FuncType.getReturnTypes())) { + bool IsMatch = false; + if (FuncInst->getModule()) { + IsMatch = AST::TypeMatcher::matchType( + ModInst->getTypeList(), *ExpDefType.getTypeIndex(), + FuncInst->getModule()->getTypeList(), FuncInst->getTypeIndex()); + } else { + // Independent host module instance case. Matching the composite type + // directly. + IsMatch = AST::TypeMatcher::matchType( + ModInst->getTypeList(), ExpDefType.getCompositeType(), + FuncInst->getHostFunc().getDefinedType().getCompositeType()); + } + if (!IsMatch) { + auto &ExpFuncType = ExpDefType.getCompositeType().getFuncType(); + auto &GotFuncType = FuncInst->getFuncType(); spdlog::error(ErrCode::Value::IndirectCallTypeMismatch); spdlog::error(ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset(), {Idx}, {ValTypeFromType<uint32_t>()})); spdlog::error(ErrInfo::InfoMismatch( - TargetFuncType->getParamTypes(), TargetFuncType->getReturnTypes(), - FuncType.getParamTypes(), FuncType.getReturnTypes())); + ExpFuncType.getParamTypes(), ExpFuncType.getReturnTypes(), + GotFuncType.getParamTypes(), GotFuncType.getReturnTypes())); return Unexpect(ErrCode::Value::IndirectCallTypeMismatch); } @@ -197,5 +247,13 @@ Expect<void> Executor::runCallIndirectOp(Runtime::StackManager &StackMgr, return {}; } +Expect<void> Executor::runTryTableOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept { + const auto &TryDesc = Instr.getTryCatch(); + StackMgr.pushHandler(PC, TryDesc.BlockParamNum, TryDesc.Catch); + return {}; +} + } // namespace Executor } // namespace WasmEdge diff --git a/lib/executor/engine/engine.cpp b/lib/executor/engine/engine.cpp index 358624cea668..2de6bef2924d 100644 --- a/lib/executor/engine/engine.cpp +++ b/lib/executor/engine/engine.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" @@ -28,8 +28,18 @@ Executor::runFunction(Runtime::StackManager &StackMgr, StackMgr.pushFrame(nullptr, AST::InstrView::iterator(), 0, 0); // Push arguments. - for (auto &Val : Params) { - StackMgr.push(Val); + const auto &PTypes = Func.getFuncType().getParamTypes(); + for (uint32_t I = 0; I < Params.size(); I++) { + // For the references, transform to non-null reference type if the value not + // null. + if (PTypes[I].isRefType() && Params[I].get<RefVariant>().getPtr<void>() && + Params[I].get<RefVariant>().getType().isNullableRefType()) { + auto Val = Params[I]; + Val.get<RefVariant>().getType().toNonNullableRef(); + StackMgr.push(Val); + } else { + StackMgr.push(Params[I]); + } } // Enter and execute function. @@ -85,6 +95,16 @@ Expect<void> Executor::execute(Runtime::StackManager &StackMgr, auto Dispatch = [this, &PC, &StackMgr]() -> Expect<void> { const AST::Instruction &Instr = *PC; + + auto GetDstCompType = [&StackMgr, &Instr, this]() { + return getDefTypeByIdx(StackMgr, Instr.getTargetIndex()) + ->getCompositeType(); + }; + auto GetSrcCompType = [&StackMgr, &Instr, this]() { + return getDefTypeByIdx(StackMgr, Instr.getSourceIndex()) + ->getCompositeType(); + }; + switch (Instr.getOpCode()) { // Control instructions. case OpCode::Unreachable: @@ -116,11 +136,18 @@ Expect<void> Executor::execute(Runtime::StackManager &StackMgr, return Unexpect(ErrCode::Value::CostLimitExceeded); } } - PC += PC->getJumpEnd(); - [[fallthrough]]; + PC += PC->getJumpEnd() - 1; + return {}; case OpCode::End: - PC = StackMgr.maybePopFrame(PC); + PC = StackMgr.maybePopFrameOrHandler(PC); return {}; + // LEGACY-EH: remove the `Try` cases after deprecating legacy EH. + case OpCode::Try: + return runTryTableOp(StackMgr, Instr, PC); + case OpCode::Throw: + return runThrowOp(StackMgr, Instr, PC); + case OpCode::Throw_ref: + return runThrowRefOp(StackMgr, Instr, PC); case OpCode::Br: return runBrOp(StackMgr, Instr, PC); case OpCode::Br_if: @@ -128,9 +155,13 @@ Expect<void> Executor::execute(Runtime::StackManager &StackMgr, case OpCode::Br_table: return runBrTableOp(StackMgr, Instr, PC); case OpCode::Br_on_null: - return runBrOnNull(StackMgr, Instr, PC); + return runBrOnNullOp(StackMgr, Instr, PC); case OpCode::Br_on_non_null: - return runBrOnNonNull(StackMgr, Instr, PC); + return runBrOnNonNullOp(StackMgr, Instr, PC); + case OpCode::Br_on_cast: + return runBrOnCastOp(StackMgr, Instr, PC); + case OpCode::Br_on_cast_fail: + return runBrOnCastOp(StackMgr, Instr, PC, true); case OpCode::Return: return runReturnOp(StackMgr, PC); case OpCode::Call: @@ -145,34 +176,132 @@ Expect<void> Executor::execute(Runtime::StackManager &StackMgr, return runCallRefOp(StackMgr, Instr, PC); case OpCode::Return_call_ref: return runCallRefOp(StackMgr, Instr, PC, true); + // LEGACY-EH: remove the `Catch` cases after deprecating legacy EH. + case OpCode::Catch: + case OpCode::Catch_all: + PC -= Instr.getCatchLegacy().CatchPCOffset; + PC += PC->getTryCatch().JumpEnd; + return {}; + case OpCode::Try_table: + return runTryTableOp(StackMgr, Instr, PC); // Reference Instructions case OpCode::Ref__null: - StackMgr.push(RefVariant(Instr.getValType())); - return {}; - case OpCode::Ref__is_null: { - ValVariant &Val = StackMgr.getTop(); - if (Val.get<RefVariant>().isNull()) { - Val.emplace<uint32_t>(UINT32_C(1)); - } else { - Val.emplace<uint32_t>(UINT32_C(0)); - } - return {}; - } - case OpCode::Ref__func: { - const auto *ModInst = StackMgr.getModule(); - const auto *FuncInst = *ModInst->getFunc(Instr.getTargetIndex()); - StackMgr.push(RefVariant(FuncInst)); - return {}; + return runRefNullOp(StackMgr, Instr.getValType()); + case OpCode::Ref__is_null: + return runRefIsNullOp(StackMgr.getTop()); + case OpCode::Ref__func: + return runRefFuncOp(StackMgr, Instr.getTargetIndex()); + case OpCode::Ref__eq: { + ValVariant Rhs = StackMgr.pop(); + return runRefEqOp(StackMgr.getTop(), Rhs); } case OpCode::Ref__as_non_null: - if (StackMgr.getTop().get<RefVariant>().isNull()) { - spdlog::error(ErrCode::Value::CastNullToNonNull); - spdlog::error( - ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); - return Unexpect(ErrCode::Value::CastNullToNonNull); - } - return {}; + return runRefAsNonNullOp(StackMgr.getTop().get<RefVariant>(), Instr); + + // GC Instructions + case OpCode::Struct__new: + return runStructNewOp(StackMgr, Instr.getTargetIndex()); + case OpCode::Struct__new_default: + return runStructNewOp(StackMgr, Instr.getTargetIndex(), true); + case OpCode::Struct__get: + case OpCode::Struct__get_u: + return runStructGetOp(StackMgr.getTop(), Instr.getSourceIndex(), + GetDstCompType(), Instr); + case OpCode::Struct__get_s: + return runStructGetOp(StackMgr.getTop(), Instr.getSourceIndex(), + GetDstCompType(), Instr, true); + case OpCode::Struct__set: { + const ValVariant Val = StackMgr.pop(); + RefVariant StructRef = StackMgr.pop().get<RefVariant>(); + return runStructSetOp(Val, StructRef, GetDstCompType(), + Instr.getSourceIndex(), Instr); + } + case OpCode::Array__new: + return runArrayNewOp(StackMgr, Instr.getTargetIndex(), 1, + StackMgr.pop().get<uint32_t>()); + case OpCode::Array__new_default: + return runArrayNewOp(StackMgr, Instr.getTargetIndex(), 0, + StackMgr.pop().get<uint32_t>()); + case OpCode::Array__new_fixed: + return runArrayNewOp(StackMgr, Instr.getTargetIndex(), + Instr.getSourceIndex(), Instr.getSourceIndex()); + case OpCode::Array__new_data: + return runArrayNewDataOp( + StackMgr, *getDataInstByIdx(StackMgr, Instr.getSourceIndex()), Instr); + case OpCode::Array__new_elem: + return runArrayNewElemOp( + StackMgr, *getElemInstByIdx(StackMgr, Instr.getSourceIndex()), Instr); + case OpCode::Array__get: + case OpCode::Array__get_u: { + const uint32_t Idx = StackMgr.pop().get<uint32_t>(); + return runArrayGetOp(StackMgr.getTop(), Idx, GetDstCompType(), Instr); + } + case OpCode::Array__get_s: { + const uint32_t Idx = StackMgr.pop().get<uint32_t>(); + return runArrayGetOp(StackMgr.getTop(), Idx, GetDstCompType(), Instr, + true); + } + case OpCode::Array__set: { + ValVariant Val = StackMgr.pop(); + const uint32_t Idx = StackMgr.pop().get<uint32_t>(); + RefVariant ArrayRef = StackMgr.pop().get<RefVariant>(); + return runArraySetOp(Val, Idx, ArrayRef, GetDstCompType(), Instr); + } + case OpCode::Array__len: + return runArrayLenOp(StackMgr.getTop(), Instr); + case OpCode::Array__fill: { + const uint32_t N = StackMgr.pop().get<uint32_t>(); + const ValVariant Val = StackMgr.pop(); + const uint32_t D = StackMgr.pop().get<uint32_t>(); + RefVariant ArrayRef = StackMgr.pop().get<RefVariant>(); + return runArrayFillOp(N, Val, D, ArrayRef, GetDstCompType(), Instr); + } + case OpCode::Array__copy: { + const uint32_t N = StackMgr.pop().get<uint32_t>(); + const uint32_t S = StackMgr.pop().get<uint32_t>(); + RefVariant SrcArrayRef = StackMgr.pop().get<RefVariant>(); + const uint32_t D = StackMgr.pop().get<uint32_t>(); + RefVariant DstArrayRef = StackMgr.pop().get<RefVariant>(); + return runArrayCopyOp(N, S, SrcArrayRef, D, DstArrayRef, GetSrcCompType(), + GetDstCompType(), Instr); + } + case OpCode::Array__init_data: { + const uint32_t N = StackMgr.pop().get<uint32_t>(); + const uint32_t S = StackMgr.pop().get<uint32_t>(); + const uint32_t D = StackMgr.pop().get<uint32_t>(); + RefVariant ArrayRef = StackMgr.pop().get<RefVariant>(); + return runArrayInitDataOp( + N, S, D, ArrayRef, GetDstCompType(), + *getDataInstByIdx(StackMgr, Instr.getSourceIndex()), Instr); + } + case OpCode::Array__init_elem: { + const uint32_t N = StackMgr.pop().get<uint32_t>(); + const uint32_t S = StackMgr.pop().get<uint32_t>(); + const uint32_t D = StackMgr.pop().get<uint32_t>(); + RefVariant ArrayRef = StackMgr.pop().get<RefVariant>(); + return runArrayInitElemOp( + N, S, D, ArrayRef, GetDstCompType(), + *getElemInstByIdx(StackMgr, Instr.getSourceIndex()), Instr); + } + case OpCode::Ref__test: + case OpCode::Ref__test_null: + return runRefTestOp(StackMgr.getModule(), StackMgr.getTop(), Instr); + case OpCode::Ref__cast: + case OpCode::Ref__cast_null: + return runRefTestOp(StackMgr.getModule(), StackMgr.getTop(), Instr, true); + case OpCode::Any__convert_extern: + return runRefConvOp(StackMgr.getTop().get<RefVariant>(), + TypeCode::AnyRef); + case OpCode::Extern__convert_any: + return runRefConvOp(StackMgr.getTop().get<RefVariant>(), + TypeCode::ExternRef); + case OpCode::Ref__i31: + return runRefI31Op(StackMgr.getTop()); + case OpCode::I31__get_s: + return runI31GetOp(StackMgr.getTop(), Instr, true); + case OpCode::I31__get_u: + return runI31GetOp(StackMgr.getTop(), Instr); // Parametric Instructions case OpCode::Drop: @@ -1696,6 +1825,112 @@ Expect<void> Executor::execute(Runtime::StackManager &StackMgr, case OpCode::F64x2__nearest: return runVectorNearestOp<double>(StackMgr.getTop()); + // Relaxed SIMD + case OpCode::I8x16__relaxed_swizzle: { + const ValVariant Val2 = StackMgr.pop(); + ValVariant &Val1 = StackMgr.getTop(); + const uint8x16_t &Index = Val2.get<uint8x16_t>(); + uint8x16_t &Vector = Val1.get<uint8x16_t>(); + uint8x16_t Result{}; + for (size_t I = 0; I < 16; ++I) { + const uint8_t SwizzleIndex = Index[I]; + if (SwizzleIndex < 16) { + Result[I] = Vector[SwizzleIndex]; + } else { + Result[I] = 0; + } + } + Vector = Result; + return {}; + } + case OpCode::I32x4__relaxed_trunc_f32x4_s: + return runVectorTruncSatOp<float, int32_t>(StackMgr.getTop()); + case OpCode::I32x4__relaxed_trunc_f32x4_u: + return runVectorTruncSatOp<float, uint32_t>(StackMgr.getTop()); + case OpCode::I32x4__relaxed_trunc_f64x2_s_zero: + return runVectorTruncSatOp<double, int32_t>(StackMgr.getTop()); + case OpCode::I32x4__relaxed_trunc_f64x2_u_zero: + return runVectorTruncSatOp<double, uint32_t>(StackMgr.getTop()); + case OpCode::F32x4__relaxed_madd: { + const ValVariant Val3 = StackMgr.pop(); + const ValVariant Val2 = StackMgr.pop(); + runVectorMulOp<float>(StackMgr.getTop(), Val2); + return runVectorAddOp<float>(StackMgr.getTop(), Val3); + } + case OpCode::F32x4__relaxed_nmadd: { + const ValVariant Val3 = StackMgr.pop(); + const ValVariant Val2 = StackMgr.pop(); + runVectorNegOp<float>(StackMgr.getTop()); + runVectorMulOp<float>(StackMgr.getTop(), Val2); + return runVectorAddOp<float>(StackMgr.getTop(), Val3); + } + case OpCode::F64x2__relaxed_madd: { + const ValVariant Val3 = StackMgr.pop(); + const ValVariant Val2 = StackMgr.pop(); + runVectorMulOp<double>(StackMgr.getTop(), Val2); + return runVectorAddOp<double>(StackMgr.getTop(), Val3); + } + case OpCode::F64x2__relaxed_nmadd: { + const ValVariant Val3 = StackMgr.pop(); + const ValVariant Val2 = StackMgr.pop(); + runVectorMulOp<double>(StackMgr.getTop(), Val2); + runVectorNegOp<double>(StackMgr.getTop()); + return runVectorAddOp<double>(StackMgr.getTop(), Val3); + } + case OpCode::I8x16__relaxed_laneselect: { + const ValVariant Mask = StackMgr.pop(); + const ValVariant Val2 = StackMgr.pop(); + return runVectorRelaxedLaneselectOp<uint8_t>(StackMgr.getTop(), Val2, + Mask); + } + case OpCode::I16x8__relaxed_laneselect: { + const ValVariant Mask = StackMgr.pop(); + const ValVariant Val2 = StackMgr.pop(); + return runVectorRelaxedLaneselectOp<uint16_t>(StackMgr.getTop(), Val2, + Mask); + } + case OpCode::I32x4__relaxed_laneselect: { + const ValVariant Mask = StackMgr.pop(); + const ValVariant Val2 = StackMgr.pop(); + return runVectorRelaxedLaneselectOp<uint32_t>(StackMgr.getTop(), Val2, + Mask); + } + case OpCode::I64x2__relaxed_laneselect: { + const ValVariant Mask = StackMgr.pop(); + const ValVariant Val2 = StackMgr.pop(); + return runVectorRelaxedLaneselectOp<uint64_t>(StackMgr.getTop(), Val2, + Mask); + } + case OpCode::F32x4__relaxed_min: { + const ValVariant Val2 = StackMgr.pop(); + return runVectorFMinOp<float>(StackMgr.getTop(), Val2); + } + case OpCode::F32x4__relaxed_max: { + const ValVariant Val2 = StackMgr.pop(); + return runVectorFMaxOp<float>(StackMgr.getTop(), Val2); + } + case OpCode::F64x2__relaxed_min: { + const ValVariant Val2 = StackMgr.pop(); + return runVectorFMinOp<double>(StackMgr.getTop(), Val2); + } + case OpCode::F64x2__relaxed_max: { + const ValVariant Val2 = StackMgr.pop(); + return runVectorFMaxOp<double>(StackMgr.getTop(), Val2); + } + case OpCode::I16x8__relaxed_q15mulr_s: { + ValVariant Rhs = StackMgr.pop(); + return runVectorQ15MulSatOp(StackMgr.getTop(), Rhs); + } + case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s: { + ValVariant Rhs = StackMgr.pop(); + return runVectorRelaxedIntegerDotProductOp(StackMgr.getTop(), Rhs); + } + case OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s: { + ValVariant C = StackMgr.pop(); + ValVariant Rhs = StackMgr.pop(); + return runVectorRelaxedIntegerDotProductOpAdd(StackMgr.getTop(), Rhs, C); + } + // Threads instructions case OpCode::Atomic__fence: return runMemoryFenceOp(); diff --git a/lib/executor/engine/memoryInstr.cpp b/lib/executor/engine/memoryInstr.cpp index 682970297e6e..6a97886d63e8 100644 --- a/lib/executor/engine/memoryInstr.cpp +++ b/lib/executor/engine/memoryInstr.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" diff --git a/lib/executor/engine/proxy.cpp b/lib/executor/engine/proxy.cpp index c2ede34f09b8..4149e45173a9 100644 --- a/lib/executor/engine/proxy.cpp +++ b/lib/executor/engine/proxy.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" #include "system/fault.h" @@ -18,11 +18,7 @@ struct Executor::ProxyHelper<Expect<RetT> (Executor::*)(Runtime::StackManager &, ArgsT...) noexcept> { template <Expect<RetT> (Executor::*Func)(Runtime::StackManager &, ArgsT...) noexcept> - static auto proxy(ArgsT... Args) -#if !WASMEDGE_OS_WINDOWS - noexcept -#endif - { + static auto proxy(ArgsT... Args) { Expect<RetT> Res = (This->*Func)(*CurrentStack, Args...); if (unlikely(!Res)) { Fault::emitFault(Res.error()); @@ -45,14 +41,14 @@ struct Executor::ProxyHelper<Expect<RetT> (Executor::*)(Runtime::StackManager &, #endif // Intrinsics table -const AST::Module::IntrinsicsTable Executor::Intrinsics = { +const Executable::IntrinsicsTable Executor::Intrinsics = { #if defined(_MSC_VER) && !defined(__clang__) #define ENTRY(NAME, FUNC) \ reinterpret_cast<void *>(&Executor::ProxyHelper< \ decltype(&Executor::FUNC)>::proxy<&Executor::FUNC>) #else #define ENTRY(NAME, FUNC) \ - [uint8_t(AST::Module::Intrinsics::NAME)] = reinterpret_cast<void *>( \ + [uint8_t(Executable::Intrinsics::NAME)] = reinterpret_cast<void *>( \ &Executor::ProxyHelper<decltype(&Executor::FUNC)>::proxy< \ &Executor::FUNC>) #endif @@ -142,15 +138,22 @@ Expect<void *> Executor::tableGetFuncSymbol(Runtime::StackManager &StackMgr, const auto *ModInst = StackMgr.getModule(); assuming(ModInst); - const auto TargetFuncType = ModInst->getFuncType(FuncTypeIdx); - assuming(TargetFuncType && *TargetFuncType); + const auto &ExpDefType = **ModInst->getType(FuncTypeIdx); const auto *FuncInst = retrieveFuncRef(*Ref); assuming(FuncInst); - const auto &FuncType = FuncInst->getFuncType(); - if (!matchTypes(*ModInst, (*TargetFuncType)->getParamTypes(), - *FuncInst->getModule(), FuncType.getParamTypes()) || - !matchTypes(*ModInst, (*TargetFuncType)->getReturnTypes(), - *FuncInst->getModule(), FuncType.getReturnTypes())) { + bool IsMatch = false; + if (FuncInst->getModule()) { + IsMatch = AST::TypeMatcher::matchType( + ModInst->getTypeList(), *ExpDefType.getTypeIndex(), + FuncInst->getModule()->getTypeList(), FuncInst->getTypeIndex()); + } else { + // Independent host module instance case. Matching the composite type + // directly. + IsMatch = AST::TypeMatcher::matchType( + ModInst->getTypeList(), ExpDefType.getCompositeType(), + FuncInst->getHostFunc().getDefinedType().getCompositeType()); + } + if (!IsMatch) { return Unexpect(ErrCode::Value::IndirectCallTypeMismatch); } @@ -180,15 +183,26 @@ Executor::callIndirect(Runtime::StackManager &StackMgr, const uint32_t TableIdx, const auto *ModInst = StackMgr.getModule(); assuming(ModInst); - const auto TargetFuncType = ModInst->getFuncType(FuncTypeIdx); - assuming(TargetFuncType && *TargetFuncType); + const auto &ExpDefType = **ModInst->getType(FuncTypeIdx); const auto *FuncInst = retrieveFuncRef(*Ref); assuming(FuncInst); - const auto &FuncType = FuncInst->getFuncType(); - if (unlikely(**TargetFuncType != FuncType)) { + bool IsMatch = false; + if (FuncInst->getModule()) { + IsMatch = AST::TypeMatcher::matchType( + ModInst->getTypeList(), *ExpDefType.getTypeIndex(), + FuncInst->getModule()->getTypeList(), FuncInst->getTypeIndex()); + } else { + // Independent host module instance case. Matching the composite type + // directly. + IsMatch = AST::TypeMatcher::matchType( + ModInst->getTypeList(), ExpDefType.getCompositeType(), + FuncInst->getHostFunc().getDefinedType().getCompositeType()); + } + if (!IsMatch) { return Unexpect(ErrCode::Value::IndirectCallTypeMismatch); } + const auto &FuncType = FuncInst->getFuncType(); const uint32_t ParamsSize = static_cast<uint32_t>(FuncType.getParamTypes().size()); const uint32_t ReturnsSize = diff --git a/lib/executor/engine/refInstr.cpp b/lib/executor/engine/refInstr.cpp new file mode 100644 index 000000000000..d2374e564e6d --- /dev/null +++ b/lib/executor/engine/refInstr.cpp @@ -0,0 +1,576 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "executor/executor.h" + +namespace WasmEdge { +namespace Executor { + +namespace { +ValVariant packVal(const ValType &Type, const ValVariant &Val) { + if (Type.isPackType()) { + switch (Type.getCode()) { + case TypeCode::I8: + return ValVariant(Val.get<uint32_t>() & 0xFFU); + case TypeCode::I16: + return ValVariant(Val.get<uint32_t>() & 0xFFFFU); + default: + assumingUnreachable(); + } + } + return Val; +} + +ValVariant unpackVal(const ValType &Type, const ValVariant &Val, + bool IsSigned = false) { + if (Type.isPackType()) { + uint32_t Num = Val.get<uint32_t>(); + switch (Type.getCode()) { + case TypeCode::I8: + if (IsSigned) { + return static_cast<uint32_t>(static_cast<int8_t>(Num)); + } else { + return static_cast<uint32_t>(static_cast<uint8_t>(Num)); + } + case TypeCode::I16: + if (IsSigned) { + return static_cast<uint32_t>(static_cast<int16_t>(Num)); + } else { + return static_cast<uint32_t>(static_cast<uint16_t>(Num)); + } + default: + assumingUnreachable(); + } + } + return Val; +} + +std::vector<ValVariant> packVals(const ValType &Type, + std::vector<ValVariant> &&Vals) { + for (uint32_t I = 0; I < Vals.size(); I++) { + Vals[I] = packVal(Type, Vals[I]); + } + return std::move(Vals); +} +} // namespace + +Expect<void> Executor::runRefNullOp(Runtime::StackManager &StackMgr, + const ValType &Type) const noexcept { + // A null reference is typed with the least type in its respective hierarchy. + StackMgr.push(RefVariant(toBottomType(StackMgr, Type))); + return {}; +} + +Expect<void> Executor::runRefIsNullOp(ValVariant &Val) const noexcept { + Val.emplace<uint32_t>(Val.get<RefVariant>().isNull() ? 1U : 0U); + return {}; +} + +Expect<void> Executor::runRefFuncOp(Runtime::StackManager &StackMgr, + uint32_t Idx) const noexcept { + const auto *FuncInst = getFuncInstByIdx(StackMgr, Idx); + StackMgr.push(RefVariant(FuncInst->getDefType(), FuncInst)); + return {}; +} + +Expect<void> Executor::runRefEqOp(ValVariant &Val1, + const ValVariant &Val2) const noexcept { + Val1.emplace<uint32_t>(Val1.get<RefVariant>().getPtr<void>() == + Val2.get<RefVariant>().getPtr<void>() + ? 1U + : 0U); + return {}; +} + +Expect<void> +Executor::runRefAsNonNullOp(RefVariant &Ref, + const AST::Instruction &Instr) const noexcept { + if (Ref.isNull()) { + spdlog::error(ErrCode::Value::CastNullToNonNull); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::CastNullToNonNull); + } + Ref.getType().toNonNullableRef(); + return {}; +} + +Expect<void> Executor::runStructNewOp(Runtime::StackManager &StackMgr, + const uint32_t DefIndex, + bool IsDefault) const noexcept { + /// TODO: The array and struct instances are owned by the module instance + /// currently because of referring the defined types of the module instances. + /// This may be changed after applying the garbage collection mechanism. + const auto &CompType = + getDefTypeByIdx(StackMgr, DefIndex)->getCompositeType(); + uint32_t N = static_cast<uint32_t>(CompType.getFieldTypes().size()); + std::vector<WasmEdge::ValVariant> Vals; + if (IsDefault) { + Vals.resize(N); + for (uint32_t I = 0; I < N; I++) { + const auto &VType = CompType.getFieldTypes()[I].getStorageType(); + Vals[I] = VType.isRefType() + ? ValVariant(RefVariant(toBottomType(StackMgr, VType))) + : ValVariant(static_cast<uint128_t>(0)); + } + } else { + Vals = StackMgr.pop(N); + for (uint32_t I = 0; I < N; I++) { + Vals[I] = packVal(CompType.getFieldTypes()[I].getStorageType(), Vals[I]); + } + } + auto *Inst = + const_cast<Runtime::Instance::ModuleInstance *>(StackMgr.getModule()) + ->newStruct(DefIndex, std::move(Vals)); + StackMgr.push(RefVariant(Inst->getDefType(), Inst)); + + return {}; +} + +Expect<void> Executor::runStructGetOp(ValVariant &Val, const uint32_t Idx, + const AST::CompositeType &CompType, + const AST::Instruction &Instr, + bool IsSigned) const noexcept { + const auto *Inst = + Val.get<RefVariant>().getPtr<Runtime::Instance::StructInstance>(); + if (Inst == nullptr) { + spdlog::error(ErrCode::Value::AccessNullStruct); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullStruct); + } + const auto &SType = CompType.getFieldTypes()[Idx].getStorageType(); + Val = unpackVal(SType, Inst->getField(Idx), IsSigned); + return {}; +} + +Expect<void> +Executor::runStructSetOp(const ValVariant &Val, const RefVariant &InstRef, + const AST::CompositeType &CompType, uint32_t Idx, + const AST::Instruction &Instr) const noexcept { + auto *Inst = InstRef.getPtr<Runtime::Instance::StructInstance>(); + if (Inst == nullptr) { + spdlog::error(ErrCode::Value::AccessNullStruct); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullStruct); + } + const auto &SType = CompType.getFieldTypes()[Idx].getStorageType(); + Inst->getField(Idx) = packVal(SType, Val); + return {}; +} + +Expect<void> Executor::runArrayNewOp(Runtime::StackManager &StackMgr, + const uint32_t DefIndex, uint32_t InitCnt, + uint32_t ValCnt) const noexcept { + /// TODO: The array and struct instances are owned by the module instance + /// currently because of referring the defined types of the module instances. + /// This may be changed after applying the garbage collection mechanism. + assuming(InitCnt == 0 || InitCnt == 1 || InitCnt == ValCnt); + const auto &CompType = + getDefTypeByIdx(StackMgr, DefIndex)->getCompositeType(); + const auto &VType = CompType.getFieldTypes()[0].getStorageType(); + if (InitCnt == 0) { + auto InitVal = VType.isRefType() + ? ValVariant(RefVariant(toBottomType(StackMgr, VType))) + : ValVariant(static_cast<uint128_t>(0)); + auto *Inst = + const_cast<Runtime::Instance::ModuleInstance *>(StackMgr.getModule()) + ->newArray(DefIndex, ValCnt, InitVal); + StackMgr.push(RefVariant(Inst->getDefType(), Inst)); + } else if (InitCnt == 1) { + auto *Inst = + const_cast<Runtime::Instance::ModuleInstance *>(StackMgr.getModule()) + ->newArray(DefIndex, ValCnt, packVal(VType, StackMgr.getTop())); + StackMgr.getTop().emplace<RefVariant>(Inst->getDefType(), Inst); + } else { + auto *Inst = + const_cast<Runtime::Instance::ModuleInstance *>(StackMgr.getModule()) + ->newArray(DefIndex, packVals(VType, StackMgr.pop(ValCnt))); + StackMgr.push(RefVariant(Inst->getDefType(), Inst)); + } + return {}; +} + +Expect<void> +Executor::runArrayNewDataOp(Runtime::StackManager &StackMgr, + const Runtime::Instance::DataInstance &DataInst, + const AST::Instruction &Instr) const noexcept { + const uint32_t N = StackMgr.pop().get<uint32_t>(); + const uint32_t S = StackMgr.getTop().get<uint32_t>(); + const auto &CompType = + getDefTypeByIdx(StackMgr, Instr.getTargetIndex())->getCompositeType(); + const uint32_t BSize = + CompType.getFieldTypes()[0].getStorageType().getBitWidth() / 8; + if (static_cast<uint64_t>(S) + static_cast<uint64_t>(N) * BSize > + DataInst.getData().size()) { + spdlog::error(ErrCode::Value::MemoryOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary( + static_cast<uint64_t>(S), N * BSize, + DataInst.getData().size() > 0 + ? static_cast<uint32_t>(DataInst.getData().size() - 1) + : 0U)); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::MemoryOutOfBounds); + } + /// TODO: The array and struct instances are owned by the module instance + /// currently because of referring the defined types of the module instances. + /// This may be changed after applying the garbage collection mechanism. + auto *Inst = + const_cast<Runtime::Instance::ModuleInstance *>(StackMgr.getModule()) + ->newArray(Instr.getTargetIndex(), N, 0U); + for (uint32_t Idx = 0; Idx < N; Idx++) { + // The value has been packed. + Inst->getData(Idx) = DataInst.loadValue(S + Idx * BSize, BSize); + } + StackMgr.getTop().emplace<RefVariant>(Inst->getDefType(), Inst); + return {}; +} + +Expect<void> +Executor::runArrayNewElemOp(Runtime::StackManager &StackMgr, + const Runtime::Instance::ElementInstance &ElemInst, + const AST::Instruction &Instr) const noexcept { + const uint32_t N = StackMgr.pop().get<uint32_t>(); + const uint32_t S = StackMgr.getTop().get<uint32_t>(); + const auto &CompType = + getDefTypeByIdx(StackMgr, Instr.getTargetIndex())->getCompositeType(); + const auto &SType = CompType.getFieldTypes()[0].getStorageType(); + auto ElemSrc = ElemInst.getRefs(); + if (static_cast<uint64_t>(S) + static_cast<uint64_t>(N) > ElemSrc.size()) { + spdlog::error(ErrCode::Value::TableOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary( + static_cast<uint64_t>(S), N, + ElemSrc.size() > 0 ? static_cast<uint32_t>(ElemSrc.size() - 1) : 0U)); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::TableOutOfBounds); + } + std::vector<ValVariant> Refs(ElemSrc.begin() + S, ElemSrc.begin() + S + N); + /// TODO: The array and struct instances are owned by the module instance + /// currently because of referring the defined types of the module instances. + /// This may be changed after applying the garbage collection mechanism. + auto *Inst = + const_cast<Runtime::Instance::ModuleInstance *>(StackMgr.getModule()) + ->newArray(Instr.getTargetIndex(), packVals(SType, std::move(Refs))); + StackMgr.getTop().emplace<RefVariant>(Inst->getDefType(), Inst); + return {}; +} + +Expect<void> +Executor::runArraySetOp(const ValVariant &Val, const uint32_t Idx, + const RefVariant &InstRef, + const AST::CompositeType &CompType, + const AST::Instruction &Instr) const noexcept { + auto *Inst = InstRef.getPtr<Runtime::Instance::ArrayInstance>(); + if (Inst == nullptr) { + spdlog::error(ErrCode::Value::AccessNullArray); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullArray); + } + if (Idx >= Inst->getLength()) { + spdlog::error(ErrCode::Value::ArrayOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary(Idx, 1, Inst->getBoundIdx())); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::ArrayOutOfBounds); + } + const auto &SType = CompType.getFieldTypes()[0].getStorageType(); + Inst->getData(Idx) = packVal(SType, Val); + return {}; +} + +Expect<void> Executor::runArrayGetOp(ValVariant &Val, const uint32_t Idx, + const AST::CompositeType &CompType, + const AST::Instruction &Instr, + bool IsSigned) const noexcept { + const auto *Inst = + Val.get<RefVariant>().getPtr<Runtime::Instance::ArrayInstance>(); + if (Inst == nullptr) { + spdlog::error(ErrCode::Value::AccessNullArray); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullArray); + } + if (Idx >= Inst->getLength()) { + spdlog::error(ErrCode::Value::ArrayOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary(Idx, 1, Inst->getBoundIdx())); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::ArrayOutOfBounds); + } + const auto &SType = CompType.getFieldTypes()[0].getStorageType(); + Val = unpackVal(SType, Inst->getData(Idx), IsSigned); + return {}; +} + +Expect<void> +Executor::runArrayLenOp(ValVariant &Val, + const AST::Instruction &Instr) const noexcept { + const auto *Inst = + Val.get<RefVariant>().getPtr<Runtime::Instance::ArrayInstance>(); + if (Inst == nullptr) { + spdlog::error(ErrCode::Value::AccessNullArray); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullArray); + } + Val.emplace<uint32_t>(Inst->getLength()); + return {}; +} + +Expect<void> +Executor::runArrayFillOp(uint32_t N, const ValVariant &Val, uint32_t D, + const RefVariant &InstRef, + const AST::CompositeType &CompType, + const AST::Instruction &Instr) const noexcept { + auto *Inst = InstRef.getPtr<Runtime::Instance::ArrayInstance>(); + if (Inst == nullptr) { + spdlog::error(ErrCode::Value::AccessNullArray); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullArray); + } + if (static_cast<uint64_t>(D) + static_cast<uint64_t>(N) > Inst->getLength()) { + spdlog::error(ErrCode::Value::ArrayOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary(static_cast<uint64_t>(D), N, + Inst->getBoundIdx())); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::ArrayOutOfBounds); + } + const auto &SType = CompType.getFieldTypes()[0].getStorageType(); + auto Arr = Inst->getArray(); + std::fill(Arr.begin() + D, Arr.begin() + D + N, packVal(SType, Val)); + return {}; +} + +Expect<void> +Executor::runArrayCopyOp(uint32_t N, uint32_t S, const RefVariant &SrcInstRef, + uint32_t D, const RefVariant &DstInstRef, + const AST::CompositeType &SrcCompType, + const AST::CompositeType &DstCompType, + const AST::Instruction &Instr) const noexcept { + auto *SrcInst = SrcInstRef.getPtr<Runtime::Instance::ArrayInstance>(); + auto *DstInst = DstInstRef.getPtr<Runtime::Instance::ArrayInstance>(); + if (SrcInst == nullptr || DstInst == nullptr) { + spdlog::error(ErrCode::Value::AccessNullArray); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullArray); + } + if (static_cast<uint64_t>(S) + static_cast<uint64_t>(N) > + SrcInst->getLength()) { + spdlog::error(ErrCode::Value::ArrayOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary(static_cast<uint64_t>(S), N, + SrcInst->getBoundIdx())); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::ArrayOutOfBounds); + } + if (static_cast<uint64_t>(D) + static_cast<uint64_t>(N) > + DstInst->getLength()) { + spdlog::error(ErrCode::Value::ArrayOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary(static_cast<uint64_t>(D), N, + DstInst->getBoundIdx())); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::ArrayOutOfBounds); + } + const auto &SrcSType = SrcCompType.getFieldTypes()[0].getStorageType(); + const auto &DstSType = DstCompType.getFieldTypes()[0].getStorageType(); + auto SrcArr = SrcInst->getArray(); + auto DstArr = DstInst->getArray(); + if (D <= S) { + std::transform(SrcArr.begin() + S, SrcArr.begin() + S + N, + DstArr.begin() + D, [&](const ValVariant &V) { + return packVal(DstSType, unpackVal(SrcSType, V)); + }); + } else { + std::transform(std::make_reverse_iterator(SrcArr.begin() + S + N), + std::make_reverse_iterator(SrcArr.begin() + S), + std::make_reverse_iterator(DstArr.begin() + D + N), + [&](const ValVariant &V) { + return packVal(DstSType, unpackVal(SrcSType, V)); + }); + } + return {}; +} + +Expect<void> +Executor::runArrayInitDataOp(uint32_t N, uint32_t S, uint32_t D, + const RefVariant &InstRef, + const AST::CompositeType &CompType, + const Runtime::Instance::DataInstance &DataInst, + const AST::Instruction &Instr) const noexcept { + const uint32_t BSize = + CompType.getFieldTypes()[0].getStorageType().getBitWidth() / 8; + auto *Inst = InstRef.getPtr<Runtime::Instance::ArrayInstance>(); + if (Inst == nullptr) { + spdlog::error(ErrCode::Value::AccessNullArray); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullArray); + } + if (static_cast<uint64_t>(D) + static_cast<uint64_t>(N) > Inst->getLength()) { + spdlog::error(ErrCode::Value::ArrayOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary(static_cast<uint64_t>(D), N, + Inst->getBoundIdx())); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::ArrayOutOfBounds); + } + if (static_cast<uint64_t>(S) + static_cast<uint64_t>(N) * BSize > + DataInst.getData().size()) { + spdlog::error(ErrCode::Value::MemoryOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary( + static_cast<uint64_t>(S), N * BSize, + DataInst.getData().size() > 0 + ? static_cast<uint32_t>(DataInst.getData().size() - 1) + : 0U)); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::MemoryOutOfBounds); + } + for (uint32_t Off = 0; Off < N; Off++) { + // The value has been packed. + Inst->getData(D + Off) = DataInst.loadValue(S + Off * BSize, BSize); + } + return {}; +} + +Expect<void> +Executor::runArrayInitElemOp(uint32_t N, uint32_t S, uint32_t D, + const RefVariant &InstRef, + const AST::CompositeType &CompType, + const Runtime::Instance::ElementInstance &ElemInst, + const AST::Instruction &Instr) const noexcept { + auto ElemSrc = ElemInst.getRefs(); + auto *Inst = InstRef.getPtr<Runtime::Instance::ArrayInstance>(); + if (Inst == nullptr) { + spdlog::error(ErrCode::Value::AccessNullArray); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullArray); + } + if (static_cast<uint64_t>(D) + static_cast<uint64_t>(N) > Inst->getLength()) { + spdlog::error(ErrCode::Value::ArrayOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary(static_cast<uint64_t>(D), N, + Inst->getBoundIdx())); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::ArrayOutOfBounds); + } + if (static_cast<uint64_t>(S) + static_cast<uint64_t>(N) > ElemSrc.size()) { + spdlog::error(ErrCode::Value::TableOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary( + static_cast<uint64_t>(S), N, + ElemSrc.size() > 0 ? static_cast<uint32_t>(ElemSrc.size() - 1) : 0U)); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::TableOutOfBounds); + } + const auto &SType = CompType.getFieldTypes()[0].getStorageType(); + + auto Arr = Inst->getArray(); + // The value has been packed. + std::transform(ElemSrc.begin() + S, ElemSrc.begin() + S + N, Arr.begin() + D, + [&](const RefVariant &V) { return packVal(SType, V); }); + return {}; +} + +Expect<void> +Executor::runRefTestOp(const Runtime::Instance::ModuleInstance *ModInst, + ValVariant &Val, const AST::Instruction &Instr, + bool IsCast) const noexcept { + // Copy the value type here due to handling the externalized case. + auto &VT = Val.get<RefVariant>().getType(); + if (VT.isExternalized()) { + VT = ValType(TypeCode::Ref, TypeCode::ExternRef); + } + Span<const AST::SubType *const> GotTypeList = ModInst->getTypeList(); + if (!VT.isAbsHeapType()) { + auto *Inst = + Val.get<RefVariant>().getPtr<Runtime::Instance::CompositeBase>(); + // Reference must not be nullptr here because the null references are typed + // with the least abstract heap type. + if (Inst->getModule()) { + GotTypeList = Inst->getModule()->getTypeList(); + } + } + + if (AST::TypeMatcher::matchType(ModInst->getTypeList(), Instr.getValType(), + GotTypeList, VT)) { + if (!IsCast) { + Val.emplace<uint32_t>(1U); + } + } else { + if (IsCast) { + spdlog::error(ErrCode::Value::CastFailed); + spdlog::error(ErrInfo::InfoMismatch(Instr.getValType(), VT)); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::CastFailed); + } else { + Val.emplace<uint32_t>(0U); + } + } + return {}; +} + +Expect<void> Executor::runRefConvOp(RefVariant &Ref, + TypeCode TCode) const noexcept { + + if (TCode == TypeCode::AnyRef) { + // Internalize. + if (Ref.isNull()) { + Ref = RefVariant(ValType(TypeCode::RefNull, TypeCode::NullRef)); + } else { + Ref.getType().setInternalized(); + if (Ref.getType().isExternRefType()) { + Ref.getType() = ValType(TypeCode::Ref, TypeCode::AnyRef); + } + } + } else { + // Externalize. + if (Ref.isNull()) { + Ref = RefVariant(ValType(TypeCode::RefNull, TypeCode::NullExternRef)); + } else { + // Use the externalize flag because the value type information should be + // reserved when a reference being externalized and internalized. + Ref.getType().setExternalized(); + } + } + return {}; +} + +Expect<void> Executor::runRefI31Op(ValVariant &Val) const noexcept { + uint32_t RefNum = (Val.get<uint32_t>() & 0x7FFFFFFFU) | 0x80000000U; + Val = RefVariant(ValType(TypeCode::Ref, TypeCode::I31Ref), + reinterpret_cast<void *>(static_cast<uint64_t>(RefNum))); + return {}; +} + +Expect<void> Executor::runI31GetOp(ValVariant &Val, + const AST::Instruction &Instr, + bool IsSigned) const noexcept { + uint32_t RefNum = static_cast<uint32_t>( + reinterpret_cast<uintptr_t>(Val.get<RefVariant>().getPtr<void>())); + if ((RefNum & 0x80000000U) == 0) { + spdlog::error(ErrCode::Value::AccessNullI31); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullI31); + } + RefNum &= 0x7FFFFFFFU; + if (IsSigned) { + RefNum |= ((RefNum & 0x40000000U) << 1); + } + Val.emplace<uint32_t>(RefNum); + return {}; +} + +} // namespace Executor +} // namespace WasmEdge diff --git a/lib/executor/engine/tableInstr.cpp b/lib/executor/engine/tableInstr.cpp index 47c40e817883..d6e83d418ded 100644 --- a/lib/executor/engine/tableInstr.cpp +++ b/lib/executor/engine/tableInstr.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" diff --git a/lib/executor/engine/threadInstr.cpp b/lib/executor/engine/threadInstr.cpp index 28c04fdfc519..fad134fda333 100644 --- a/lib/executor/engine/threadInstr.cpp +++ b/lib/executor/engine/threadInstr.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" diff --git a/lib/executor/engine/variableInstr.cpp b/lib/executor/engine/variableInstr.cpp index f57ee4fec1f0..105ac6a3ba5a 100644 --- a/lib/executor/engine/variableInstr.cpp +++ b/lib/executor/engine/variableInstr.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" @@ -39,7 +39,7 @@ Expect<void> Executor::runGlobalSetOp(Runtime::StackManager &StackMgr, uint32_t Idx) const noexcept { auto *GlobInst = getGlobInstByIdx(StackMgr, Idx); assuming(GlobInst); - GlobInst->getValue() = StackMgr.pop(); + GlobInst->setValue(StackMgr.pop()); return {}; } diff --git a/lib/executor/executor.cpp b/lib/executor/executor.cpp index a330009e070f..c0cf576172e3 100644 --- a/lib/executor/executor.cpp +++ b/lib/executor/executor.cpp @@ -1,14 +1,34 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" namespace WasmEdge { namespace Executor { +Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>> +Executor::instantiateComponent(Runtime::StoreManager &StoreMgr, + const AST::Component::Component &Comp) { + auto Res = instantiate(StoreMgr, Comp); + if (!Res) { + return Unexpect(Res); + } + return Res; +} +Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>> +Executor::instantiateComponent(Runtime::StoreManager &StoreMgr, + const AST::Component::Component &Comp, + std::string_view Name) { + auto Res = instantiate(StoreMgr, Comp, Name); + if (!Res) { + return Unexpect(Res); + } + return Res; +} + /// Instantiate a WASM Module. See "include/executor/executor.h". Expect<std::unique_ptr<Runtime::Instance::ModuleInstance>> Executor::instantiateModule(Runtime::StoreManager &StoreMgr, @@ -54,6 +74,16 @@ Executor::registerModule(Runtime::StoreManager &StoreMgr, } return {}; } +Expect<void> Executor::registerComponent( + Runtime::StoreManager &StoreMgr, + const Runtime::Instance::ComponentInstance &CompInst) { + if (auto Res = StoreMgr.registerComponent(&CompInst); !Res) { + spdlog::error(ErrCode::Value::ModuleNameConflict); + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); + return Unexpect(ErrCode::Value::ModuleNameConflict); + } + return {}; +} /// Register a host function which will be invoked before calling a /// host function. @@ -81,12 +111,21 @@ Executor::invoke(const Runtime::Instance::FunctionInstance *FuncInst, return Unexpect(ErrCode::Value::FuncNotFound); } - // Check parameter and function type. + // Matching arguments and function type. const auto &FuncType = FuncInst->getFuncType(); const auto &PTypes = FuncType.getParamTypes(); const auto &RTypes = FuncType.getReturnTypes(); - if (!matchTypes(*FuncInst->getModule(), ParamTypes, *FuncInst->getModule(), - PTypes)) { + // The defined type list may be empty if the function is an independent + // function instance, that is, the module instance will be nullptr. For this + // case, all of value types are number types or abstract heap types. + // + // If a function belongs to component instance, we should totally get + // converted type, so should no need type list. + WasmEdge::Span<const WasmEdge::AST::SubType *const> TypeList = {}; + if (FuncInst->getModule()) { + TypeList = FuncInst->getModule()->getTypeList(); + } + if (!AST::TypeMatcher::matchTypes(TypeList, ParamTypes, PTypes)) { spdlog::error(ErrCode::Value::FuncSigMismatch); spdlog::error(ErrInfo::InfoMismatch( PTypes, RTypes, std::vector(ParamTypes.begin(), ParamTypes.end()), @@ -115,8 +154,40 @@ Executor::invoke(const Runtime::Instance::FunctionInstance *FuncInst, // Get return values. std::vector<std::pair<ValVariant, ValType>> Returns(RTypes.size()); for (uint32_t I = 0; I < RTypes.size(); ++I) { - Returns[RTypes.size() - I - 1] = - std::make_pair(StackMgr.pop(), RTypes[RTypes.size() - I - 1]); + auto Val = StackMgr.pop(); + const auto &RType = RTypes[RTypes.size() - I - 1]; + if (RType.isRefType()) { + // For the reference type cases of the return values, they should be + // transformed into abstract heap types due to the opaque of type indices. + auto &RefType = Val.get<RefVariant>().getType(); + if (RefType.isExternalized()) { + // First handle the forced externalized value type case. + RefType = ValType(TypeCode::Ref, TypeCode::ExternRef); + } + if (!RefType.isAbsHeapType()) { + // The instance must not be nullptr because the null references are + // already dynamic typed into the top abstract heap type. + auto *Inst = + Val.get<RefVariant>().getPtr<Runtime::Instance::CompositeBase>(); + assuming(Inst); + // The ModInst may be nullptr only in the independent host function + // instance. Therefore the module instance here must not be nullptr + // because the independent host function instance cannot be imported and + // be referred by instructions. + const auto *ModInst = Inst->getModule(); + auto *DefType = *ModInst->getType(RefType.getTypeIndex()); + RefType = + ValType(RefType.getCode(), DefType->getCompositeType().expand()); + } + // Should use the value type from the reference here due to the dynamic + // typing rule of the null references. + Returns[RTypes.size() - I - 1] = std::make_pair(Val, RefType); + } else { + // For the number type cases of the return values, the unused bits should + // be erased due to the security issue. + cleanNumericVal(Val, RType); + Returns[RTypes.size() - I - 1] = std::make_pair(Val, RType); + } } // After execution, the value stack size should be 0. diff --git a/lib/executor/helper.cpp b/lib/executor/helper.cpp index 3e5a02a47166..eb964a4f81f9 100644 --- a/lib/executor/helper.cpp +++ b/lib/executor/helper.cpp @@ -1,9 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" -#include "common/log.h" +#include "common/spdlog.h" #include "system/fault.h" #include <cstdint> @@ -31,6 +31,10 @@ Executor::enterFunction(Runtime::StackManager &StackMgr, const uint32_t RetsN = static_cast<uint32_t>(FuncType.getReturnTypes().size()); + // For the exception handler, remove the inactive handlers caused by the + // branches. + StackMgr.removeInactiveHandler(RetIt - 1); + if (Func.isHostFunction()) { // Host function case: Push args and call function. auto &HostFunc = Func.getHostFunc(); @@ -69,6 +73,11 @@ Executor::enterFunction(Runtime::StackManager &StackMgr, // Run host function. Span<ValVariant> Args = StackMgr.getTopSpan(ArgsN); + for (uint32_t I = 0; I < ArgsN; I++) { + // For the number type cases of the arguments, the unused bits should be + // erased due to the security issue. + cleanNumericVal(Args[I], FuncType.getParamTypes()[I]); + } std::vector<ValVariant> Rets(RetsN); auto Ret = HostFunc.run(CallFrame, std::move(Args), Rets); @@ -133,20 +142,26 @@ Executor::enterFunction(Runtime::StackManager &StackMgr, prepare(StackMgr, ModInst->MemoryPtrs.data(), ModInst->GlobalPtrs.data()); } - { + ErrCode Err; + try { // Get symbol and execute the function. Fault FaultHandler; uint32_t Code = PREPARE_FAULT(FaultHandler); - if (auto Err = ErrCode(static_cast<ErrCategory>(Code >> 24), Code); - unlikely(Err != ErrCode::Value::Success)) { - if (Err != ErrCode::Value::Terminated) { - spdlog::error(Err); - } - return Unexpect(Err); + if (Code != 0) { + Err = ErrCode(static_cast<ErrCategory>(Code >> 24), Code); + } else { + auto &Wrapper = FuncType.getSymbol(); + Wrapper(&ExecutionContext, Func.getSymbol().get(), Args.data(), + Rets.data()); + } + } catch (const ErrCode &E) { + Err = E; + } + if (unlikely(Err)) { + if (Err != ErrCode::Value::Terminated) { + spdlog::error(Err); } - auto &Wrapper = FuncType.getSymbol(); - Wrapper(&ExecutionContext, Func.getSymbol().get(), Args.data(), - Rets.data()); + return Unexpect(Err); } // Push returns back to stack. @@ -183,22 +198,67 @@ Executor::enterFunction(Runtime::StackManager &StackMgr, } } -Expect<void> Executor::branchToLabel(Runtime::StackManager &StackMgr, - uint32_t EraseBegin, uint32_t EraseEnd, - int32_t PCOffset, - AST::InstrView::iterator &PC) noexcept { - // Check stop token +Expect<void> +Executor::branchToLabel(Runtime::StackManager &StackMgr, + const AST::Instruction::JumpDescriptor &JumpDesc, + AST::InstrView::iterator &PC) noexcept { + // Check the stop token. if (unlikely(StopToken.exchange(0, std::memory_order_relaxed))) { spdlog::error(ErrCode::Value::Interrupted); return Unexpect(ErrCode::Value::Interrupted); } - StackMgr.stackErase(EraseBegin, EraseEnd); + StackMgr.eraseValueStack(JumpDesc.StackEraseBegin, JumpDesc.StackEraseEnd); // PC need to -1 here because the PC will increase in the next iteration. - PC += (PCOffset - 1); + PC += (JumpDesc.PCOffset - 1); return {}; } +Expect<void> Executor::throwException(Runtime::StackManager &StackMgr, + Runtime::Instance::TagInstance &TagInst, + AST::InstrView::iterator &PC) noexcept { + StackMgr.removeInactiveHandler(PC); + auto AssocValSize = TagInst.getTagType().getAssocValSize(); + while (true) { + // Pop the top handler. + auto Handler = StackMgr.popTopHandler(AssocValSize); + if (!Handler.has_value()) { + break; + } + // Checking through the catch clause. + for (const auto &C : Handler->CatchClause) { + if (!C.IsAll && getTagInstByIdx(StackMgr, C.TagIndex) != &TagInst) { + // For catching a specific tag, should check the equivalence of tag + // address. + continue; + } + if (C.IsRef) { + // For catching a exception reference, push the reference value onto + // stack. + StackMgr.push( + RefVariant(ValType(TypeCode::Ref, TypeCode::ExnRef), &TagInst)); + } + // When being here, an exception is caught. Move the PC to the try block + // and branch to the label. + + PC = Handler->Try; + return branchToLabel(StackMgr, C.Jump, PC); + } + } + spdlog::error(ErrCode::Value::UncaughtException); + return Unexpect(ErrCode::Value::UncaughtException); +} + +const AST::SubType *Executor::getDefTypeByIdx(Runtime::StackManager &StackMgr, + const uint32_t Idx) const { + const auto *ModInst = StackMgr.getModule(); + // When top frame is dummy frame, cannot find instance. + if (unlikely(ModInst == nullptr)) { + return nullptr; + } + return ModInst->unsafeGetType(Idx); +} + Runtime::Instance::FunctionInstance * Executor::getFuncInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const { @@ -232,6 +292,17 @@ Executor::getMemInstByIdx(Runtime::StackManager &StackMgr, return ModInst->unsafeGetMemory(Idx); } +Runtime::Instance::TagInstance * +Executor::getTagInstByIdx(Runtime::StackManager &StackMgr, + const uint32_t Idx) const { + const auto *ModInst = StackMgr.getModule(); + // When top frame is dummy frame, cannot find instance. + if (unlikely(ModInst == nullptr)) { + return nullptr; + } + return ModInst->unsafeGetTag(Idx); +} + Runtime::Instance::GlobalInstance * Executor::getGlobInstByIdx(Runtime::StackManager &StackMgr, const uint32_t Idx) const { @@ -265,64 +336,76 @@ Executor::getDataInstByIdx(Runtime::StackManager &StackMgr, return ModInst->unsafeGetData(Idx); } -bool Executor::matchType(const Runtime::Instance::ModuleInstance &ModExp, - const ValType &Exp, - const Runtime::Instance::ModuleInstance &ModGot, - const ValType &Got) const noexcept { - if (!Exp.isRefType() && !Got.isRefType() && Exp.getCode() == Got.getCode()) { - // Match for the non-reference type case. - return true; - } - if (Exp.isRefType() && Got.isRefType()) { - // Nullable matching. - if (!Exp.isNullableRefType() && Got.isNullableRefType()) { - return false; - } - - // Match the heap type. - if (Exp.getHeapTypeCode() == Got.getHeapTypeCode() && - Exp.getHeapTypeCode() != TypeCode::TypeIndex) { - // Abs heap type are the same. - return true; - } - if (Exp.getHeapTypeCode() == TypeCode::FuncRef && - Got.getHeapTypeCode() == TypeCode::TypeIndex) { - // Match type index to any funcref. - return true; - } - if (Exp.getHeapTypeCode() == TypeCode::TypeIndex && - Got.getHeapTypeCode() == TypeCode::TypeIndex) { - // Match got type index to expected type index. - if (matchTypes( - ModExp, ModExp.FuncTypes[Exp.getTypeIndex()].getParamTypes(), - ModGot, ModGot.FuncTypes[Got.getTypeIndex()].getParamTypes()) && - matchTypes( - ModExp, ModExp.FuncTypes[Exp.getTypeIndex()].getReturnTypes(), - ModGot, ModGot.FuncTypes[Got.getTypeIndex()].getReturnTypes())) { - // Note: In future versions of WebAssembly, subtyping on function types - // may be relaxed to support co- and contra-variance. - // Due to passing the validation of type section, this will not cause - // infinite recursion. - return true; +TypeCode Executor::toBottomType(Runtime::StackManager &StackMgr, + const ValType &Type) const { + if (Type.isRefType()) { + if (Type.isAbsHeapType()) { + switch (Type.getHeapTypeCode()) { + case TypeCode::NullFuncRef: + case TypeCode::FuncRef: + return TypeCode::NullFuncRef; + case TypeCode::NullExternRef: + case TypeCode::ExternRef: + return TypeCode::NullExternRef; + case TypeCode::NullRef: + case TypeCode::AnyRef: + case TypeCode::EqRef: + case TypeCode::I31Ref: + case TypeCode::StructRef: + case TypeCode::ArrayRef: + return TypeCode::NullRef; + case TypeCode::ExnRef: + return TypeCode::ExnRef; + default: + assumingUnreachable(); + } + } else { + const auto &CompType = + (*StackMgr.getModule()->getType(Type.getTypeIndex())) + ->getCompositeType(); + if (CompType.isFunc()) { + return TypeCode::NullFuncRef; + } else { + return TypeCode::NullRef; } } + } else { + return Type.getCode(); } - return false; } -bool Executor::matchTypes(const Runtime::Instance::ModuleInstance &ModExp, - Span<const ValType> Exp, - const Runtime::Instance::ModuleInstance &ModGot, - Span<const ValType> Got) const noexcept { - if (Exp.size() != Got.size()) { - return false; - } - for (uint32_t I = 0; I < Exp.size(); I++) { - if (!matchType(ModExp, Exp[I], ModGot, Got[I])) { - return false; +void Executor::cleanNumericVal(ValVariant &Val, + const ValType &Type) const noexcept { + if (Type.isNumType()) { + switch (Type.getCode()) { + case TypeCode::I32: { + uint32_t V = Val.get<uint32_t>(); + Val.emplace<uint128_t>(static_cast<uint128_t>(0)); + Val.emplace<uint32_t>(V); + break; + } + case TypeCode::F32: { + float V = Val.get<float>(); + Val.emplace<uint128_t>(static_cast<uint128_t>(0)); + Val.emplace<float>(V); + break; + } + case TypeCode::I64: { + uint64_t V = Val.get<uint64_t>(); + Val.emplace<uint128_t>(static_cast<uint128_t>(0)); + Val.emplace<uint64_t>(V); + break; + } + case TypeCode::F64: { + double V = Val.get<double>(); + Val.emplace<uint128_t>(static_cast<uint128_t>(0)); + Val.emplace<double>(V); + break; + } + default: + break; } } - return true; } } // namespace Executor diff --git a/lib/executor/instantiate/component.cpp b/lib/executor/instantiate/component.cpp new file mode 100644 index 000000000000..c5a6c248453c --- /dev/null +++ b/lib/executor/instantiate/component.cpp @@ -0,0 +1,92 @@ +#include "ast/component/instance.h" +#include "ast/module.h" +#include "common/errcode.h" +#include "executor/executor.h" + +#include "runtime/instance/module.h" + +#include <string_view> +#include <variant> + +namespace WasmEdge { +namespace Executor { + +// Instantiate module instance. See "include/executor/Executor.h". +Expect<std::unique_ptr<Runtime::Instance::ComponentInstance>> +Executor::instantiate(Runtime::StoreManager &StoreMgr, + const AST::Component::Component &Comp, + std::optional<std::string_view> Name) { + using namespace AST::Component; + + std::unique_ptr<Runtime::Instance::ComponentInstance> CompInst; + if (Name.has_value()) { + CompInst = + std::make_unique<Runtime::Instance::ComponentInstance>(Name.value()); + } else { + CompInst = std::make_unique<Runtime::Instance::ComponentInstance>(""); + } + + for (auto &Sec : Comp.getSections()) { + if (std::holds_alternative<AST::CustomSection>(Sec)) { + } else if (std::holds_alternative<AST::CoreModuleSection>(Sec)) { + CompInst->addModule(std::get<AST::CoreModuleSection>(Sec).getContent()); + } else if (std::holds_alternative<ComponentSection>(Sec)) { + CompInst->addComponent(std::get<ComponentSection>(Sec).getContent()); + } else if (std::holds_alternative<CoreInstanceSection>(Sec)) { + auto Res = + instantiate(StoreMgr, *CompInst, std::get<CoreInstanceSection>(Sec)); + if (!Res) { + return Unexpect(Res); + } + } else if (std::holds_alternative<InstanceSection>(Sec)) { + auto Res = + instantiate(StoreMgr, *CompInst, std::get<InstanceSection>(Sec)); + if (!Res) { + return Unexpect(Res); + } + } else if (std::holds_alternative<ImportSection>(Sec)) { + auto Res = instantiate(StoreMgr, *CompInst, std::get<ImportSection>(Sec)); + if (!Res) { + return Unexpect(Res); + } + } else if (std::holds_alternative<CoreTypeSection>(Sec)) { + auto Res = + instantiate(StoreMgr, *CompInst, std::get<CoreTypeSection>(Sec)); + if (!Res) { + return Unexpect(Res); + } + } else if (std::holds_alternative<TypeSection>(Sec)) { + auto Res = instantiate(StoreMgr, *CompInst, std::get<TypeSection>(Sec)); + if (!Res) { + return Unexpect(Res); + } + } else if (std::holds_alternative<StartSection>(Sec)) { + auto Res = instantiate(StoreMgr, *CompInst, std::get<StartSection>(Sec)); + if (!Res) { + return Unexpect(Res); + } + } else if (std::holds_alternative<CanonSection>(Sec)) { + auto Res = instantiate(StoreMgr, *CompInst, std::get<CanonSection>(Sec)); + if (!Res) { + return Unexpect(Res); + } + } else if (std::holds_alternative<AliasSection>(Sec)) { + auto Res = instantiate(StoreMgr, *CompInst, std::get<AliasSection>(Sec)); + if (!Res) { + return Unexpect(Res); + } + } else if (std::holds_alternative<ExportSection>(Sec)) { + auto Res = instantiate(StoreMgr, *CompInst, std::get<ExportSection>(Sec)); + if (!Res) { + return Unexpect(Res); + } + } + } + + StoreMgr.registerComponent(CompInst.get()); + + return CompInst; +} + +} // namespace Executor +} // namespace WasmEdge diff --git a/lib/executor/instantiate/component/instantiate_component_alias.cpp b/lib/executor/instantiate/component/instantiate_component_alias.cpp new file mode 100644 index 000000000000..13297f783bc3 --- /dev/null +++ b/lib/executor/instantiate/component/instantiate_component_alias.cpp @@ -0,0 +1,124 @@ +#include "common/errcode.h" +#include "executor/executor.h" + +#include "runtime/instance/module.h" + +#include <string_view> +#include <variant> + +namespace WasmEdge { +namespace Executor { + +using namespace std::literals; +using namespace AST::Component; + +Expect<void> +Executor::instantiate(Runtime::StoreManager &, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::AliasSection &AliasSec) { + for (auto &A : AliasSec.getContent()) { + auto &T = A.getTarget(); + auto &S = A.getSort(); + if (std::holds_alternative<CoreSort>(S)) { + if (std::holds_alternative<AliasTargetExport>(T)) { + // This means instance exports a function + auto &Exp = std::get<AliasTargetExport>(T); + const auto *ModInst = CompInst.getModuleInstance(Exp.getInstanceIdx()); + + switch (std::get<CoreSort>(S)) { + case CoreSort::Func: { + auto *FuncInst = ModInst->getFuncExports( + [&](const std::map<std::string, + Runtime::Instance::FunctionInstance *, + std::less<>> &Map) { + return ModInst->unsafeFindExports(Map, Exp.getName()); + }); + CompInst.addCoreFunctionInstance(FuncInst); + break; + } + case CoreSort::Table: + spdlog::warn("incomplete core alias sort: table"); + break; + case CoreSort::Memory: { + auto *MemInst = ModInst->getMemoryExports( + [&](const std::map<std::string, + Runtime::Instance::MemoryInstance *, + std::less<>> &Map) { + return ModInst->unsafeFindExports(Map, Exp.getName()); + }); + CompInst.addCoreMemoryInstance(MemInst); + break; + } + case CoreSort::Global: + spdlog::warn("incomplete core alias sort: global"sv); + break; + case CoreSort::Type: + spdlog::warn("incomplete core alias sort: type"sv); + break; + case CoreSort::Module: + spdlog::warn("incomplete core alias sort: module"sv); + break; + case CoreSort::Instance: + spdlog::warn("incomplete core alias sort: instance"sv); + break; + } + } else { + spdlog::warn("incomplete alias target outer"sv); + } + } else if (std::holds_alternative<SortCase>(S)) { + if (std::holds_alternative<AliasTargetExport>(T)) { + auto &Exp = std::get<AliasTargetExport>(T); + + switch (std::get<SortCase>(S)) { + case SortCase::Func: { + auto *CInst = CompInst.getComponentInstance(Exp.getInstanceIdx()); + auto *FuncInst = CInst->findFuncExports(Exp.getName()); + CompInst.addFunctionInstance(FuncInst); + break; + } + case SortCase::Value: // TODO: need real use cases to analysis how to + // implement these cases + spdlog::warn("incomplete alias sort target export: value"sv); + break; + case SortCase::Type: + spdlog::warn("incomplete alias sort target export: type"sv); + break; + case SortCase::Component: + spdlog::warn("incomplete alias sort target export: component"sv); + break; + case SortCase::Instance: + spdlog::warn("incomplete alias sort target export: instance"sv); + break; + } + } else { + auto &Out = std::get<AliasTargetOuter>(T); + + switch (std::get<SortCase>(S)) { + case SortCase::Func: { + auto *FuncInst = CompInst.getComponentInstance(Out.getComponent()) + ->getCoreFunctionInstance(Out.getIndex()); + CompInst.addFunctionInstance(FuncInst); + break; + } + case SortCase::Value: // TODO: need real use cases to analysis how to + // implement these cases + spdlog::warn("incomplete alias sort outer: value"sv); + break; + case SortCase::Type: + spdlog::warn("incomplete alias sort outer: type"sv); + break; + case SortCase::Component: + spdlog::warn("incomplete alias sort outer: component"sv); + break; + case SortCase::Instance: + spdlog::warn("incomplete alias sort outer: instance"sv); + break; + } + } + } + } + return {}; +} + +} // namespace Executor +} // namespace WasmEdge diff --git a/lib/executor/instantiate/component/instantiate_component_canon.cpp b/lib/executor/instantiate/component/instantiate_component_canon.cpp new file mode 100644 index 000000000000..f3ef3f6f9c2b --- /dev/null +++ b/lib/executor/instantiate/component/instantiate_component_canon.cpp @@ -0,0 +1,380 @@ +#include "ast/component/instance.h" +#include "ast/module.h" +#include "common/errcode.h" +#include "executor/executor.h" + +#include "runtime/instance/module.h" + +#include <sstream> +#include <string_view> +#include <variant> + +namespace WasmEdge { +namespace Executor { + +using namespace std::literals; +using namespace AST::Component; +using namespace Runtime; + +namespace { +void pushType(Runtime::Instance::ComponentInstance &Comp, + std::vector<ValType> &Types, const ValueType &T) { + // notice that we might need to convert one type to multiple types, and hence, + // we must let this function control the vector need to be modified. + if (std::holds_alternative<PrimValType>(T)) { + switch (std::get<PrimValType>(T)) { + case PrimValType::Bool: + case PrimValType::Char: + case PrimValType::S8: + case PrimValType::U8: + Types.push_back(TypeCode::I8); + break; + case PrimValType::S16: + case PrimValType::U16: + Types.push_back(TypeCode::I16); + break; + case PrimValType::S32: + case PrimValType::U32: + Types.push_back(TypeCode::I32); + break; + case PrimValType::S64: + case PrimValType::U64: + Types.push_back(TypeCode::I64); + break; + case PrimValType::Float32: + Types.push_back(TypeCode::F32); + break; + case PrimValType::Float64: + Types.push_back(TypeCode::F64); + break; + case PrimValType::String: + Types.push_back(TypeCode::String); + break; + } + } else { + auto Idx = std::get<TypeIndex>(T); + const auto &Ty = Comp.getType(Idx); + spdlog::warn("Type {} is not handled yet"sv, Ty); + } +} + +AST::FunctionType convert(Runtime::Instance::ComponentInstance &Comp, + const FuncType &DT) { + std::vector<ValType> ParamTypes{}; + for (const auto &P : DT.getParamList()) { + pushType(Comp, ParamTypes, P.getValType()); + } + + std::vector<ValType> ResultTypes{}; + if (std::holds_alternative<ValueType>(DT.getResultList())) { + pushType(Comp, ResultTypes, std::get<ValueType>(DT.getResultList())); + } else { + const auto &RL = DT.getResultList(); + for (const auto &R : std::get<std::vector<LabelValType>>(RL)) { + pushType(Comp, ResultTypes, R.getValType()); + } + } + + return AST::FunctionType(ParamTypes, ResultTypes); +} +} // namespace + +class LiftTrans : public HostFunctionBase { +public: + LiftTrans(Executor *Exec, const FuncType &DefinedType, + Instance::FunctionInstance *Func, Instance::MemoryInstance *M, + Instance::FunctionInstance *R, + Runtime::Instance::ComponentInstance &Comp) + : HostFunctionBase(0), Exec(Exec), LowerFunc(Func), Memory(M), + Realloc(R) { + auto &FT = DefType.getCompositeType().getFuncType(); + // The convert is simply let component type to internal type. + FT = convert(Comp, DefinedType); + spdlog::info("lifted: {}"sv, FT); + } + + Expect<void> run(const Runtime::CallingFrame &, Span<const ValVariant> Args, + Span<ValVariant> Rets) override { + const auto &HigherFuncType = DefType.getCompositeType().getFuncType(); + + uint32_t PI = 0; + std::vector<ValVariant> LowerArgs{}; + for (auto &ParamTy : HigherFuncType.getParamTypes()) { + switch (ParamTy.getCode()) { + case TypeCode::String: { + std::string_view Str = Args[PI++].get<StrVariant>().getString(); + + auto StrSize = static_cast<uint32_t>(Str.size()); + std::vector<ValVariant> ReallocArgs{ValVariant(0), ValVariant(0), + ValVariant(0), ValVariant(StrSize)}; + auto RPtr = Exec->invoke(Realloc, ReallocArgs, + Realloc->getFuncType().getParamTypes()); + if (!RPtr) { + return Unexpect(RPtr); + } + ValVariant PtrInMem = (*RPtr)[0].first; + + Memory->setBytes(std::vector<Byte>{Str.begin(), Str.end()}, + PtrInMem.get<uint32_t>(), 0, + static_cast<uint32_t>(Str.size())); + LowerArgs.push_back(PtrInMem); + LowerArgs.push_back(StrSize); + break; + } + default: { + // usual type has no need conversion + const ValVariant &Arg = Args[PI++]; + LowerArgs.push_back(Arg); + break; + } + } + } + + auto &LowerFuncType = LowerFunc->getFuncType(); + auto Res = + Exec->invoke(LowerFunc, LowerArgs, LowerFuncType.getParamTypes()); + if (!Res) { + return Unexpect(Res); + } + + uint32_t RI = 0; + uint32_t TakeI = 0; + auto &ResultList = *Res; + for (auto &HighTy : HigherFuncType.getReturnTypes()) { + switch (HighTy.getCode()) { + case TypeCode::String: { + auto Idx = ResultList[TakeI++].first.get<uint32_t>(); + auto Size = ResultList[TakeI++].first.get<uint32_t>(); + auto Str = Memory->getStringView(Idx, Size); + Rets[RI++] = StrVariant(std::string(Str.begin(), Str.end())); + break; + } + default: { + Rets[RI++] = ResultList[TakeI++].first; + break; + } + } + } + + return {}; + } + +private: + Executor *Exec; + Instance::FunctionInstance *LowerFunc; + Instance::MemoryInstance *Memory; + Instance::FunctionInstance *Realloc; +}; + +std::unique_ptr<Instance::FunctionInstance> +Executor::lifting(Runtime::Instance::ComponentInstance &Comp, + const FuncType &FuncType, Instance::FunctionInstance *Func, + Instance::MemoryInstance *Memory, + Instance::FunctionInstance *Realloc) { + auto R = std::make_unique<Instance::FunctionInstance>( + std::make_unique<LiftTrans>(this, FuncType, Func, Memory, Realloc, Comp)); + return R; +} + +class LowerTrans : public HostFunctionBase { +public: + LowerTrans(Executor *Exec, Instance::FunctionInstance *Func, + Instance::MemoryInstance *Memory, + Instance::FunctionInstance *Realloc) + : HostFunctionBase(0), Exec(Exec), HigherFunc(Func), Memory(Memory), + Realloc(Realloc) { + auto &HigherType = HigherFunc->getFuncType(); + + auto &FuncType = DefType.getCompositeType().getFuncType(); + for (auto &ParamTy : HigherType.getParamTypes()) { + switch (ParamTy.getCode()) { + case TypeCode::String: + FuncType.getParamTypes().push_back(TypeCode::I32); + FuncType.getParamTypes().push_back(TypeCode::I32); + break; + default: + FuncType.getParamTypes().push_back(ParamTy); + break; + } + } + + for (auto &ReturnTy : HigherType.getReturnTypes()) { + switch (ReturnTy.getCode()) { + case TypeCode::String: + FuncType.getReturnTypes().push_back(TypeCode::I32); + FuncType.getReturnTypes().push_back(TypeCode::I32); + break; + default: + FuncType.getReturnTypes().push_back(ReturnTy); + break; + } + } + + spdlog::info("lower: {}"sv, FuncType); + } + + Expect<void> run(const Runtime::CallingFrame &, Span<const ValVariant> Args, + Span<ValVariant> Rets) override { + auto &HigherFuncType = HigherFunc->getFuncType(); + + uint32_t PI = 0; + std::vector<ValVariant> HigherArgs{}; + for (auto &ParamTy : HigherFuncType.getParamTypes()) { + switch (ParamTy.getCode()) { + case TypeCode::String: { + auto Idx = Args[PI++]; + auto Len = Args[PI++]; + std::string_view V = + Memory->getStringView(Idx.get<uint32_t>(), Len.get<uint32_t>()); + std::string S{V.begin(), V.end()}; + HigherArgs.push_back(StrVariant(std::move(S))); + break; + } + default: + // usual type has no need conversion + const ValVariant &Arg = Args[PI++]; + HigherArgs.push_back(Arg); + break; + } + } + + auto Res = + Exec->invoke(HigherFunc, HigherArgs, HigherFuncType.getParamTypes()); + if (!Res) { + return Unexpect(Res); + } + + uint32_t RI = 0; + for (auto &[RetVal, RetTy] : *Res) { + switch (RetTy.getCode()) { + case TypeCode::String: { + auto const &Str = RetVal.get<StrVariant>().getString(); + + auto StrSize = static_cast<uint32_t>(Str.size()); + std::vector<ValVariant> ReallocArgs{ValVariant(0), ValVariant(0), + ValVariant(0), ValVariant(StrSize)}; + auto RPtr = Exec->invoke(Realloc, ReallocArgs, + Realloc->getFuncType().getParamTypes()); + if (!RPtr) { + return Unexpect(RPtr); + } + ValVariant V = (*RPtr)[0].first; + + Memory->setBytes(std::vector<Byte>{Str.begin(), Str.end()}, + V.get<uint32_t>(), 0, + static_cast<uint32_t>(Str.size())); + Rets[RI++] = V; + Rets[RI++] = ValVariant(StrSize); + break; + } + default: + Rets[RI++] = RetVal; + break; + } + } + + return {}; + } + +private: + Executor *Exec; + Instance::FunctionInstance *HigherFunc; + Instance::MemoryInstance *Memory; + Instance::FunctionInstance *Realloc; +}; + +std::unique_ptr<Instance::FunctionInstance> +Executor::lowering(Instance::FunctionInstance *Func, + Instance::MemoryInstance *Memory, + Instance::FunctionInstance *Realloc) { + auto R = std::make_unique<Instance::FunctionInstance>( + std::make_unique<LowerTrans>(this, Func, Memory, Realloc)); + return R; +} + +Expect<void> +Executor::instantiate(Runtime::StoreManager &, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::CanonSection &CanonSec) { + for (auto &C : CanonSec.getContent()) { + if (std::holds_alternative<Lift>(C)) { + // lift wrap a core wasm function to a component function, with proper + // modification about canonical ABI. + + const auto &L = std::get<Lift>(C); + + const auto &Opts = L.getOptions(); + + Runtime::Instance::MemoryInstance *Mem = nullptr; + Runtime::Instance::FunctionInstance *ReallocFunc = nullptr; + for (auto &Opt : Opts) { + if (std::holds_alternative<StringEncoding>(Opt)) { + spdlog::warn("incomplete canonical option `string-encoding`"sv); + } else if (std::holds_alternative<Memory>(Opt)) { + auto MemIdx = std::get<Memory>(Opt).getMemIndex(); + Mem = CompInst.getCoreMemoryInstance(MemIdx); + } else if (std::holds_alternative<Realloc>(Opt)) { + ReallocFunc = CompInst.getCoreFunctionInstance( + std::get<Realloc>(Opt).getFuncIndex()); + } else if (std::holds_alternative<PostReturn>(Opt)) { + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Canon)); + return Unexpect(ErrCode::Value::InvalidCanonOption); + } + } + + const auto &AstFuncType = CompInst.getType(L.getFuncTypeIndex()); + if (unlikely(!std::holds_alternative<FuncType>(AstFuncType))) { + // It doesn't make sense if one tries to lift an instance not a + // function, so unlikely happen. + spdlog::error("cannot lift a non-function"sv); + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Canon)); + return Unexpect(ErrCode::Value::InvalidCanonOption); + } + + auto *FuncInst = CompInst.getCoreFunctionInstance(L.getCoreFuncIndex()); + CompInst.addFunctionInstance(lifting(CompInst, + std::get<FuncType>(AstFuncType), + FuncInst, Mem, ReallocFunc)); + } else if (std::holds_alternative<Lower>(C)) { + // lower sends a component function to a core wasm function, with proper + // modification about canonical ABI. + const auto &L = std::get<Lower>(C); + + Runtime::Instance::MemoryInstance *Mem = nullptr; + Runtime::Instance::FunctionInstance *ReallocFunc = nullptr; + const auto &Opts = L.getOptions(); + for (auto &Opt : Opts) { + if (std::holds_alternative<StringEncoding>(Opt)) { + spdlog::warn("incomplete canonical option `string-encoding`"sv); + return Unexpect(ErrCode::Value::InvalidCanonOption); + } else if (std::holds_alternative<Memory>(Opt)) { + auto MemIdx = std::get<Memory>(Opt).getMemIndex(); + Mem = CompInst.getCoreMemoryInstance(MemIdx); + } else if (std::holds_alternative<Realloc>(Opt)) { + ReallocFunc = CompInst.getCoreFunctionInstance( + std::get<Realloc>(Opt).getFuncIndex()); + } else if (std::holds_alternative<PostReturn>(Opt)) { + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Canon)); + return Unexpect(ErrCode::Value::InvalidCanonOption); + } + } + + auto *FuncInst = CompInst.getFunctionInstance(L.getFuncIndex()); + CompInst.addCoreFunctionInstance(lowering(FuncInst, Mem, ReallocFunc)); + } else if (std::holds_alternative<ResourceNew>(C)) { + spdlog::warn("resource is not supported yet"sv); + return Unexpect(ErrCode::Value::InvalidCanonOption); + } else if (std::holds_alternative<ResourceDrop>(C)) { + spdlog::warn("resource is not supported yet"sv); + return Unexpect(ErrCode::Value::InvalidCanonOption); + } else if (std::holds_alternative<ResourceRep>(C)) { + spdlog::warn("resource is not supported yet"sv); + return Unexpect(ErrCode::Value::InvalidCanonOption); + } + } + + return {}; +} + +} // namespace Executor +} // namespace WasmEdge diff --git a/lib/executor/instantiate/component/instantiate_component_export.cpp b/lib/executor/instantiate/component/instantiate_component_export.cpp new file mode 100644 index 000000000000..784fe8482f7b --- /dev/null +++ b/lib/executor/instantiate/component/instantiate_component_export.cpp @@ -0,0 +1,65 @@ +#include "ast/component/instance.h" +#include "ast/module.h" +#include "common/errcode.h" +#include "executor/executor.h" + +#include "runtime/instance/module.h" + +#include <string_view> +#include <variant> + +namespace WasmEdge { +namespace Executor { + +using namespace std::literals; + +Expect<void> +Executor::instantiate(Runtime::StoreManager &, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::ExportSection &Sec) { + using namespace WasmEdge::AST::Component; + + for (const auto &Export : Sec.getContent()) { + auto &SortIndex = Export.getSortIndex(); + const auto &ExportName = Export.getName(); + + auto Index = SortIndex.getSortIdx(); + const auto &S = SortIndex.getSort(); + if (std::holds_alternative<CoreSort>(S)) { + switch (std::get<CoreSort>(S)) { + case CoreSort::Module: { + auto const *Mod = CompInst.getModuleInstance(Index); + CompInst.addExport(ExportName, Mod); + break; + } + default: + // Any exported sortidx, which disallows core sorts other than core + // module. + spdlog::error("export core sort other than core module is invalid."sv); + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_CompExport)); + return Unexpect(ErrCode::Value::InvalidCoreSort); + } + } else { + switch (std::get<SortCase>(S)) { + case SortCase::Func: { + auto *Func = CompInst.getFunctionInstance(Index); + CompInst.addExport(ExportName, Func); + break; + } + default: // TODO: There are four sorts haven't get handled + // 1. Value + // 2. Type + // 3. Component + // 4. Instance + spdlog::warn("incomplete sort {}"sv, + static_cast<Byte>(std::get<SortCase>(S))); + break; + } + } + } + + return {}; +} + +} // namespace Executor +} // namespace WasmEdge diff --git a/lib/executor/instantiate/component/instantiate_component_import.cpp b/lib/executor/instantiate/component/instantiate_component_import.cpp new file mode 100644 index 000000000000..e3bb10e30c07 --- /dev/null +++ b/lib/executor/instantiate/component/instantiate_component_import.cpp @@ -0,0 +1,62 @@ +#include "common/errcode.h" +#include "executor/executor.h" + +#include "runtime/instance/module.h" + +#include <string_view> +#include <variant> + +namespace WasmEdge { +namespace Executor { + +using namespace std::literals; +using namespace AST::Component; + +Expect<void> +Executor::instantiate(Runtime::StoreManager &StoreMgr, + Runtime::Instance::ComponentInstance &CompInst, + const ImportSection &Sec) { + for (auto &ImportStatement : Sec.getContent()) { + auto &Desc = ImportStatement.getDesc(); + if (std::holds_alternative<DescTypeIndex>(Desc)) { + auto &TypeIndex = std::get<DescTypeIndex>(Desc); + + // TODO: get type via index `TypeIndex.getIndex()`, then use the type to + // check the imported thing + + switch (TypeIndex.getKind()) { + case IndexKind::CoreType: // TODO + spdlog::warn("incomplete import core type"sv); + break; + case IndexKind::FuncType: // TODO + spdlog::warn("incomplete import function"sv); + break; + case IndexKind::ComponentType: // TODO + spdlog::warn("incomplete import component"sv); + break; + case IndexKind::InstanceType: + auto CompName = ImportStatement.getName(); + const auto *ImportedCompInst = StoreMgr.findComponent(CompName); + if (unlikely(ImportedCompInst == nullptr)) { + spdlog::error(ErrCode::Value::UnknownImport); + spdlog::error("component name: {}"sv, CompName); + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_CompImport)); + return Unexpect(ErrCode::Value::UnknownImport); + } + CompInst.addComponentInstance(ImportedCompInst); + break; + } + } else if (std::holds_alternative<TypeBound>(Desc)) { + // TODO: import a type or resource + spdlog::warn("incomplete import type bound"sv); + } else if (std::holds_alternative<ValueType>(Desc)) { + // TODO: import a value and check its type, this is a new concept, so a + // plugin of component should allow this + spdlog::warn("incomplete import value type"sv); + } + } + return {}; +} + +} // namespace Executor +} // namespace WasmEdge diff --git a/lib/executor/instantiate/component/instantiate_component_instance.cpp b/lib/executor/instantiate/component/instantiate_component_instance.cpp new file mode 100644 index 000000000000..68b34351ff8b --- /dev/null +++ b/lib/executor/instantiate/component/instantiate_component_instance.cpp @@ -0,0 +1,173 @@ +#include "ast/component/instance.h" +#include "ast/module.h" +#include "common/errcode.h" +#include "executor/executor.h" + +#include "runtime/instance/module.h" + +#include <string_view> +#include <variant> + +namespace WasmEdge { +namespace Executor { + +using namespace std::literals; +using namespace AST::Component; + +Expect<void> +Executor::instantiate(Runtime::StoreManager &StoreMgr, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::CoreInstanceSection &Sec) { + // In this function, we will create a new module instance and insert it into + // component module instance index space. + for (const CoreInstanceExpr &InstExpr : Sec.getContent()) { + if (std::holds_alternative<CoreInstantiate>(InstExpr)) { + auto &Instantiate = std::get<CoreInstantiate>(InstExpr); + + for (auto &Arg : Instantiate.getArgs()) { + // instantiate a list of `(with (name $instance))` + // each $instance get named as `name` as statement tell + StoreMgr.addNamedModule(Arg.getName(), + CompInst.getModuleInstance(Arg.getIndex())); + } + const AST::Module &Mod = CompInst.getModule(Instantiate.getModuleIdx()); + auto Res = instantiate(StoreMgr, Mod); + if (!Res) { + return Unexpect(Res); + } + CompInst.addModuleInstance(std::move(*Res)); + } else { + auto &InstantiateExpr = + std::get<AST::Component::CoreInlineExports>(InstExpr); + + // create an immediate module instance, which has no name + // + // this happened usually at `(with xxx)` statement, where we can have a + // module instance expression. + auto M = std::make_unique<Runtime::Instance::ModuleInstance>(""); + + for (auto &S : InstantiateExpr.getExports()) { + const auto &SortIdx = S.getSortIdx(); + switch (SortIdx.getSort()) { + case CoreSort::Func: { + // The module instance takes functions and export them + M->exportFunction( + S.getName(), + // get stored core function + CompInst.getCoreFunctionInstance(SortIdx.getSortIdx())); + break; + } + case CoreSort::Table: { + M->exportTable(S.getName(), + CompInst.getCoreTableInstance(SortIdx.getSortIdx())); + break; + } + case CoreSort::Memory: { + M->exportMemory(S.getName(), + CompInst.getCoreMemoryInstance(SortIdx.getSortIdx())); + break; + } + case CoreSort::Global: { + M->exportGlobal(S.getName(), + CompInst.getCoreGlobalInstance(SortIdx.getSortIdx())); + break; + } + case CoreSort::Type: + case CoreSort::Module: + case CoreSort::Instance: { + spdlog::error( + "A module instance cannot exports types, modules, or instances"sv); + return Unexpect(ErrCode::Value::CoreInvalidExport); + } + } + } + + // insert this immediate module instance into the component instance + CompInst.addModuleInstance(std::move(M)); + } + } + return {}; +} + +Expect<void> +Executor::instantiate(Runtime::StoreManager &StoreMgr, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::InstanceSection &Sec) { + for (auto &InstExpr : Sec.getContent()) { + if (std::holds_alternative<AST::Component::Instantiate>(InstExpr)) { + auto &Instantiate = std::get<AST::Component::Instantiate>(InstExpr); + + for (auto &Arg : Instantiate.getArgs()) { + const auto &Idx = Arg.getIndex(); + const auto &S = Idx.getSort(); + if (std::holds_alternative<CoreSort>(S)) { + // TODO: insert below into mapping + switch (std::get<CoreSort>(S)) { + case CoreSort::Func: + spdlog::warn("incomplete (with {}) core:func"sv, Arg.getName()); + break; + case CoreSort::Table: + spdlog::warn("incomplete (with {}) core:table"sv, Arg.getName()); + break; + case CoreSort::Memory: + spdlog::warn("incomplete (with {}) core:memory"sv, Arg.getName()); + break; + case CoreSort::Global: + spdlog::warn("incomplete (with {}) core:global"sv, Arg.getName()); + break; + case CoreSort::Type: + spdlog::warn("incomplete (with {}) core:type"sv, Arg.getName()); + break; + case CoreSort::Module: + spdlog::warn("incomplete (with {}) core:module"sv, Arg.getName()); + break; + case CoreSort::Instance: + StoreMgr.addNamedModule( + Arg.getName(), CompInst.getModuleInstance(Idx.getSortIdx())); + break; + } + } else if (std::holds_alternative<SortCase>(S)) { + switch (std::get<SortCase>(S)) { + case SortCase::Func: // TODO: figure out how to do this registry + spdlog::warn("incomplete (with {}) function"sv, Arg.getName()); + break; + case SortCase::Value: // TODO: figure out how to do this registry + spdlog::warn("incomplete (with {}) value"sv, Arg.getName()); + break; + case SortCase::Type: // TODO: figure out how to do this registry + spdlog::warn("incomplete (with {}) type"sv, Arg.getName()); + break; + case SortCase::Component: + if (auto Res = StoreMgr.registerComponent( + Arg.getName(), + CompInst.getComponentInstance(Idx.getSortIdx())); + !Res) { + spdlog::error("failed to register component instance"sv); + return Unexpect(Res); + } + break; + case SortCase::Instance: + // TODO: figure out how to do this registry + spdlog::warn("incomplete (with {}) instance"sv, Arg.getName()); + break; + } + } + } + auto &C = CompInst.getComponent(Instantiate.getComponentIdx()); + auto Res = instantiate(StoreMgr, C); + if (!Res) { + return Unexpect(Res); + } + auto Inst = std::move(*Res); + CompInst.addComponentInstance(std::move(Inst)); + } else { + std::get<CompInlineExports>(InstExpr).getExports(); + // TODO: complete inline exports + spdlog::warn("incomplete component inline exports"sv); + } + } + return {}; +} + +} // namespace Executor +} // namespace WasmEdge diff --git a/lib/executor/instantiate/component/instantiate_component_start.cpp b/lib/executor/instantiate/component/instantiate_component_start.cpp new file mode 100644 index 000000000000..d171e3b81461 --- /dev/null +++ b/lib/executor/instantiate/component/instantiate_component_start.cpp @@ -0,0 +1,25 @@ +#include "ast/component/instance.h" +#include "ast/module.h" +#include "common/errcode.h" +#include "executor/executor.h" + +#include "runtime/instance/module.h" + +#include <string_view> +#include <variant> + +namespace WasmEdge { +namespace Executor { + +using namespace std::literals; +using namespace AST::Component; + +Expect<void> Executor::instantiate(Runtime::StoreManager &, + Runtime::Instance::ComponentInstance &, + const AST::Component::StartSection &) { + spdlog::warn("start section is not supported yet"sv); + return {}; +} + +} // namespace Executor +} // namespace WasmEdge diff --git a/lib/executor/instantiate/component/instantiate_component_type.cpp b/lib/executor/instantiate/component/instantiate_component_type.cpp new file mode 100644 index 000000000000..3735392ee8eb --- /dev/null +++ b/lib/executor/instantiate/component/instantiate_component_type.cpp @@ -0,0 +1,35 @@ +#include "ast/component/instance.h" +#include "ast/module.h" +#include "common/errcode.h" +#include "executor/executor.h" + +#include "runtime/instance/module.h" + +#include <string_view> +#include <variant> + +namespace WasmEdge { +namespace Executor { + +Expect<void> +Executor::instantiate(Runtime::StoreManager &, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::CoreTypeSection &CoreTypeSec) { + for (auto &Ty : CoreTypeSec.getContent()) { + CompInst.addCoreType(Ty); + } + return {}; +} + +Expect<void> +Executor::instantiate(Runtime::StoreManager &, + Runtime::Instance::ComponentInstance &CompInst, + const AST::Component::TypeSection &TySec) { + for (auto &Ty : TySec.getContent()) { + CompInst.addType(Ty); + } + return {}; +} + +} // namespace Executor +} // namespace WasmEdge diff --git a/lib/executor/instantiate/data.cpp b/lib/executor/instantiate/data.cpp index 3e1d6ec13b63..77cc0e19d546 100644 --- a/lib/executor/instantiate/data.cpp +++ b/lib/executor/instantiate/data.cpp @@ -1,10 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" #include <cstdint> @@ -94,7 +94,8 @@ Expect<void> Executor::initMemory(Runtime::StackManager &StackMgr, return {}; } -Expect<uint32_t> Executor::dataSegmentOffset(Runtime::StackManager &StackMgr, const AST::DataSegment &DataSeg) { +Expect<uint32_t> Executor::dataSegmentOffset(Runtime::StackManager &StackMgr, + const AST::DataSegment &DataSeg) { if (DataSeg.getMode() == AST::DataSegment::DataMode::Active) { if (auto Res = runExpression(StackMgr, DataSeg.getExpr().getInstrs()); unlikely(!Res)) { diff --git a/lib/executor/instantiate/elem.cpp b/lib/executor/instantiate/elem.cpp index 9643b396c465..79519054c239 100644 --- a/lib/executor/instantiate/elem.cpp +++ b/lib/executor/instantiate/elem.cpp @@ -1,10 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" #include <cstdint> #include <vector> diff --git a/lib/executor/instantiate/export.cpp b/lib/executor/instantiate/export.cpp index d7daa24e6cf5..f123cc748890 100644 --- a/lib/executor/instantiate/export.cpp +++ b/lib/executor/instantiate/export.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" @@ -33,6 +33,9 @@ Expect<void> Executor::instantiate(Runtime::Instance::ModuleInstance &ModInst, case ExternalType::Table: ModInst.exportTable(ExtName, ExtIdx); break; + case ExternalType::Tag: + ModInst.exportTag(ExtName, ExtIdx); + break; default: break; } diff --git a/lib/executor/instantiate/function.cpp b/lib/executor/instantiate/function.cpp index d0239bac0506..a8679a92f766 100644 --- a/lib/executor/instantiate/function.cpp +++ b/lib/executor/instantiate/function.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" @@ -27,17 +27,20 @@ Expect<void> Executor::instantiate(Runtime::Instance::ModuleInstance &ModInst, // and dispatch it into different cases to reduce branch misses. if (CodeSegs[0].getSymbol() != false) { for (uint32_t I = 0; I < CodeSegs.size(); ++I) { - auto *FuncType = *ModInst.getFuncType(TypeIdxs[I]); auto Symbol = CodeSegs[I].getSymbol(); - ModInst.addFunc(*FuncType, std::move(Symbol)); + ModInst.addFunc( + TypeIdxs[I], + (*ModInst.getType(TypeIdxs[I]))->getCompositeType().getFuncType(), + std::move(Symbol)); } } else { // Iterate through the code segments to instantiate function instances. for (uint32_t I = 0; I < CodeSegs.size(); ++I) { // Create and add the function instance into the module instance. - auto *FuncType = *ModInst.getFuncType(TypeIdxs[I]); - ModInst.addFunc(*FuncType, CodeSegs[I].getLocals(), - CodeSegs[I].getExpr().getInstrs()); + ModInst.addFunc( + TypeIdxs[I], + (*ModInst.getType(TypeIdxs[I]))->getCompositeType().getFuncType(), + CodeSegs[I].getLocals(), CodeSegs[I].getExpr().getInstrs()); } } return {}; diff --git a/lib/executor/instantiate/global.cpp b/lib/executor/instantiate/global.cpp index 76b1efb346d2..505e7adb5804 100644 --- a/lib/executor/instantiate/global.cpp +++ b/lib/executor/instantiate/global.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" diff --git a/lib/executor/instantiate/import.cpp b/lib/executor/instantiate/import.cpp index 612a6b8f7913..49bf8bcedb1f 100644 --- a/lib/executor/instantiate/import.cpp +++ b/lib/executor/instantiate/import.cpp @@ -1,10 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" #include <cstdint> #include <string_view> @@ -70,6 +70,11 @@ checkImportMatched(std::string_view ModName, std::string_view ExtName, return {}; } break; + case ExternalType::Tag: + if (auto Res = ModInst.findTagExports(ExtName); likely(Res != nullptr)) { + return {}; + } + break; default: return logUnknownError(ModName, ExtName, ExtType); } @@ -87,6 +92,9 @@ checkImportMatched(std::string_view ModName, std::string_view ExtName, return logMatchError(ModName, ExtName, ExtType, ExtType, ExternalType::Memory); } + if (ModInst.findTagExports(ExtName)) { + return logMatchError(ModName, ExtName, ExtType, ExtType, ExternalType::Tag); + } if (ModInst.findGlobalExports(ExtName)) { return logMatchError(ModName, ExtName, ExtType, ExtType, ExternalType::Global); @@ -106,8 +114,8 @@ Expect<void> Executor::instantiate(Runtime::StoreManager &StoreMgr, auto ExtType = ImpDesc.getExternalType(); auto ModName = ImpDesc.getModuleName(); auto ExtName = ImpDesc.getExternalName(); - const auto *TargetModInst = StoreMgr.findModule(ModName); - if (unlikely(TargetModInst == nullptr)) { + const auto *ImpModInst = StoreMgr.findModule(ModName); + if (unlikely(ImpModInst == nullptr)) { auto Res = logUnknownError(ModName, ExtName, ExtType); if (ModName == "wasi_snapshot_preview1") { spdlog::error(" This is a WASI related import. Please ensure that " @@ -132,8 +140,7 @@ Expect<void> Executor::instantiate(Runtime::StoreManager &StoreMgr, } return Res; } - if (auto Res = - checkImportMatched(ModName, ExtName, ExtType, *TargetModInst); + if (auto Res = checkImportMatched(ModName, ExtName, ExtType, *ImpModInst); unlikely(!Res)) { return Unexpect(Res); } @@ -144,16 +151,17 @@ Expect<void> Executor::instantiate(Runtime::StoreManager &StoreMgr, // Get function type index. External type checked in validation. uint32_t TypeIdx = ImpDesc.getExternalFuncTypeIdx(); // Import matching. - auto *TargetInst = TargetModInst->findFuncExports(ExtName); - const auto &TargetType = TargetInst->getFuncType(); - const auto *FuncType = *ModInst.getFuncType(TypeIdx); + auto *ImpInst = ImpModInst->findFuncExports(ExtName); // External function type should match the import function type in // description. - if (!matchTypes(ModInst, FuncType->getParamTypes(), *TargetModInst, - TargetType.getParamTypes()) || - !matchTypes(ModInst, FuncType->getReturnTypes(), *TargetModInst, - TargetType.getReturnTypes())) { + + if (!AST::TypeMatcher::matchType(ModInst.getTypeList(), TypeIdx, + ImpModInst->getTypeList(), + ImpInst->getTypeIndex())) { + const auto &ExpDefType = **ModInst.getType(TypeIdx); bool IsMatchV2 = false; + const auto &ExpFuncType = ExpDefType.getCompositeType().getFuncType(); + const auto &ImpFuncType = ImpInst->getFuncType(); if (ModName == "wasi_snapshot_preview1") { /* * The following functions should provide V1 and V2. @@ -177,11 +185,12 @@ Expect<void> Executor::instantiate(Runtime::StoreManager &StoreMgr, for (auto Iter = CompatibleWASISocketAPI.begin(); Iter != CompatibleWASISocketAPI.end(); Iter++) { if (ExtName == *Iter) { - auto *TargetInstV2 = - TargetModInst->findFuncExports(*Iter + "_v2"); - if (TargetInstV2->getFuncType() == *FuncType) { + auto *ImpInstV2 = ImpModInst->findFuncExports(*Iter + "_v2"); + if (!AST::TypeMatcher::matchType( + ModInst.getTypeList(), *ExpDefType.getTypeIndex(), + ImpModInst->getTypeList(), ImpInst->getTypeIndex())) { // Try to match the new version - TargetInst = TargetInstV2; + ImpInst = ImpInstV2; IsMatchV2 = true; break; } @@ -190,13 +199,13 @@ Expect<void> Executor::instantiate(Runtime::StoreManager &StoreMgr, } if (!IsMatchV2) { return logMatchError( - ModName, ExtName, ExtType, FuncType->getParamTypes(), - FuncType->getReturnTypes(), TargetType.getParamTypes(), - TargetType.getReturnTypes()); + ModName, ExtName, ExtType, ExpFuncType.getParamTypes(), + ExpFuncType.getReturnTypes(), ImpFuncType.getParamTypes(), + ImpFuncType.getReturnTypes()); } } // Set the matched function address to module instance. - ModInst.importFunction(TargetInst); + ModInst.importFunction(ImpInst); break; } case ExternalType::Table: { @@ -205,23 +214,25 @@ Expect<void> Executor::instantiate(Runtime::StoreManager &StoreMgr, const auto &TabLim = TabType.getLimit(); // Import matching. External table type should match the one in import // description. - auto *TargetInst = TargetModInst->findTableExports(ExtName); - const auto &TargetType = TargetInst->getTableType(); - const auto &TargetLim = TargetType.getLimit(); + auto *ImpInst = ImpModInst->findTableExports(ExtName); + const auto &ImpType = ImpInst->getTableType(); + const auto &ImpLim = ImpType.getLimit(); // External table reference type should match the import table reference // type in description, and vice versa. - if (!matchType(ModInst, TabType.getRefType(), *TargetModInst, - TargetType.getRefType()) || - !matchType(*TargetModInst, TargetType.getRefType(), ModInst, - TabType.getRefType()) || - !matchLimit(TabLim, TargetLim)) { + if (!AST::TypeMatcher::matchType( + ModInst.getTypeList(), TabType.getRefType(), + ImpModInst->getTypeList(), ImpType.getRefType()) || + !AST::TypeMatcher::matchType( + ImpModInst->getTypeList(), ImpType.getRefType(), + ModInst.getTypeList(), TabType.getRefType()) || + !matchLimit(TabLim, ImpLim)) { return logMatchError(ModName, ExtName, ExtType, TabType.getRefType(), TabLim.hasMax(), TabLim.getMin(), TabLim.getMax(), - TargetType.getRefType(), TargetLim.hasMax(), - TargetLim.getMin(), TargetLim.getMax()); + ImpType.getRefType(), ImpLim.hasMax(), + ImpLim.getMin(), ImpLim.getMax()); } // Set the matched table address to module instance. - ModInst.importTable(TargetInst); + ModInst.importTable(ImpInst); break; } case ExternalType::Memory: { @@ -230,16 +241,35 @@ Expect<void> Executor::instantiate(Runtime::StoreManager &StoreMgr, const auto &MemLim = MemType.getLimit(); // Import matching. External memory type should match the one in import // description. - auto *TargetInst = TargetModInst->findMemoryExports(ExtName); - const auto &TargetLim = TargetInst->getMemoryType().getLimit(); - if (!matchLimit(MemLim, TargetLim)) { + auto *ImpInst = ImpModInst->findMemoryExports(ExtName); + const auto &ImpLim = ImpInst->getMemoryType().getLimit(); + if (!matchLimit(MemLim, ImpLim)) { return logMatchError(ModName, ExtName, ExtType, MemLim.hasMax(), - MemLim.getMin(), MemLim.getMax(), - TargetLim.hasMax(), TargetLim.getMin(), - TargetLim.getMax()); + MemLim.getMin(), MemLim.getMax(), ImpLim.hasMax(), + ImpLim.getMin(), ImpLim.getMax()); } // Set the matched memory address to module instance. - ModInst.importMemory(TargetInst); + ModInst.importMemory(ImpInst); + break; + } + case ExternalType::Tag: { + // Get tag type. External type checked in validation. + const auto &TagType = ImpDesc.getExternalTagType(); + // Import matching. + auto *ImpInst = ImpModInst->findTagExports(ExtName); + if (!AST::TypeMatcher::matchType( + ModInst.getTypeList(), TagType.getTypeIdx(), + ImpModInst->getTypeList(), ImpInst->getTagType().getTypeIdx())) { + const auto &ExpFuncType = + TagType.getDefType().getCompositeType().getFuncType(); + const auto &ImpFuncType = + ImpInst->getTagType().getDefType().getCompositeType().getFuncType(); + return logMatchError( + ModName, ExtName, ExtType, ExpFuncType.getParamTypes(), + ExpFuncType.getReturnTypes(), ImpFuncType.getParamTypes(), + ImpFuncType.getReturnTypes()); + } + ModInst.importTag(ImpInst); break; } case ExternalType::Global: { @@ -247,28 +277,30 @@ Expect<void> Executor::instantiate(Runtime::StoreManager &StoreMgr, const auto &GlobType = ImpDesc.getExternalGlobalType(); // Import matching. External global type should match the one in // import description. - auto *TargetInst = TargetModInst->findGlobalExports(ExtName); - const auto &TargetType = TargetInst->getGlobalType(); + auto *ImpInst = ImpModInst->findGlobalExports(ExtName); + const auto &ImpType = ImpInst->getGlobalType(); bool IsMatch = false; - if (TargetType.getValMut() == GlobType.getValMut()) { + if (ImpType.getValMut() == GlobType.getValMut()) { // For both const or both var: external global value type should match // the import global value type in description. - IsMatch = matchType(ModInst, GlobType.getValType(), *TargetModInst, - TargetType.getValType()); - if (TargetType.getValMut() == ValMut::Var) { + IsMatch = AST::TypeMatcher::matchType( + ModInst.getTypeList(), GlobType.getValType(), + ImpModInst->getTypeList(), ImpType.getValType()); + if (ImpType.getValMut() == ValMut::Var) { // If both var: import global value type in description should also // match the external global value type. - IsMatch &= matchType(*TargetModInst, TargetType.getValType(), ModInst, - GlobType.getValType()); + IsMatch &= AST::TypeMatcher::matchType( + ImpModInst->getTypeList(), ImpType.getValType(), + ModInst.getTypeList(), GlobType.getValType()); } } if (!IsMatch) { return logMatchError(ModName, ExtName, ExtType, GlobType.getValType(), - GlobType.getValMut(), TargetType.getValType(), - TargetType.getValMut()); + GlobType.getValMut(), ImpType.getValType(), + ImpType.getValMut()); } // Set the matched global address to module instance. - ModInst.importGlobal(TargetInst); + ModInst.importGlobal(ImpInst); break; } default: diff --git a/lib/executor/instantiate/memory.cpp b/lib/executor/instantiate/memory.cpp index fc5363e2af1c..227ca46d173a 100644 --- a/lib/executor/instantiate/memory.cpp +++ b/lib/executor/instantiate/memory.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" diff --git a/lib/executor/instantiate/module.cpp b/lib/executor/instantiate/module.cpp index f6f73d58e8cb..11cdd900bedc 100644 --- a/lib/executor/instantiate/module.cpp +++ b/lib/executor/instantiate/module.cpp @@ -1,10 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" #include <cstdint> #include <string_view> @@ -45,9 +45,9 @@ Executor::instantiate(Runtime::StoreManager &StoreMgr, const AST::Module &Mod, } // Instantiate Function Types in Module Instance. (TypeSec) - for (auto &FuncType : Mod.getTypeSection().getContent()) { - // Copy param and return lists to module instance. - ModInst->addFuncType(FuncType); + for (auto &SubType : Mod.getTypeSection().getContent()) { + // Copy defined types to module instance. + ModInst->addDefinedType(SubType); } // Instantiate ImportSection and do import matching. (ImportSec) @@ -70,18 +70,13 @@ Executor::instantiate(Runtime::StoreManager &StoreMgr, const AST::Module &Mod, // This function will always success. instantiate(*ModInst, MemSec); - // Add a temp module to Store with only imported globals for initialization. - std::unique_ptr<Runtime::Instance::ModuleInstance> TmpModInst = - std::make_unique<Runtime::Instance::ModuleInstance>(""); - for (uint32_t I = 0; I < ModInst->getGlobalImportNum(); ++I) { - TmpModInst->importGlobal(*(ModInst->getGlobal(I))); - } - for (uint32_t I = 0; I < ModInst->getFuncNum(); ++I) { - TmpModInst->importFunction(*(ModInst->getFunc(I))); - } + // Instantiate TagSection (TagSec) + const AST::TagSection &TagSec = Mod.getTagSection(); + // This function will always success. + instantiate(*ModInst, TagSec); - // Push a new frame {TmpModInst:{globaddrs}, locals:none} - StackMgr.pushFrame(TmpModInst.get(), AST::InstrView::iterator(), 0, 0); + // Push a new frame {ModInst, locals:none} + StackMgr.pushFrame(ModInst.get(), AST::InstrView::iterator(), 0, 0); // Instantiate GlobalSection (GlobalSec) const AST::GlobalSection &GlobSec = Mod.getGlobalSection(); @@ -101,17 +96,11 @@ Executor::instantiate(Runtime::StoreManager &StoreMgr, const AST::Module &Mod, return Unexpect(Res); } - // Pop frame with the temp. module. - StackMgr.popFrame(); - // Instantiate ExportSection (ExportSec) const AST::ExportSection &ExportSec = Mod.getExportSection(); // This function will always success. instantiate(*ModInst, ExportSec); - // Push a new frame {ModInst, locals:none} - StackMgr.pushFrame(ModInst.get(), AST::InstrView::iterator(), 0, 0); - // Instantiate ElementSection (ElemSec) const AST::ElementSection &ElemSec = Mod.getElementSection(); if (auto Res = instantiate(StackMgr, *ModInst, ElemSec); !Res) { diff --git a/lib/executor/instantiate/table.cpp b/lib/executor/instantiate/table.cpp index a633e7683898..599e0e59bb21 100644 --- a/lib/executor/instantiate/table.cpp +++ b/lib/executor/instantiate/table.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "executor/executor.h" diff --git a/lib/executor/instantiate/tag.cpp b/lib/executor/instantiate/tag.cpp new file mode 100644 index 000000000000..4bd20f155978 --- /dev/null +++ b/lib/executor/instantiate/tag.cpp @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "executor/executor.h" + +namespace WasmEdge { +namespace Executor { + +// Instantiate tag instance. See "include/executor/executor.h". +Expect<void> Executor::instantiate(Runtime::Instance::ModuleInstance &ModInst, + const AST::TagSection &TagSec) { + // Iterate through the tags to instantiate the tag instances. + for (const auto &TgType : TagSec.getContent()) { + // Add Tag with corresponding Type. + auto SubTypePtr = *ModInst.getType(TgType.getTypeIdx()); + ModInst.addTag(TgType, SubTypePtr); + } + return {}; +} + +} // namespace Executor +} // namespace WasmEdge diff --git a/lib/host/CMakeLists.txt b/lib/host/CMakeLists.txt index e865f9467379..f7568bac9a3e 100644 --- a/lib/host/CMakeLists.txt +++ b/lib/host/CMakeLists.txt @@ -1,4 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC add_subdirectory(wasi) diff --git a/lib/host/wasi/CMakeLists.txt b/lib/host/wasi/CMakeLists.txt index 01be02b19dd7..970c7363095f 100644 --- a/lib/host/wasi/CMakeLists.txt +++ b/lib/host/wasi/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC if(APPLE) set(WASMEDGE_WASI_SRCS clock-macos.cpp environ-macos.cpp inode-macos.cpp macos.mm) @@ -38,6 +38,7 @@ endif() if(WIN32) target_link_libraries(wasmedgeHostModuleWasi PRIVATE + ktmw32 ntdll wsock32 ws2_32 diff --git a/lib/host/wasi/clock-linux.cpp b/lib/host/wasi/clock-linux.cpp index 894df5b096c7..4e90a0aa6280 100644 --- a/lib/host/wasi/clock-linux.cpp +++ b/lib/host/wasi/clock-linux.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #if WASMEDGE_OS_LINUX diff --git a/lib/host/wasi/clock-macos.cpp b/lib/host/wasi/clock-macos.cpp index 6a25f3f87b0b..53d0e1bca887 100644 --- a/lib/host/wasi/clock-macos.cpp +++ b/lib/host/wasi/clock-macos.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #if WASMEDGE_OS_MACOS diff --git a/lib/host/wasi/clock-win.cpp b/lib/host/wasi/clock-win.cpp index 8a2e5c9873f5..7666c8c7bec9 100644 --- a/lib/host/wasi/clock-win.cpp +++ b/lib/host/wasi/clock-win.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #if WASMEDGE_OS_WINDOWS diff --git a/lib/host/wasi/environ-linux.cpp b/lib/host/wasi/environ-linux.cpp index 23c624df747b..eedd8f6ede3c 100644 --- a/lib/host/wasi/environ-linux.cpp +++ b/lib/host/wasi/environ-linux.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #if WASMEDGE_OS_LINUX diff --git a/lib/host/wasi/environ-macos.cpp b/lib/host/wasi/environ-macos.cpp index a92ea11420a4..717c8dc49dfb 100644 --- a/lib/host/wasi/environ-macos.cpp +++ b/lib/host/wasi/environ-macos.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #if WASMEDGE_OS_MACOS diff --git a/lib/host/wasi/environ-win.cpp b/lib/host/wasi/environ-win.cpp index f5605a90bc59..db9a54bd4ac3 100644 --- a/lib/host/wasi/environ-win.cpp +++ b/lib/host/wasi/environ-win.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #if WASMEDGE_OS_WINDOWS diff --git a/lib/host/wasi/environ.cpp b/lib/host/wasi/environ.cpp index be0d904704bb..48c642cd9611 100644 --- a/lib/host/wasi/environ.cpp +++ b/lib/host/wasi/environ.cpp @@ -1,9 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "host/wasi/environ.h" #include "common/errcode.h" -#include "common/log.h" +#include "common/spdlog.h" #include "host/wasi/vfs.h" #include "host/wasi/vinode.h" diff --git a/lib/host/wasi/inode-linux.cpp b/lib/host/wasi/inode-linux.cpp index 8307465e62b1..c248797b10ee 100644 --- a/lib/host/wasi/inode-linux.cpp +++ b/lib/host/wasi/inode-linux.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #if WASMEDGE_OS_LINUX @@ -82,14 +82,11 @@ constexpr int openFlags(__wasi_oflags_t OpenFlags, __wasi_fdflags_t FdFlags, if (OpenFlags & __WASI_OFLAGS_EXCL) { Flags |= O_EXCL; } - if (OpenFlags & __WASI_OFLAGS_TRUNC) { + if ((OpenFlags & __WASI_OFLAGS_TRUNC) && (VFSFlags & VFS::Write)) { Flags |= O_TRUNC; } // Convert file descriptor flags. - if ((FdFlags & __WASI_FDFLAGS_APPEND) != 0) { - Flags |= O_APPEND; - } if ((FdFlags & __WASI_FDFLAGS_DSYNC) != 0) { #ifdef O_DSYNC Flags |= O_DSYNC; @@ -171,7 +168,8 @@ WasiExpect<INode> INode::open(std::string Path, __wasi_oflags_t OpenFlags, if (auto NewFd = ::open(Path.c_str(), Flags, 0644); unlikely(NewFd < 0)) { return WasiUnexpect(fromErrNo(errno)); } else { - INode New(NewFd); + INode New(NewFd, true, FdFlags & __WASI_FDFLAGS_APPEND); + #ifndef O_CLOEXEC if (auto Res = ::fcntl(New.Fd, F_SETFD, FD_CLOEXEC); unlikely(Res != 0)) { return WasiUnexpect(fromErrNo(errno)); @@ -195,7 +193,9 @@ WasiExpect<void> INode::fdAdvise(__wasi_filesize_t Offset, WasiExpect<void> INode::fdAllocate(__wasi_filesize_t Offset, __wasi_filesize_t Len) const noexcept { if (auto Res = ::posix_fallocate(Fd, Offset, Len); unlikely(Res != 0)) { - return WasiUnexpect(fromErrNo(errno)); + // https://man7.org/linux/man-pages/man3/posix_fallocate.3.html + // posix_fallocate will not set errno, use return the value directly. + return WasiUnexpect(fromErrNo(Res)); } return {}; @@ -220,7 +220,7 @@ WasiExpect<void> INode::fdFdstatGet(__wasi_fdstat_t &FdStat) const noexcept { FdStat.fs_filetype = unsafeFiletype(); FdStat.fs_flags = static_cast<__wasi_fdflags_t>(0); - if (FdFlags & O_APPEND) { + if (Append) { FdStat.fs_flags |= __WASI_FDFLAGS_APPEND; } if (FdFlags & O_DSYNC) { @@ -243,9 +243,6 @@ INode::fdFdstatSetFlags(__wasi_fdflags_t FdFlags) const noexcept { if (FdFlags & __WASI_FDFLAGS_NONBLOCK) { SysFlag |= O_NONBLOCK; } - if (FdFlags & __WASI_FDFLAGS_APPEND) { - SysFlag |= O_APPEND; - } if (FdFlags & __WASI_FDFLAGS_DSYNC) { SysFlag |= O_DSYNC; } @@ -260,6 +257,7 @@ INode::fdFdstatSetFlags(__wasi_fdflags_t FdFlags) const noexcept { return WasiUnexpect(fromErrNo(errno)); } + Append = FdFlags & __WASI_FDFLAGS_APPEND; return {}; } @@ -578,6 +576,10 @@ WasiExpect<void> INode::fdWrite(Span<Span<const uint8_t>> IOVs, ++SysIOVsSize; } + if (Append) { + ::lseek(Fd, 0, SEEK_END); + } + if (auto Res = ::writev(Fd, SysIOVs, SysIOVsSize); unlikely(Res < 0)) { return WasiUnexpect(fromErrNo(errno)); } else { @@ -610,7 +612,7 @@ INode::pathFilestatGet(std::string Path, Filestat.dev = SysFStat.st_dev; Filestat.ino = SysFStat.st_ino; - Filestat.filetype = fromFileType(SysFStat.st_mode); + Filestat.filetype = fromFileType(static_cast<mode_t>(SysFStat.st_mode)); Filestat.nlink = SysFStat.st_nlink; Filestat.size = SysFStat.st_size; Filestat.atim = fromTimespec(SysFStat.st_atim); @@ -733,7 +735,8 @@ WasiExpect<INode> INode::pathOpen(std::string Path, __wasi_oflags_t OpenFlags, unlikely(NewFd < 0)) { return WasiUnexpect(fromErrNo(errno)); } else { - INode New(NewFd); + INode New(NewFd, true, FdFlags & __WASI_FDFLAGS_APPEND); + #ifndef O_CLOEXEC if (auto Res = ::fcntl(New.Fd, F_SETFD, FD_CLOEXEC); unlikely(Res != 0)) { return WasiUnexpect(fromErrNo(errno)); @@ -1371,7 +1374,7 @@ INode::sockGetPeerAddr(__wasi_address_family_t *AddressFamilyPtr, } __wasi_filetype_t INode::unsafeFiletype() const noexcept { - return fromFileType(Stat->st_mode); + return fromFileType(static_cast<mode_t>(Stat->st_mode)); } WasiExpect<__wasi_filetype_t> INode::filetype() const noexcept { diff --git a/lib/host/wasi/inode-macos.cpp b/lib/host/wasi/inode-macos.cpp index cc461aa653a8..3d8dd0390322 100644 --- a/lib/host/wasi/inode-macos.cpp +++ b/lib/host/wasi/inode-macos.cpp @@ -1,11 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #if WASMEDGE_OS_MACOS #include "common/errcode.h" -#include "common/log.h" +#include "common/spdlog.h" #include "common/variant.h" #include "host/wasi/environ.h" #include "host/wasi/inode.h" @@ -73,14 +73,11 @@ constexpr int openFlags(__wasi_oflags_t OpenFlags, __wasi_fdflags_t FdFlags, if (OpenFlags & __WASI_OFLAGS_EXCL) { Flags |= O_EXCL; } - if (OpenFlags & __WASI_OFLAGS_TRUNC) { + if ((OpenFlags & __WASI_OFLAGS_TRUNC) && (VFSFlags & VFS::Write)) { Flags |= O_TRUNC; } // Convert file descriptor flags. - if ((FdFlags & __WASI_FDFLAGS_APPEND) != 0) { - Flags |= O_APPEND; - } if ((FdFlags & (__WASI_FDFLAGS_DSYNC | __WASI_FDFLAGS_RSYNC | __WASI_FDFLAGS_SYNC)) != 0) { Flags |= O_SYNC; @@ -142,7 +139,7 @@ WasiExpect<INode> INode::open(std::string Path, __wasi_oflags_t OpenFlags, if (auto NewFd = ::open(Path.c_str(), Flags, 0644); unlikely(NewFd < 0)) { return WasiUnexpect(fromErrNo(errno)); } else { - return INode(NewFd); + return INode(NewFd, true, FdFlags & __WASI_FDFLAGS_APPEND); } } @@ -207,7 +204,7 @@ WasiExpect<void> INode::fdFdstatGet(__wasi_fdstat_t &FdStat) const noexcept { FdStat.fs_filetype = unsafeFiletype(); FdStat.fs_flags = static_cast<__wasi_fdflags_t>(0); - if (FdFlags & O_APPEND) { + if (Append) { FdStat.fs_flags |= __WASI_FDFLAGS_APPEND; } if (FdFlags & O_DSYNC) { @@ -230,9 +227,6 @@ INode::fdFdstatSetFlags(__wasi_fdflags_t FdFlags) const noexcept { if (FdFlags & __WASI_FDFLAGS_NONBLOCK) { SysFlag |= O_NONBLOCK; } - if (FdFlags & __WASI_FDFLAGS_APPEND) { - SysFlag |= O_APPEND; - } if (FdFlags & __WASI_FDFLAGS_DSYNC) { SysFlag |= O_DSYNC; } @@ -247,6 +241,7 @@ INode::fdFdstatSetFlags(__wasi_fdflags_t FdFlags) const noexcept { return WasiUnexpect(fromErrNo(errno)); } + Append = FdFlags & __WASI_FDFLAGS_APPEND; return {}; } @@ -546,6 +541,10 @@ WasiExpect<void> INode::fdWrite(Span<Span<const uint8_t>> IOVs, ++SysIOVsSize; } + if (Append) { + ::lseek(Fd, 0, SEEK_END); + } + if (auto Res = ::writev(Fd, SysIOVs, SysIOVsSize); unlikely(Res < 0)) { return WasiUnexpect(fromErrNo(errno)); } else { @@ -697,7 +696,7 @@ WasiExpect<INode> INode::pathOpen(std::string Path, __wasi_oflags_t OpenFlags, unlikely(NewFd < 0)) { return WasiUnexpect(fromErrNo(errno)); } else { - return INode(NewFd); + return INode(NewFd, true, FdFlags & __WASI_FDFLAGS_APPEND); } } diff --git a/lib/host/wasi/inode-win.cpp b/lib/host/wasi/inode-win.cpp index a13c63a86a60..ea6531c21828 100644 --- a/lib/host/wasi/inode-win.cpp +++ b/lib/host/wasi/inode-win.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #if WASMEDGE_OS_WINDOWS @@ -25,6 +25,9 @@ namespace WASI { namespace { +inline void WASMEDGE_WINAPI_WINAPI_CC +EmptyOverlappedCompletionRoutine(DWORD_, DWORD_, LPOVERLAPPED_) noexcept {} + #if WINAPI_PARTITION_DESKTOP inline constexpr uint64_t combineHighLow(uint32_t HighPart, uint32_t LowPart) noexcept { @@ -74,17 +77,19 @@ WasiExpect<std::tuple<DWORD_, DWORD_, DWORD_>> inline constexpr getOpenFlags( VFS::Flags VFSFlags) noexcept { // Always use FILE_FLAG_BACKUP_SEMANTICS to prevent failure on opening a // directory. - DWORD_ AttributeFlags = FILE_FLAG_BACKUP_SEMANTICS_; + DWORD_ AttributeFlags = + FILE_FLAG_BACKUP_SEMANTICS_ | FILE_FLAG_OPEN_REPARSE_POINT_; // Source: https://devblogs.microsoft.com/oldnewthing/20210729-00/?p=105494 - if (FdFlags & (__WASI_FDFLAGS_SYNC | __WASI_FDFLAGS_RSYNC)) { - // Linux does not implement O_RSYNC and glibc defines O_RSYNC as O_SYNC - AttributeFlags |= FILE_FLAG_WRITE_THROUGH_ | FILE_FLAG_NO_BUFFERING_; - FdFlags &= ~(__WASI_FDFLAGS_SYNC | __WASI_FDFLAGS_RSYNC); - } - if (FdFlags & __WASI_FDFLAGS_DSYNC) { + if (FdFlags & + (__WASI_FDFLAGS_SYNC | __WASI_FDFLAGS_RSYNC | __WASI_FDFLAGS_DSYNC)) { AttributeFlags |= FILE_FLAG_WRITE_THROUGH_; - FdFlags &= ~__WASI_FDFLAGS_DSYNC; + FdFlags &= + ~(__WASI_FDFLAGS_SYNC | __WASI_FDFLAGS_RSYNC | __WASI_FDFLAGS_DSYNC); + } + if (FdFlags & __WASI_FDFLAGS_NONBLOCK) { + // Ignore NONBLOCK flag + FdFlags &= ~__WASI_FDFLAGS_NONBLOCK; } if (OpenFlags & __WASI_OFLAGS_DIRECTORY) { AttributeFlags |= FILE_ATTRIBUTE_DIRECTORY_; @@ -98,21 +103,16 @@ WasiExpect<std::tuple<DWORD_, DWORD_, DWORD_>> inline constexpr getOpenFlags( AccessFlags |= FILE_APPEND_DATA_; FdFlags &= ~__WASI_FDFLAGS_APPEND; } - if (VFSFlags & VFS::Read) { + if ((VFSFlags & VFS::Read) || (VFSFlags == 0)) { AccessFlags |= FILE_GENERIC_READ_; - VFSFlags &= ~VFS::Read; } if (VFSFlags & VFS::Write) { AccessFlags |= FILE_GENERIC_WRITE_; - VFSFlags &= ~VFS::Write; } if (FdFlags) { return WasiUnexpect(__WASI_ERRNO_INVAL); } - if (VFSFlags) { - return WasiUnexpect(__WASI_ERRNO_INVAL); - } if (OpenFlags & ~(__WASI_OFLAGS_CREAT | __WASI_OFLAGS_EXCL | __WASI_OFLAGS_TRUNC)) { return WasiUnexpect(__WASI_ERRNO_INVAL); @@ -136,7 +136,11 @@ WasiExpect<std::tuple<DWORD_, DWORD_, DWORD_>> inline constexpr getOpenFlags( break; case __WASI_OFLAGS_TRUNC: case __WASI_OFLAGS_EXCL | __WASI_OFLAGS_TRUNC: - CreationDisposition = TRUNCATE_EXISTING_; + if (VFSFlags & VFS::Write) { + CreationDisposition = TRUNCATE_EXISTING_; + } else { + CreationDisposition = OPEN_EXISTING_; + } break; default: assumingUnreachable(); @@ -160,12 +164,12 @@ inline DWORD_ fastGetFileType(HandleHolder::HandleType Type, } inline __wasi_filetype_t getDiskFileType(DWORD_ Attribute) noexcept { - if (Attribute & FILE_ATTRIBUTE_DIRECTORY_) { - return __WASI_FILETYPE_DIRECTORY; - } if (Attribute & FILE_ATTRIBUTE_REPARSE_POINT_) { return __WASI_FILETYPE_SYMBOLIC_LINK; } + if (Attribute & FILE_ATTRIBUTE_DIRECTORY_) { + return __WASI_FILETYPE_DIRECTORY; + } return __WASI_FILETYPE_REGULAR_FILE; } @@ -450,9 +454,10 @@ HandleHolder::filestatGet(__wasi_filestat_t &FileStat) const noexcept { } else { Filename = Res->filename().native(); Holder = HandleHolder(Res->parent_path(), FILE_GENERIC_READ_, - FILE_SHARE_READ_, OPEN_EXISTING_, + FILE_SHARE_VALID_FLAGS_, OPEN_EXISTING_, FILE_ATTRIBUTE_DIRECTORY_ | - FILE_FLAG_BACKUP_SEMANTICS_); + FILE_FLAG_BACKUP_SEMANTICS_ | + FILE_FLAG_OPEN_REPARSE_POINT_); Finder.emplace(Holder.Handle); } break; @@ -643,8 +648,10 @@ WasiExpect<void> FindHolder::doRewind(bool First) noexcept { WasiExpect<void> FindHolder::doLoadDirent() noexcept { const std::filesystem::path Filename(FindData.cFileName); - HandleHolder File(getPath() / Filename, FILE_GENERIC_READ_, FILE_SHARE_READ_, - OPEN_EXISTING_, FILE_FLAG_BACKUP_SEMANTICS_); + HandleHolder File(getPath() / Filename, FILE_GENERIC_READ_, + FILE_SHARE_VALID_FLAGS_, OPEN_EXISTING_, + FILE_FLAG_BACKUP_SEMANTICS_ | + FILE_FLAG_OPEN_REPARSE_POINT_); if (unlikely(!File.ok())) { return WasiUnexpect(detail::fromLastError(GetLastError())); @@ -695,8 +702,7 @@ WasiExpect<INode> INode::open(std::string Path, __wasi_oflags_t OpenFlags, std::tie(AttributeFlags, AccessFlags, CreationDisposition) = *Res; } - const DWORD_ ShareFlags = - FILE_SHARE_READ_ | FILE_SHARE_WRITE_ | FILE_SHARE_DELETE_; + const DWORD_ ShareFlags = FILE_SHARE_VALID_FLAGS_; const auto FullPath = std::filesystem::u8path(Path); INode Result(FullPath, AccessFlags, ShareFlags, CreationDisposition, @@ -956,7 +962,7 @@ WasiExpect<void> INode::fdPread(Span<Span<uint8_t>> IOVs, Query.OffsetHigh = LocalOffset.HighPart; Query.hEvent = nullptr; if (!ReadFileEx(Handle, IOV.data(), static_cast<uint32_t>(IOV.size()), - &Query, nullptr)) { + &Query, &EmptyOverlappedCompletionRoutine)) { if (unlikely(GetLastError() != ERROR_IO_PENDING_)) { Result = WasiUnexpect(detail::fromLastError(GetLastError())); Queries.resize(I); @@ -972,12 +978,15 @@ WasiExpect<void> INode::fdPread(Span<Span<uint8_t>> IOVs, DWORD_ NumberOfBytesRead = 0; if (unlikely( !GetOverlappedResult(Handle, &Query, &NumberOfBytesRead, true))) { - Result = WasiUnexpect(detail::fromLastError(GetLastError())); - CancelIo(Handle); - for (size_t J = I + 1; J < Queries.size(); ++J) { - GetOverlappedResult(Handle, &Queries[J], nullptr, true); + if (const auto Error = GetLastError(); + unlikely(Error != ERROR_HANDLE_EOF_)) { + Result = WasiUnexpect(detail::fromLastError(Error)); + CancelIo(Handle); + for (size_t J = I + 1; J < Queries.size(); ++J) { + GetOverlappedResult(Handle, &Queries[J], &NumberOfBytesRead, true); + } + break; } - break; } NRead += NumberOfBytesRead; } @@ -988,7 +997,6 @@ WasiExpect<void> INode::fdPread(Span<Span<uint8_t>> IOVs, WasiExpect<void> INode::fdPwrite(Span<Span<const uint8_t>> IOVs, __wasi_filesize_t Offset, __wasi_size_t &NWritten) const noexcept { - const bool Append = SavedFdFlags & __WASI_FDFLAGS_APPEND; WasiExpect<void> Result; std::vector<OVERLAPPED_> Queries(IOVs.size()); ULARGE_INTEGER_ LocalOffset = _ULARGE_INTEGER(Offset); @@ -996,16 +1004,11 @@ WasiExpect<void> INode::fdPwrite(Span<Span<const uint8_t>> IOVs, for (size_t I = 0; I < IOVs.size(); ++I) { auto &IOV = IOVs[I]; auto &Query = Queries[I]; - if (!Append) { - Query.Offset = LocalOffset.LowPart; - Query.OffsetHigh = LocalOffset.HighPart; - } else { - Query.Offset = 0xFFFFFFFF; - Query.OffsetHigh = 0xFFFFFFFF; - } + Query.Offset = LocalOffset.LowPart; + Query.OffsetHigh = LocalOffset.HighPart; Query.hEvent = nullptr; if (!WriteFileEx(Handle, IOV.data(), static_cast<uint32_t>(IOV.size()), - &Query, nullptr)) { + &Query, &EmptyOverlappedCompletionRoutine)) { if (const auto Error = GetLastError(); unlikely(Error != ERROR_IO_PENDING_ && Error != ERROR_HANDLE_EOF_)) { Result = WasiUnexpect(detail::fromLastError(Error)); @@ -1013,25 +1016,26 @@ WasiExpect<void> INode::fdPwrite(Span<Span<const uint8_t>> IOVs, break; } } - if (!Append) { - LocalOffset.QuadPart += IOV.size(); - } + LocalOffset.QuadPart += IOV.size(); } NWritten = 0; for (size_t I = 0; I < Queries.size(); ++I) { auto &Query = Queries[I]; - DWORD_ NumberOfBytesRead = 0; + DWORD_ NumberOfBytesWrite = 0; if (unlikely( - !GetOverlappedResult(Handle, &Query, &NumberOfBytesRead, true))) { - Result = WasiUnexpect(detail::fromLastError(GetLastError())); - CancelIo(Handle); - for (size_t J = I + 1; J < Queries.size(); ++J) { - GetOverlappedResult(Handle, &Queries[J], nullptr, true); + !GetOverlappedResult(Handle, &Query, &NumberOfBytesWrite, true))) { + if (const auto Error = GetLastError(); + unlikely(Error != ERROR_HANDLE_EOF_)) { + Result = WasiUnexpect(detail::fromLastError(Error)); + CancelIo(Handle); + for (size_t J = I + 1; J < Queries.size(); ++J) { + GetOverlappedResult(Handle, &Queries[J], &NumberOfBytesWrite, true); + } + break; } - break; } - NWritten += NumberOfBytesRead; + NWritten += NumberOfBytesWrite; } return Result; @@ -1055,7 +1059,7 @@ WasiExpect<void> INode::fdRead(Span<Span<uint8_t>> IOVs, Query.OffsetHigh = static_cast<DWORD_>(LocalOffset.HighPart); Query.hEvent = nullptr; if (!ReadFileEx(Handle, IOV.data(), static_cast<uint32_t>(IOV.size()), - &Query, nullptr)) { + &Query, &EmptyOverlappedCompletionRoutine)) { if (unlikely(GetLastError() != ERROR_IO_PENDING_)) { Result = WasiUnexpect(detail::fromLastError(GetLastError())); Queries.resize(I); @@ -1071,12 +1075,15 @@ WasiExpect<void> INode::fdRead(Span<Span<uint8_t>> IOVs, DWORD_ NumberOfBytesRead = 0; if (unlikely( !GetOverlappedResult(Handle, &Query, &NumberOfBytesRead, true))) { - Result = WasiUnexpect(detail::fromLastError(GetLastError())); - CancelIo(Handle); - for (size_t J = I + 1; J < Queries.size(); ++J) { - GetOverlappedResult(Handle, &Queries[J], nullptr, true); + if (const auto Error = GetLastError(); + unlikely(Error != ERROR_HANDLE_EOF_)) { + Result = WasiUnexpect(detail::fromLastError(Error)); + CancelIo(Handle); + for (size_t J = I + 1; J < Queries.size(); ++J) { + GetOverlappedResult(Handle, &Queries[J], &NumberOfBytesRead, true); + } + break; } - break; } NRead += NumberOfBytesRead; } @@ -1187,7 +1194,7 @@ WasiExpect<void> INode::fdWrite(Span<Span<const uint8_t>> IOVs, } Query.hEvent = nullptr; if (!WriteFileEx(Handle, IOV.data(), static_cast<uint32_t>(IOV.size()), - &Query, nullptr)) { + &Query, &EmptyOverlappedCompletionRoutine)) { if (const auto Error = GetLastError(); unlikely(Error != ERROR_IO_PENDING_ && Error != ERROR_HANDLE_EOF_)) { Result = WasiUnexpect(detail::fromLastError(Error)); @@ -1203,17 +1210,20 @@ WasiExpect<void> INode::fdWrite(Span<Span<const uint8_t>> IOVs, NWritten = 0; for (size_t I = 0; I < Queries.size(); ++I) { auto &Query = Queries[I]; - DWORD_ NumberOfBytesRead = 0; + DWORD_ NumberOfBytesWrite = 0; if (unlikely( - !GetOverlappedResult(Handle, &Query, &NumberOfBytesRead, true))) { - Result = WasiUnexpect(detail::fromLastError(GetLastError())); - CancelIo(Handle); - for (size_t J = I + 1; J < Queries.size(); ++J) { - GetOverlappedResult(Handle, &Queries[J], nullptr, true); + !GetOverlappedResult(Handle, &Query, &NumberOfBytesWrite, true))) { + if (const auto Error = GetLastError(); + unlikely(Error != ERROR_HANDLE_EOF_)) { + Result = WasiUnexpect(detail::fromLastError(Error)); + CancelIo(Handle); + for (size_t J = I + 1; J < Queries.size(); ++J) { + GetOverlappedResult(Handle, &Queries[J], &NumberOfBytesWrite, true); + } + break; } - break; } - NWritten += NumberOfBytesRead; + NWritten += NumberOfBytesWrite; } if (!Append) { @@ -1252,8 +1262,9 @@ INode::pathFilestatGet(std::string Path, FullPath = std::move(*Res); } - HandleHolder File(FullPath, FILE_GENERIC_READ_, FILE_SHARE_READ_, - OPEN_EXISTING_, FILE_FLAG_BACKUP_SEMANTICS_); + HandleHolder File( + FullPath, FILE_GENERIC_READ_, FILE_SHARE_VALID_FLAGS_, OPEN_EXISTING_, + FILE_FLAG_BACKUP_SEMANTICS_ | FILE_FLAG_OPEN_REPARSE_POINT_); if (unlikely(!File.ok())) { return WasiUnexpect(detail::fromLastError(GetLastError())); @@ -1273,8 +1284,10 @@ INode::pathFilestatSetTimes(std::string Path, __wasi_timestamp_t ATim, FullPath = std::move(*Res); } - HandleHolder File(FullPath, FILE_GENERIC_READ_, FILE_SHARE_READ_, - OPEN_EXISTING_, FILE_FLAG_BACKUP_SEMANTICS_); + HandleHolder File(FullPath, FILE_GENERIC_READ_ | FILE_GENERIC_WRITE_, + FILE_SHARE_VALID_FLAGS_, OPEN_EXISTING_, + FILE_FLAG_BACKUP_SEMANTICS_ | + FILE_FLAG_OPEN_REPARSE_POINT_); if (unlikely(!File.ok())) { return WasiUnexpect(detail::fromLastError(GetLastError())); @@ -1356,8 +1369,7 @@ WasiExpect<INode> INode::pathOpen(std::string Path, __wasi_oflags_t OpenFlags, std::tie(AttributeFlags, AccessFlags, CreationDisposition) = *Res; } - const DWORD_ ShareFlags = - FILE_SHARE_READ_ | FILE_SHARE_WRITE_ | FILE_SHARE_DELETE_; + const DWORD_ ShareFlags = FILE_SHARE_VALID_FLAGS_; std::filesystem::path FullPath; if (auto Res = getRelativePath(Handle, Path); unlikely(!Res)) { @@ -1372,6 +1384,13 @@ WasiExpect<INode> INode::pathOpen(std::string Path, __wasi_oflags_t OpenFlags, if (unlikely(!Result.ok())) { return WasiUnexpect(detail::fromLastError(GetLastError())); } + if (unlikely(Result.isSymlink())) { + return WasiUnexpect(__WASI_ERRNO_LOOP); + } + const bool NeedDir = OpenFlags & __WASI_OFLAGS_DIRECTORY; + if (NeedDir && unlikely(!Result.isDirectory())) { + return WasiUnexpect(__WASI_ERRNO_NOTDIR); + } Result.SavedFdFlags = FdFlags; Result.SavedVFSFlags = VFSFlags; @@ -1388,20 +1407,53 @@ WasiExpect<void> INode::pathReadlink(std::string Path, Span<char> Buffer, } // Fill the Buffer with the contents of the link - HandleHolder Link(FullPath, FILE_GENERIC_READ_, FILE_SHARE_READ_, - OPEN_EXISTING_, FILE_FLAG_OPEN_REPARSE_POINT_); + HandleHolder Link(FullPath, 0, FILE_SHARE_VALID_FLAGS_, OPEN_EXISTING_, + FILE_FLAG_BACKUP_SEMANTICS_ | + FILE_FLAG_OPEN_REPARSE_POINT_); if (unlikely(!Link.ok())) { return WasiUnexpect(detail::fromLastError(GetLastError())); } - if (auto Res = getHandlePath(Link.Handle); unlikely(!Res)) { - return WasiUnexpect(Res); - } else { - const auto U8Data = Res->u8string(); - NRead = static_cast<uint32_t>(std::min(Buffer.size(), U8Data.size())); - std::copy_n(U8Data.begin(), NRead, Buffer.begin()); + constexpr const size_t MaximumReparseDataBufferSize = 16384; + std::array<std::byte, MaximumReparseDataBufferSize> DataBuffer; + DWORD_ BytesReturned; + if (!DeviceIoControl( + Link.Handle, FSCTL_GET_REPARSE_POINT_, nullptr, 0, DataBuffer.data(), + static_cast<DWORD_>(DataBuffer.size()), &BytesReturned, nullptr)) { + return WasiUnexpect(detail::fromLastError(GetLastError())); + } + auto &Reparse = + *reinterpret_cast<const REPARSE_DATA_BUFFER_ *>(DataBuffer.data()); + std::wstring_view Data; + switch (Reparse.ReparseTag) { + case IO_REPARSE_TAG_SYMLINK_: + Data = {&Reparse.SymbolicLinkReparseBuffer.PathBuffer + [Reparse.SymbolicLinkReparseBuffer.SubstituteNameOffset / + sizeof(WCHAR_)], + Reparse.SymbolicLinkReparseBuffer.SubstituteNameLength / + sizeof(WCHAR_)}; + using namespace std::literals; + if (!(Reparse.SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE_) && + Data.size() >= 4 && Data.substr(0, 4) == L"\\??\\"sv) { + Data = Data.substr(3); + } + break; + case IO_REPARSE_TAG_MOUNT_POINT_: + Data = { + &Reparse.MountPointReparseBuffer + .PathBuffer[Reparse.MountPointReparseBuffer.SubstituteNameOffset / + sizeof(WCHAR_)], + Reparse.MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR_)}; + break; + default: + return WasiUnexpect(__WASI_ERRNO_NOSYS); } + + const auto U8Data = std::filesystem::path{Data}.u8string(); + NRead = static_cast<uint32_t>(std::min(Buffer.size(), U8Data.size())); + std::copy_n(U8Data.begin(), NRead, Buffer.begin()); + return {}; } @@ -1435,9 +1487,45 @@ WasiExpect<void> INode::pathRename(const INode &Old, std::string OldPath, NewFullPath = std::move(*Res); } + const auto OldAttr = GetFileAttributesW(OldFullPath.c_str()); + const auto NewAttr = GetFileAttributesW(NewFullPath.c_str()); + if (OldAttr != INVALID_FILE_ATTRIBUTES_ && + NewAttr != INVALID_FILE_ATTRIBUTES_) { + // If source is a directory and destination is a file, fail with NOTDIR + if ((OldAttr & FILE_ATTRIBUTE_DIRECTORY_) && + !(NewAttr & FILE_ATTRIBUTE_DIRECTORY_)) { + return WasiUnexpect(__WASI_ERRNO_NOTDIR); + } + // If source is a file and destination is a directory, fail with ISDIR + if (!(OldAttr & FILE_ATTRIBUTE_DIRECTORY_) && + (NewAttr & FILE_ATTRIBUTE_DIRECTORY_)) { + return WasiUnexpect(__WASI_ERRNO_ISDIR); + } + } + // Rename the file from the paths - if (unlikely(!MoveFileExW(OldFullPath.c_str(), NewFullPath.c_str(), - MOVEFILE_REPLACE_EXISTING_))) { + if (unlikely( + !MoveFileExW(OldFullPath.c_str(), NewFullPath.c_str(), + MOVEFILE_COPY_ALLOWED_ | MOVEFILE_REPLACE_EXISTING_))) { +#if NTDDI_VERSION >= NTDDI_VISTA + if (const auto Error = GetLastError(); Error != ERROR_ACCESS_DENIED_) { + return WasiUnexpect(detail::fromLastError(Error)); + } + // If NewFullPath is an empty directory, remove it and rename. + HandleHolder Transaction{ + CreateTransaction(nullptr, nullptr, 0, 0, 0, 0, nullptr), false}; + if (Transaction.ok()) { + if (RemoveDirectoryTransactedW(NewFullPath.c_str(), Transaction.Handle)) { + if (MoveFileTransactedW(OldFullPath.c_str(), NewFullPath.c_str(), + nullptr, nullptr, MOVEFILE_REPLACE_EXISTING_, + Transaction.Handle)) { + if (CommitTransaction(Transaction.Handle)) { + return {}; + } + } + } + } +#endif return WasiUnexpect(detail::fromLastError(GetLastError())); } @@ -1456,6 +1544,16 @@ WasiExpect<void> INode::pathSymlink(std::string OldPath, } else { NewFullPath = std::move(*Res); } + if (GetFileAttributesW(NewFullPath.c_str()) == INVALID_FILE_ATTRIBUTES_) { + assuming(!NewPath.empty()); + if (NewPath.back() == '/') { + // Dangling link destination shouldn't end with a slash + return WasiUnexpect(__WASI_ERRNO_NOENT); + } + } else { + return WasiUnexpect(__WASI_ERRNO_EXIST); + } + const std::filesystem::path OldU8Path = std::filesystem::u8path(OldPath); DWORD_ TargetType = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE_; @@ -2256,6 +2354,31 @@ void Poller::close(const INode &) noexcept {} void Poller::read(const INode &Node, TriggerType Trigger, __wasi_userdata_t UserData) noexcept { + if (Node.Type == HandleHolder::HandleType::StdHandle) { + if (ReadFds.fd_count > 0 || WriteFds.fd_count > 0) { + // Cannot wait on socket and console at the same time + error(UserData, __WASI_ERRNO_NOSYS, __WASI_EVENTTYPE_FD_READ); + return; + } + + assuming(Events.size() < WasiEvents.size()); + auto &Event = Events.emplace_back(); + Event.Valid = false; + Event.userdata = UserData; + Event.type = __WASI_EVENTTYPE_FD_READ; + + try { + auto [Iter, Added] = ConsoleReadEvent.try_emplace(Node.Handle); + Iter->second = &Event; + } catch (std::bad_alloc &) { + Event.Valid = true; + Event.error = __WASI_ERRNO_NOMEM; + return; + } + + return; + } + if (Node.Type != HandleHolder::HandleType::NormalSocket || Trigger != TriggerType::Level) { // Windows does not support polling other then socket, and only with level @@ -2263,6 +2386,11 @@ void Poller::read(const INode &Node, TriggerType Trigger, error(UserData, __WASI_ERRNO_NOSYS, __WASI_EVENTTYPE_FD_READ); return; } + if (!ConsoleReadEvent.empty() || !ConsoleWriteEvent.empty()) { + // Cannot wait on socket and console at the same time + error(UserData, __WASI_ERRNO_NOSYS, __WASI_EVENTTYPE_FD_READ); + return; + } if (ReadFds.fd_count == FD_SETSIZE_) { error(UserData, __WASI_ERRNO_NOMEM, __WASI_EVENTTYPE_FD_READ); return; @@ -2300,6 +2428,30 @@ void Poller::read(const INode &Node, TriggerType Trigger, void Poller::write(const INode &Node, TriggerType Trigger, __wasi_userdata_t UserData) noexcept { + if (Node.Type == HandleHolder::HandleType::StdHandle) { + if (ReadFds.fd_count > 0 || WriteFds.fd_count > 0) { + // Cannot wait on socket and console at the same time + error(UserData, __WASI_ERRNO_NOSYS, __WASI_EVENTTYPE_FD_WRITE); + return; + } + + assuming(Events.size() < WasiEvents.size()); + auto &Event = Events.emplace_back(); + Event.Valid = false; + Event.userdata = UserData; + Event.type = __WASI_EVENTTYPE_FD_WRITE; + + try { + auto [Iter, Added] = ConsoleWriteEvent.try_emplace(Node.Handle); + Iter->second = &Event; + } catch (std::bad_alloc &) { + Event.Valid = true; + Event.error = __WASI_ERRNO_NOMEM; + return; + } + + return; + } if (Node.Type != HandleHolder::HandleType::NormalSocket || Trigger != TriggerType::Level) { // Windows does not support polling other then socket, and only with level @@ -2307,6 +2459,11 @@ void Poller::write(const INode &Node, TriggerType Trigger, error(UserData, __WASI_ERRNO_NOSYS, __WASI_EVENTTYPE_FD_WRITE); return; } + if (!ConsoleReadEvent.empty() || !ConsoleWriteEvent.empty()) { + // Cannot wait on socket and console at the same time + error(UserData, __WASI_ERRNO_NOSYS, __WASI_EVENTTYPE_FD_WRITE); + return; + } if (WriteFds.fd_count == FD_SETSIZE_) { error(UserData, __WASI_ERRNO_NOMEM, __WASI_EVENTTYPE_FD_WRITE); return; @@ -2337,6 +2494,66 @@ void Poller::write(const INode &Node, TriggerType Trigger, } void Poller::wait() noexcept { + if (!ConsoleWriteEvent.empty()) { + assuming(ReadFds.fd_count == 0 && WriteFds.fd_count == 0); + // Console can always write + for (const auto &[NodeHandle, Event] : ConsoleWriteEvent) { + Event->Valid = true; + Event->error = __WASI_ERRNO_SUCCESS; + } + ConsoleWriteEvent.clear(); + ConsoleReadEvent.clear(); + TimeoutEvent = nullptr; + return; + } + if (!ConsoleReadEvent.empty()) { + assuming(ReadFds.fd_count == 0 && WriteFds.fd_count == 0); + DWORD_ Timeout = INFINITE_; + if (TimeoutEvent != nullptr) { + const std::chrono::microseconds MicroSecs = + std::chrono::seconds(MinimumTimeout.tv_sec) + + std::chrono::microseconds(MinimumTimeout.tv_sec); + Timeout = static_cast<DWORD_>(MicroSecs.count()); + } + std::vector<HANDLE_> Handles; + DWORD_ Count = std::min(static_cast<DWORD_>(ConsoleReadEvent.size()), + MAXIMUM_WAIT_OBJECTS_); + Handles.reserve(Count); + for (const auto &[NodeHandle, Event] : ConsoleReadEvent) { + if (likely(Handles.size() < Count)) { + Handles.push_back(NodeHandle); + } + } + const auto Result = + WaitForMultipleObjects(Count, Handles.data(), false, Timeout); + assuming(static_cast<DWORD_>(0) <= Result); + if (likely(Result < Count)) { + ConsoleReadEvent[Handles[Result]]->Valid = true; + ConsoleReadEvent[Handles[Result]]->error = __WASI_ERRNO_SUCCESS; + } else { + switch (Result) { + case WAIT_TIMEOUT_: + if (likely(TimeoutEvent)) { + TimeoutEvent->Valid = true; + TimeoutEvent->error = __WASI_ERRNO_SUCCESS; + } + break; + case WAIT_FAILED_: + default: { + const auto Error = detail::fromLastError(GetLastError()); + for (const auto &[NodeHandle, Event] : ConsoleWriteEvent) { + Event->Valid = true; + Event->error = Error; + } + break; + } + } + } + assuming(ConsoleWriteEvent.empty()); + ConsoleReadEvent.clear(); + TimeoutEvent = nullptr; + return; + } if (const int Count = select(0, &ReadFds, &WriteFds, nullptr, TimeoutEvent != nullptr ? &MinimumTimeout : nullptr); diff --git a/lib/host/wasi/linux.h b/lib/host/wasi/linux.h index 44f8dac17b48..dddb6f527a8e 100644 --- a/lib/host/wasi/linux.h +++ b/lib/host/wasi/linux.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #if !WASMEDGE_OS_LINUX diff --git a/lib/host/wasi/macos.h b/lib/host/wasi/macos.h index 908d4723c800..0107f5a2e4e0 100644 --- a/lib/host/wasi/macos.h +++ b/lib/host/wasi/macos.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #if !WASMEDGE_OS_MACOS diff --git a/lib/host/wasi/macos.mm b/lib/host/wasi/macos.mm index c7933a985b44..b26ec1eaeec6 100644 --- a/lib/host/wasi/macos.mm +++ b/lib/host/wasi/macos.mm @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "macos.h" #import <Foundation/Foundation.h> diff --git a/lib/host/wasi/vinode.cpp b/lib/host/wasi/vinode.cpp index fe3fe70ed477..87a9d7a315e7 100644 --- a/lib/host/wasi/vinode.cpp +++ b/lib/host/wasi/vinode.cpp @@ -1,9 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "host/wasi/vinode.h" #include "common/errcode.h" -#include "common/log.h" +#include "common/spdlog.h" #include "host/wasi/environ.h" #include "host/wasi/vfs.h" #include <algorithm> @@ -106,7 +106,7 @@ WasiExpect<std::shared_ptr<VINode>> VINode::bind(__wasi_rights_t FRB, WasiExpect<void> VINode::pathCreateDirectory(std::shared_ptr<VINode> Fd, std::string_view Path) { std::vector<char> Buffer; - if (auto Res = resolvePath(Fd, Path); unlikely(!Res)) { + if (auto Res = resolvePath(Fd, Path, false); unlikely(!Res)) { return WasiUnexpect(Res); } else if (!Fd->can(__WASI_RIGHTS_PATH_CREATE_DIRECTORY)) { return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE); @@ -472,13 +472,14 @@ VINode::resolvePath(std::shared_ptr<VINode> &Fd, std::string_view &Path, return WasiUnexpect(__WASI_ERRNO_LOOP); } - std::vector<char> NewBuffer(Filestat.size); + std::vector<char> NewBuffer(16384); __wasi_size_t NRead; if (auto Res = Fd->Node.pathReadlink(std::string(Part), NewBuffer, NRead); unlikely(!Res)) { return WasiUnexpect(Res); } else { + NewBuffer.resize(NRead); // Don't drop Buffer now because Path may referencing it. if (!Remain.empty()) { if (NewBuffer.back() != '/') { diff --git a/lib/host/wasi/wasifunc.cpp b/lib/host/wasi/wasifunc.cpp index a534f617ede9..260ea52a39cd 100644 --- a/lib/host/wasi/wasifunc.cpp +++ b/lib/host/wasi/wasifunc.cpp @@ -1,9 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "host/wasi/wasifunc.h" #include "common/filesystem.h" -#include "common/log.h" +#include "common/spdlog.h" #include "executor/executor.h" #include "host/wasi/environ.h" #include "runtime/instance/memory.h" @@ -1297,6 +1297,13 @@ Expect<uint32_t> WasiPathOpen::body( return __WASI_ERRNO_FAULT; } + // Open directory and read/write rights should fail with isdir + if ((WasiOFlags & __WASI_OFLAGS_DIRECTORY) && + (WasiFsRightsBase & __WASI_RIGHTS_FD_READ) && + (WasiFsRightsBase & __WASI_RIGHTS_FD_WRITE)) { + return __WASI_ERRNO_ISDIR; + } + const __wasi_fd_t WasiDirFd = DirFd; if (auto Res = diff --git a/lib/host/wasi/wasimodule.cpp b/lib/host/wasi/wasimodule.cpp index 8765087b0b80..e41b1e7fc595 100644 --- a/lib/host/wasi/wasimodule.cpp +++ b/lib/host/wasi/wasimodule.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "host/wasi/wasimodule.h" #include "host/wasi/wasifunc.h" diff --git a/lib/host/wasi/win.h b/lib/host/wasi/win.h index 1e98edb4ef7e..a8ac8e2d8e74 100644 --- a/lib/host/wasi/win.h +++ b/lib/host/wasi/win.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #if !WASMEDGE_OS_WINDOWS @@ -179,6 +179,7 @@ inline __wasi_errno_t fromLastError(DWORD_ Code) noexcept { switch (Code) { case ERROR_INVALID_PARAMETER_: // MultiByteToWideChar case ERROR_INVALID_HANDLE_: // GetFinalPathNameByHandleW + case ERROR_NEGATIVE_SEEK_: // SetFilePointerEx return __WASI_ERRNO_INVAL; case ERROR_SHARING_VIOLATION_: // CreateFile2 case ERROR_PIPE_BUSY_: // CreateFile2 @@ -189,9 +190,14 @@ inline __wasi_errno_t fromLastError(DWORD_ Code) noexcept { case ERROR_FILE_EXISTS_: // CreateFile2 return __WASI_ERRNO_EXIST; case ERROR_FILE_NOT_FOUND_: // CreateFile2 + case ERROR_INVALID_NAME_: // CreateFile2 return __WASI_ERRNO_NOENT; case ERROR_PRIVILEGE_NOT_HELD_: // CreateSymbolicLinkW return __WASI_ERRNO_PERM; + case ERROR_DIRECTORY_: // RemoveDirectoryW + return __WASI_ERRNO_NOTDIR; + case ERROR_DIR_NOT_EMPTY_: // RemoveDirectoryW + return __WASI_ERRNO_NOTEMPTY; case ERROR_IO_PENDING_: // ReadFileEx case ERROR_HANDLE_EOF_: // ReadFileEx @@ -208,7 +214,10 @@ using FiletimeDuration = std::chrono::duration< std::ratio_multiply<std::ratio<100, 1>, std::chrono::nanoseconds::period>>; /// from 1601-01-01 to 1970-01-01, 134774 days static inline constexpr const FiletimeDuration NTToUnixEpoch = - std::chrono::seconds{134774u * 86400u}; + std::chrono::seconds{134774LL * 86400LL}; + +static_assert(std::chrono::duration_cast<std::chrono::seconds>(NTToUnixEpoch) + .count() == 11644473600LL); static constexpr __wasi_timestamp_t fromFiletime(FILETIME_ FileTime) noexcept { using std::chrono::duration_cast; diff --git a/lib/llvm/CMakeLists.txt b/lib/llvm/CMakeLists.txt new file mode 100644 index 000000000000..d259a0718105 --- /dev/null +++ b/lib/llvm/CMakeLists.txt @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_PATH}") +get_filename_component(LLVM_DIR "${LLVM_DIR}" ABSOLUTE) +list(APPEND CMAKE_MODULE_PATH ${LLVM_DIR}) +include(LLVMConfig) +include(AddLLVM) + +get_filename_component(LLD_DIR "${LLVM_LIBRARY_DIR}/cmake/lld" ABSOLUTE) +find_package(LLD REQUIRED HINTS ${LLD_DIR}) + +if(WASMEDGE_LINK_LLVM_STATIC) + wasmedge_add_library(wasmedgeLLVM + compiler.cpp + codegen.cpp + data.cpp + jit.cpp + ) + + target_link_libraries(wasmedgeLLVM + PUBLIC + wasmedgeCommon + wasmedgeSystem + std::filesystem + ${WASMEDGE_LLVM_LINK_STATIC_COMPONENTS} + ${WASMEDGE_LLVM_LINK_SHARED_COMPONENTS} + ) +else() + if(APPLE) + list(APPEND LLD_LIBS lldMachO) + elseif(WIN32) + list(APPEND LLD_LIBS lldCOFF) + set(EXTRA_COMPONENTS DebugInfoPDB LibDriver WindowsManifest) + else() + list(APPEND LLD_LIBS lldELF) + endif() + + list(APPEND LLD_LIBS lldCommon) + if(LLVM_VERSION_MAJOR LESS_EQUAL 13) + list(APPEND LLD_LIBS lldDriver) + endif() + + # Command line warning D9025 : overriding '/EHs' with '/EHs-' + # prevent LLVM from adding /EHs-c-. + if(WIN32) + set(LLVM_REQUIRES_EH ON) + endif() + + llvm_add_library(wasmedgeLLVM + compiler.cpp + codegen.cpp + data.cpp + jit.cpp + LINK_LIBS + wasmedgeCommon + wasmedgeSystem + ${LLD_LIBS} + std::filesystem + ${CMAKE_THREAD_LIBS_INIT} + LINK_COMPONENTS + core + lto + native + nativecodegen + option + passes + support + orcjit + transformutils + ${EXTRA_COMPONENTS} + ) +endif() + +wasmedge_setup_target(wasmedgeLLVM) + +target_include_directories(wasmedgeLLVM + SYSTEM + PRIVATE + ${LLVM_INCLUDE_DIR} +) + +target_include_directories(wasmedgeLLVM + PUBLIC + ${PROJECT_BINARY_DIR}/include +) + +include(CheckCXXSourceCompiles) +set(CMAKE_REQUIRED_LINK_OPTIONS "-Wl,-lc,--exclude-libs=libc.a") +check_cxx_source_compiles("int main(){}" SUPPORT_EXCLUDE_LIBS) + +if(SUPPORT_EXCLUDE_LIBS) + file(GLOB LLD_ALL_LIBS ${LLVM_LIBRARY_DIR}/liblld*.a) + list(TRANSFORM LLD_ALL_LIBS REPLACE "^.*/" "") + string(JOIN : LLD_ALL_LIBS_COLON ${LLD_ALL_LIBS}) + if(NOT LLD_ALL_LIBS_COLON STREQUAL "") + target_link_options(wasmedgeLLVM + PUBLIC + "SHELL:-Wl,--exclude-libs=${LLD_ALL_LIBS_COLON}" + ) + endif() +endif() diff --git a/lib/llvm/codegen.cpp b/lib/llvm/codegen.cpp new file mode 100644 index 000000000000..594a855e35f8 --- /dev/null +++ b/lib/llvm/codegen.cpp @@ -0,0 +1,639 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 Second State INC + +#include "llvm/codegen.h" + +#include "aot/version.h" +#include "common/defines.h" +#include "data.h" +#include "llvm.h" + +#include <charconv> +#include <fstream> +#include <lld/Common/Driver.h> +#include <random> +#include <sstream> + +#if LLVM_VERSION_MAJOR >= 14 +#include <lld/Common/CommonLinkerContext.h> +#endif +#if LLVM_VERSION_MAJOR >= 17 +#if WASMEDGE_OS_MACOS +LLD_HAS_DRIVER(macho) +#elif WASMEDGE_OS_LINUX +LLD_HAS_DRIVER(elf) +#elif WASMEDGE_OS_WINDOWS +LLD_HAS_DRIVER(coff) +#endif +#endif + +#if WASMEDGE_OS_MACOS +#include <sys/utsname.h> +#include <unistd.h> +#endif +#if WASMEDGE_OS_WINDOWS +#include <llvm/Object/COFF.h> +#endif + +#if WASMEDGE_OS_LINUX +#define SYMBOL(X) X +#elif WASMEDGE_OS_MACOS +#define SYMBOL(X) "_" X +#elif WASMEDGE_OS_WINDOWS +#define SYMBOL(X) X +#endif + +namespace LLVM = WasmEdge::LLVM; +using namespace std::literals; + +namespace { + +using namespace WasmEdge; + +#if WASMEDGE_OS_MACOS +// Get current OS version +std::string getOSVersion() noexcept { + struct utsname Info; + if (::uname(&Info)) { + // default os version + return "13.0.0"s; + } + std::string_view Release = Info.release; + auto GetNum = [](std::string_view &String) noexcept { + uint64_t Result = 0; + while (!String.empty() && std::isdigit(String[0])) { + Result = Result * 10 + (String[0] - '0'); + String = String.substr(1); + } + return Result; + }; + auto SkipDot = [](std::string_view &String) noexcept { + if (!String.empty() && String[0] == '.') + String = String.substr(1); + }; + uint64_t Major = GetNum(Release); + SkipDot(Release); + uint64_t Minor = GetNum(Release); + SkipDot(Release); + uint64_t Micro = GetNum(Release); + + if (Major == 0) { + Major = 8; + } + if (Major <= 19) { + Micro = 0; + Minor = Major - 4; + Major = 10; + } else { + Micro = 0; + Minor = 0; + Major = 11 + Major - 20; + } + + return fmt::format("{}.{}.{}"sv, Major, Minor, Micro); +} +// Get current SDK version +std::string getSDKVersion() noexcept { + // TODO: parse SDKSettings.json to get real version + return "12.1"s; +} +// Get current SDK version in pair +std::pair<uint32_t, uint32_t> getSDKVersionPair() noexcept { + // TODO: parse SDKSettings.json to get real version + return {UINT32_C(12), UINT32_C(1)}; +} +#endif + +Expect<void> WriteByte(std::ostream &OS, uint8_t Data) noexcept { + OS.put(static_cast<char>(Data)); + return {}; +} + +Expect<void> WriteU32(std::ostream &OS, uint32_t Data) noexcept { + do { + uint8_t Byte = static_cast<uint8_t>(Data & UINT32_C(0x7f)); + Data >>= 7; + if (Data > UINT32_C(0)) { + Byte |= UINT8_C(0x80); + } + WriteByte(OS, Byte); + } while (Data > UINT32_C(0)); + return {}; +} + +Expect<void> WriteU64(std::ostream &OS, uint64_t Data) noexcept { + do { + uint8_t Byte = static_cast<uint8_t>(Data & UINT64_C(0x7f)); + Data >>= 7; + if (Data > UINT64_C(0)) { + Byte |= UINT8_C(0x80); + } + WriteByte(OS, Byte); + } while (Data > UINT64_C(0)); + return {}; +} + +Expect<void> WriteName(std::ostream &OS, std::string_view Data) noexcept { + WriteU32(OS, static_cast<uint32_t>(Data.size())); + for (const auto C : Data) { + WriteByte(OS, static_cast<uint8_t>(C)); + } + return {}; +} + +inline constexpr bool startsWith(std::string_view Value, + std::string_view Prefix) noexcept { + return Value.size() >= Prefix.size() && + Value.substr(0, Prefix.size()) == Prefix; +} + +std::filesystem::path uniquePath(const std::filesystem::path Model) noexcept { + using size_type = std::filesystem::path::string_type::size_type; + using value_type = std::filesystem::path::value_type; + static const auto Hex = "0123456789abcdef"sv; + std::random_device Device; + std::default_random_engine Engine(Device()); + std::uniform_int_distribution<size_type> Distribution(0, Hex.size() - 1); + auto String = Model.native(); + for (size_type N = String.size(), I = 0; I < N; ++I) { + if (String[I] == static_cast<value_type>('%')) { + String[I] = static_cast<value_type>(Hex[Distribution(Engine)]); + } + } + return String; +} + +std::filesystem::path createTemp(const std::filesystem::path Model) noexcept { + while (true) { + auto Result = uniquePath(Model); + std::error_code Error; + if (!std::filesystem::exists(Result, Error)) { + if (Error) { + return {}; + } + return Result; + } + } +} + +// Write output object and link +Expect<void> outputNativeLibrary(const std::filesystem::path &OutputPath, + const LLVM::MemoryBuffer &OSVec) noexcept { + spdlog::info("output start"); + std::filesystem::path ObjectName; + { + // tempfile + std::filesystem::path OPath(OutputPath); +#if WASMEDGE_OS_WINDOWS + OPath.replace_extension("%%%%%%%%%%.obj"sv); +#else + OPath.replace_extension("%%%%%%%%%%.o"sv); +#endif + ObjectName = createTemp(OPath); + if (ObjectName.empty()) { + // TODO:return error + spdlog::error("so file creation failed:{}", OPath.u8string()); + return Unexpect(ErrCode::Value::IllegalPath); + } + std::ofstream OS(ObjectName, std::ios_base::binary); + OS.write(OSVec.data(), static_cast<std::streamsize>(OSVec.size())); + OS.close(); + } + + // link + bool LinkResult = false; +#if WASMEDGE_OS_MACOS + const auto OSVersion = getOSVersion(); + const auto SDKVersion = getSDKVersion(); +#if LLVM_VERSION_MAJOR >= 14 + // LLVM 14 replaces the older mach_o lld implementation with the new one. + // So we need to change the namespace after LLVM 14.x released. + // Reference: https://reviews.llvm.org/D114842 + LinkResult = lld::macho::link( +#else + LinkResult = lld::mach_o::link( +#endif + std::initializer_list<const char *> { + "lld", "-arch", +#if defined(__x86_64__) + "x86_64", +#elif defined(__aarch64__) + "arm64", +#else +#error Unsupported architecture on the MacOS! +#endif +#if LLVM_VERSION_MAJOR >= 14 + // LLVM 14 replaces the older mach_o lld implementation with the new + // one. And it require -arch and -platform_version to always be + // specified. Reference: https://reviews.llvm.org/D97799 + "-platform_version", "macos", OSVersion.c_str(), SDKVersion.c_str(), +#else + "-sdk_version", SDKVersion.c_str(), +#endif + "-dylib", "-demangle", "-macosx_version_min", OSVersion.c_str(), + "-syslibroot", + "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk", + ObjectName.u8string().c_str(), "-o", OutputPath.u8string().c_str() + }, +#elif WASMEDGE_OS_LINUX + LinkResult = lld::elf::link( + std::initializer_list<const char *>{"ld.lld", "--eh-frame-hdr", + "--shared", "--gc-sections", + "--discard-all", ObjectName.c_str(), + "-o", OutputPath.u8string().c_str()}, +#elif WASMEDGE_OS_WINDOWS + LinkResult = lld::coff::link( + std::initializer_list<const char *>{ + "lld-link", "-dll", "-base:0", "-nologo", + ObjectName.u8string().c_str(), + ("-out:" + OutputPath.u8string()).c_str()}, +#endif + +#if LLVM_VERSION_MAJOR >= 14 + llvm::outs(), llvm::errs(), false, false +#elif LLVM_VERSION_MAJOR >= 10 + false, llvm::outs(), llvm::errs() +#else + false, llvm::errs() +#endif + ); + +#if LLVM_VERSION_MAJOR >= 14 + lld::CommonLinkerContext::destroy(); +#endif + + if (LinkResult) { + std::error_code Error; + std::filesystem::remove(ObjectName, Error); +#if WASMEDGE_OS_WINDOWS + std::filesystem::path LibPath(OutputPath); + LibPath.replace_extension(".lib"sv); + std::filesystem::remove(LibPath, Error); +#endif + + spdlog::info("codegen done"); + } else { + spdlog::error("link error"); + } + +#if WASMEDGE_OS_MACOS + // codesign + if (LinkResult) { + pid_t PID = ::fork(); + if (PID == -1) { + spdlog::error("codesign error on fork:{}", std::strerror(errno)); + } else if (PID == 0) { + execlp("/usr/bin/codesign", "codesign", "-s", "-", + OutputPath.u8string().c_str(), nullptr); + std::exit(256); + } else { + int ChildStat; + waitpid(PID, &ChildStat, 0); + if (const int Status = WEXITSTATUS(ChildStat); Status != 0) { + spdlog::error("codesign exited with status {}", Status); + } + } + } +#endif + + return {}; +} + +Expect<void> outputWasmLibrary(LLVM::Context LLContext, + const std::filesystem::path &OutputPath, + Span<const Byte> Data, + const LLVM::MemoryBuffer &OSVec) noexcept { + std::filesystem::path SharedObjectName; + { + // tempfile + std::filesystem::path SOPath(OutputPath); + SOPath.replace_extension("%%%%%%%%%%" WASMEDGE_LIB_EXTENSION); + SharedObjectName = createTemp(SOPath); + if (SharedObjectName.empty()) { + // TODO:return error + spdlog::error("so file creation failed:{}", SOPath.u8string()); + return Unexpect(ErrCode::Value::IllegalPath); + } + std::ofstream OS(SharedObjectName, std::ios_base::binary); + OS.write(OSVec.data(), static_cast<std::streamsize>(OSVec.size())); + OS.close(); + } + + if (auto Res = outputNativeLibrary(SharedObjectName, OSVec); unlikely(!Res)) { + return Unexpect(Res); + } + + LLVM::MemoryBuffer SOFile; + if (auto [Res, ErrorMessage] = + LLVM::MemoryBuffer::getFile(SharedObjectName.u8string().c_str()); + unlikely(ErrorMessage)) { + spdlog::error("object file open error:{}", ErrorMessage.string_view()); + return Unexpect(ErrCode::Value::IllegalPath); + } else { + SOFile = std::move(Res); + } + + LLVM::Binary ObjFile; + if (auto [Res, ErrorMessage] = LLVM::Binary::create(SOFile, LLContext); + unlikely(ErrorMessage)) { + spdlog::error("object file parse error:{}", ErrorMessage.string_view()); + return Unexpect(ErrCode::Value::IllegalPath); + } else { + ObjFile = std::move(Res); + } + + std::string OSCustomSecVec; + { + std::ostringstream OS; + WriteName(OS, "wasmedge"sv); + WriteU32(OS, AOT::kBinaryVersion); + +#if WASMEDGE_OS_LINUX + WriteByte(OS, UINT8_C(1)); +#elif WASMEDGE_OS_MACOS + WriteByte(OS, UINT8_C(2)); +#elif WASMEDGE_OS_WINDOWS + WriteByte(OS, UINT8_C(3)); +#else +#error Unsupported operating system! +#endif + +#if defined(__x86_64__) + WriteByte(OS, UINT8_C(1)); +#elif defined(__aarch64__) + WriteByte(OS, UINT8_C(2)); +#elif defined(__riscv) && __riscv_xlen == 64 + WriteByte(OS, UINT8_C(3)); +#elif defined(__arm__) && __ARM_ARCH == 7 + WriteByte(OS, UINT8_C(4)); +#else +#error Unsupported hardware architecture! +#endif + + std::vector<std::pair<std::string, uint64_t>> SymbolTable; +#if !WASMEDGE_OS_WINDOWS + for (auto Symbol = ObjFile.symbols(); + Symbol && !ObjFile.isSymbolEnd(Symbol); Symbol.next()) { + SymbolTable.emplace_back(Symbol.getName(), Symbol.getAddress()); + } +#else + for (auto &Symbol : + llvm::object::unwrap<llvm::object::COFFObjectFile>(ObjFile.unwrap()) + ->export_directories()) { + llvm::StringRef Name; + if (auto Error = Symbol.getSymbolName(Name); unlikely(!!Error)) { + continue; + } else if (Name.empty()) { + continue; + } + uint32_t Offset = 0; + if (auto Error = Symbol.getExportRVA(Offset); unlikely(!!Error)) { + continue; + } + SymbolTable.emplace_back(Name.str(), Offset); + } +#endif + uint64_t VersionAddress = 0, IntrinsicsAddress = 0; + std::vector<uint64_t> Types; + std::vector<uint64_t> Codes; + uint64_t CodesMin = std::numeric_limits<uint64_t>::max(); + for (const auto &[Name, Address] : SymbolTable) { + if (Name == SYMBOL("version"sv)) { + VersionAddress = Address; + } else if (Name == SYMBOL("intrinsics"sv)) { + IntrinsicsAddress = Address; + } else if (startsWith(Name, SYMBOL("t"sv))) { + uint64_t Index = 0; + std::from_chars(Name.data() + SYMBOL("t"sv).size(), + Name.data() + Name.size(), Index); + if (Types.size() < Index + 1) { + Types.resize(Index + 1); + } + Types[Index] = Address; + } else if (startsWith(Name, SYMBOL("f"sv))) { + uint64_t Index = 0; + std::from_chars(Name.data() + SYMBOL("f"sv).size(), + Name.data() + Name.size(), Index); + if (Codes.size() < Index + 1) { + Codes.resize(Index + 1); + } + CodesMin = std::min(CodesMin, Index); + Codes[Index] = Address; + } + } + if (CodesMin != std::numeric_limits<uint64_t>::max()) { + Codes.erase(Codes.begin(), + Codes.begin() + static_cast<int64_t>(CodesMin)); + } + WriteU64(OS, VersionAddress); + WriteU64(OS, IntrinsicsAddress); + WriteU64(OS, Types.size()); + for (const uint64_t TypeAddress : Types) { + WriteU64(OS, TypeAddress); + } + WriteU64(OS, Codes.size()); + for (const uint64_t CodeAddress : Codes) { + WriteU64(OS, CodeAddress); + } + + uint32_t SectionCount = 0; + for (auto Section = ObjFile.sections(); !ObjFile.isSectionEnd(Section); + Section.next()) { + if (Section.getSize() == 0) { + continue; + } + if (!Section.isEHFrame() && !Section.isPData() && !Section.isText() && + !Section.isData() && !Section.isBSS()) { + continue; + } + ++SectionCount; + } + WriteU32(OS, SectionCount); + + for (auto Section = ObjFile.sections(); !ObjFile.isSectionEnd(Section); + Section.next()) { + if (Section.getSize() == 0) { + continue; + } + std::vector<char> Content; + if (auto Res = Section.getContents(); unlikely(Res.empty())) { + assumingUnreachable(); + } else { + Content.assign(Res.begin(), Res.end()); + } + if (Section.isEHFrame() || Section.isPData()) { + WriteByte(OS, UINT8_C(4)); + } else if (Section.isText()) { + WriteByte(OS, UINT8_C(1)); + } else if (Section.isData()) { + WriteByte(OS, UINT8_C(2)); + } else if (Section.isBSS()) { + WriteByte(OS, UINT8_C(3)); + } else { + continue; + } + + WriteU64(OS, Section.getAddress()); + WriteU64(OS, Content.size()); + WriteName(OS, std::string_view(Content.data(), Content.size())); + } + OSCustomSecVec = OS.str(); + } + + spdlog::info("output start"); + + std::filesystem::path OutputPathTmp(OutputPath); + OutputPathTmp.replace_extension("%%%%%%%%%%.wasm"); + OutputPathTmp = createTemp(OutputPathTmp); + if (OutputPathTmp.empty()) { + return WasmEdge::Unexpect(WasmEdge::ErrCode::Value::IllegalPath); + } + std::ofstream OS(OutputPathTmp, std::ios_base::binary); + if (!OS) { + spdlog::error("output failed."); + return Unexpect(ErrCode::Value::IllegalPath); + } + OS.write(reinterpret_cast<const char *>(Data.data()), + static_cast<std::streamsize>(Data.size())); + // Custom section id + WriteByte(OS, UINT8_C(0x00)); + WriteName(OS, std::string_view(OSCustomSecVec.data(), OSCustomSecVec.size())); + + std::error_code Error; + std::filesystem::remove(SharedObjectName, Error); + std::filesystem::rename(OutputPathTmp, OutputPath); + + spdlog::info("output done"); + return {}; +} + +} // namespace + +namespace WasmEdge::LLVM { + +Expect<void> CodeGen::codegen(Span<const Byte> WasmData, Data D, + std::filesystem::path OutputPath) noexcept { + auto LLContext = D.extract().LLContext(); + auto &LLModule = D.extract().LLModule; + auto &TM = D.extract().TM; + std::filesystem::path LLPath(OutputPath); + LLPath.replace_extension("ll"sv); + +#if WASMEDGE_OS_WINDOWS + { + // create dummy dllmain function + auto FTy = LLVM::Type::getFunctionType(LLContext.getInt32Ty(), {}); + auto F = + LLModule.addFunction(FTy, LLVMExternalLinkage, "_DllMainCRTStartup"); + F.setVisibility(LLVMProtectedVisibility); + F.setDSOLocal(true); + F.addFnAttr( + LLVM::Attribute::createString(LLContext, "no-stack-arg-probe"sv, {})); + F.addFnAttr( + LLVM::Attribute::createEnum(LLContext, LLVM::Core::StrictFP, 0)); + F.addFnAttr(LLVM::Attribute::createEnum(LLContext, LLVM::Core::UWTable, + LLVM::Core::UWTableDefault)); + F.addFnAttr( + LLVM::Attribute::createEnum(LLContext, LLVM::Core::NoReturn, 0)); + LLVM::Builder Builder(LLContext); + Builder.positionAtEnd(LLVM::BasicBlock::create(LLContext, F, "entry")); + Builder.createRet(LLContext.getInt32(1u)); + + auto A = LLModule.addAlias(F.getType(), F, "_fltused"); + A.setLinkage(LLVMExternalLinkage); + A.setVisibility(LLVMProtectedVisibility); + A.setDSOLocal(true); + } +#endif +#if WASMEDGE_OS_MACOS + { + const auto [Major, Minor] = getSDKVersionPair(); + LLModule.addFlag(LLVMModuleFlagBehaviorError, "SDK Version"sv, + LLVM::Value::getConstVector32(LLContext, {Major, Minor})); + } +#endif + + if (Conf.getCompilerConfigure().getOutputFormat() != + CompilerConfigure::OutputFormat::Wasm) { + // create wasm.code and wasm.size + auto Int32Ty = LLContext.getInt32Ty(); + auto Content = LLVM::Value::getConstString( + LLContext, + {reinterpret_cast<const char *>(WasmData.data()), WasmData.size()}, + true); + LLModule.addGlobal(Content.getType(), true, LLVMExternalLinkage, Content, + "wasm.code"); + LLModule.addGlobal(Int32Ty, true, LLVMExternalLinkage, + LLVM::Value::getConstInt(Int32Ty, WasmData.size()), + "wasm.size"); + for (auto Fn = LLModule.getFirstFunction(); Fn; Fn = Fn.getNextFunction()) { + if (Fn.getLinkage() == LLVMInternalLinkage) { + Fn.setLinkage(LLVMExternalLinkage); + Fn.setVisibility(LLVMProtectedVisibility); + Fn.setDSOLocal(true); + Fn.setDLLStorageClass(LLVMDLLExportStorageClass); + } + } + } else { + for (auto Fn = LLModule.getFirstFunction(); Fn; Fn = Fn.getNextFunction()) { + if (Fn.getLinkage() == LLVMInternalLinkage) { + Fn.setLinkage(LLVMPrivateLinkage); + Fn.setDSOLocal(true); + Fn.setDLLStorageClass(LLVMDefaultStorageClass); + } + } + } + + // set dllexport + for (auto GV = LLModule.getFirstGlobal(); GV; GV = GV.getNextGlobal()) { + if (GV.getLinkage() == LLVMExternalLinkage) { + GV.setVisibility(LLVMProtectedVisibility); + GV.setDSOLocal(true); + GV.setDLLStorageClass(LLVMDLLExportStorageClass); + } + } + + if (Conf.getCompilerConfigure().isDumpIR()) { + if (auto ErrorMessage = LLModule.printModuleToFile("wasm.ll"); + unlikely(ErrorMessage)) { + spdlog::error("wasm.ll open error:{}", ErrorMessage.string_view()); + return WasmEdge::Unexpect(WasmEdge::ErrCode::Value::IllegalPath); + } + } + + spdlog::info("codegen start"); + // codegen + { + if (Conf.getCompilerConfigure().isDumpIR()) { + if (auto ErrorMessage = LLModule.printModuleToFile("wasm-opt.ll")) { + // TODO:return error + spdlog::error("printModuleToFile failed"); + return Unexpect(ErrCode::Value::IllegalPath); + } + } + + auto [OSVec, ErrorMessage] = + TM.emitToMemoryBuffer(LLModule, LLVMObjectFile); + if (ErrorMessage) { + // TODO:return error + spdlog::error("addPassesToEmitFile failed"); + return Unexpect(ErrCode::Value::IllegalPath); + } + + if (Conf.getCompilerConfigure().getOutputFormat() == + CompilerConfigure::OutputFormat::Wasm) { + if (auto Res = outputWasmLibrary(LLContext, OutputPath, WasmData, OSVec); + unlikely(!Res)) { + return Unexpect(Res); + } + } else { + if (auto Res = outputNativeLibrary(OutputPath, OSVec); unlikely(!Res)) { + return Unexpect(Res); + } + } + } + + return {}; +} + +} // namespace WasmEdge::LLVM \ No newline at end of file diff --git a/lib/aot/compiler.cpp b/lib/llvm/compiler.cpp similarity index 88% rename from lib/aot/compiler.cpp rename to lib/llvm/compiler.cpp index 1e2e8a1665ac..afc19a68555f 100644 --- a/lib/aot/compiler.cpp +++ b/lib/llvm/compiler.cpp @@ -1,134 +1,47 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2019-2022 Second State INC -#include "aot/compiler.h" +#include "llvm/compiler.h" #include "aot/version.h" #include "common/defines.h" #include "common/filesystem.h" -#include "common/log.h" +#include "common/spdlog.h" +#include "data.h" #include "llvm.h" #include <algorithm> #include <array> -#include <charconv> #include <cinttypes> #include <cstdint> #include <cstdlib> -#include <fstream> #include <limits> -#include <lld/Common/Driver.h> #include <memory> #include <numeric> -#include <random> -#include <sstream> #include <string> #include <string_view> #include <system_error> -#if LLVM_VERSION_MAJOR >= 14 -#include <lld/Common/CommonLinkerContext.h> -#endif -#if LLVM_VERSION_MAJOR >= 17 -#if WASMEDGE_OS_MACOS -LLD_HAS_DRIVER(macho) -#elif WASMEDGE_OS_LINUX -LLD_HAS_DRIVER(elf) -#elif WASMEDGE_OS_WINDOWS -LLD_HAS_DRIVER(coff) -#endif -#endif - -#if WASMEDGE_OS_MACOS -#include <sys/utsname.h> -#include <unistd.h> -#endif -#if WASMEDGE_OS_WINDOWS -#include <llvm/Object/COFF.h> -#endif - -#if WASMEDGE_OS_LINUX -#define SYMBOL(X) X -#elif WASMEDGE_OS_MACOS -#define SYMBOL(X) "_" X -#elif WASMEDGE_OS_WINDOWS -#define SYMBOL(X) X -#endif - +namespace LLVM = WasmEdge::LLVM; using namespace std::literals; -namespace LLVM = WasmEdge::AOT::LLVM; namespace { -#if WASMEDGE_OS_MACOS -// Get current OS version -std::string getOSVersion() noexcept { - struct utsname Info; - if (::uname(&Info)) { - // default os version - return "13.0.0"; - } - std::string_view Release = Info.release; - auto GetNum = [](std::string_view &String) noexcept { - uint64_t Result = 0; - while (!String.empty() && std::isdigit(String[0])) { - Result = Result * 10 + (String[0] - '0'); - String = String.substr(1); - } - return Result; - }; - auto SkipDot = [](std::string_view &String) noexcept { - if (!String.empty() && String[0] == '.') - String = String.substr(1); - }; - uint64_t Major = GetNum(Release); - SkipDot(Release); - uint64_t Minor = GetNum(Release); - SkipDot(Release); - uint64_t Micro = GetNum(Release); - - if (Major == 0) { - Major = 8; - } - if (Major <= 19) { - Micro = 0; - Minor = Major - 4; - Major = 10; - } else { - Micro = 0; - Minor = 0; - Major = 11 + Major - 20; - } - - return fmt::format("{}.{}.{}"sv, Major, Minor, Micro); -} -// Get current SDK version -std::string getSDKVersion() noexcept { - // TODO: parse SDKSettings.json to get real version - return "12.1"s; -} -// Get current SDK version in pair -std::pair<uint32_t, uint32_t> getSDKVersionPair() noexcept { - // TODO: parse SDKSettings.json to get real version - return {UINT32_C(12), UINT32_C(1)}; -} -#endif - static bool isVoidReturn(WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept; -static LLVM::Type toLLVMType(LLVM::Context &LLContext, +static LLVM::Type toLLVMType(LLVM::Context LLContext, const WasmEdge::ValType &ValType) noexcept; static std::vector<LLVM::Type> -toLLVMArgsType(LLVM::Context &LLContext, LLVM::Type ExecCtxPtrTy, +toLLVMArgsType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy, WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept; static LLVM::Type -toLLVMRetsType(LLVM::Context &LLContext, +toLLVMRetsType(LLVM::Context LLContext, WasmEdge::Span<const WasmEdge::ValType> ValTypes) noexcept; static LLVM::Type -toLLVMType(LLVM::Context &LLContext, LLVM::Type ExecCtxPtrTy, +toLLVMType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy, const WasmEdge::AST::FunctionType &FuncType) noexcept; static LLVM::Value -toLLVMConstantZero(LLVM::Context &LLContext, +toLLVMConstantZero(LLVM::Context LLContext, const WasmEdge::ValType &ValType) noexcept; static std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder, LLVM::Value Struct) noexcept; @@ -153,7 +66,7 @@ toLLVMLevel(WasmEdge::CompilerConfigure::OptimizationLevel Level) noexcept { case OL::O0: return "default<O0>,function(tailcallelim)"; case OL::O1: - return "default<O1>"; + return "default<O1>,function(tailcallelim)"; case OL::O2: return "default<O2>"; case OL::O3: @@ -209,84 +122,10 @@ static inline LLVMCodeGenOptLevel toLLVMCodeGenLevel( assumingUnreachable(); } } - -WasmEdge::Expect<void> WriteByte(std::ostream &OS, uint8_t Data) noexcept { - OS.put(static_cast<char>(Data)); - return {}; -} - -WasmEdge::Expect<void> WriteU32(std::ostream &OS, uint32_t Data) noexcept { - do { - uint8_t Byte = static_cast<uint8_t>(Data & UINT32_C(0x7f)); - Data >>= 7; - if (Data > UINT32_C(0)) { - Byte |= UINT8_C(0x80); - } - WriteByte(OS, Byte); - } while (Data > UINT32_C(0)); - return {}; -} - -WasmEdge::Expect<void> WriteU64(std::ostream &OS, uint64_t Data) noexcept { - do { - uint8_t Byte = static_cast<uint8_t>(Data & UINT64_C(0x7f)); - Data >>= 7; - if (Data > UINT64_C(0)) { - Byte |= UINT8_C(0x80); - } - WriteByte(OS, Byte); - } while (Data > UINT64_C(0)); - return {}; -} - -WasmEdge::Expect<void> WriteName(std::ostream &OS, - std::string_view Data) noexcept { - WriteU32(OS, static_cast<uint32_t>(Data.size())); - for (const auto C : Data) { - WriteByte(OS, static_cast<uint8_t>(C)); - } - return {}; -} - -inline constexpr bool startsWith(std::string_view Value, - std::string_view Prefix) noexcept { - return Value.size() >= Prefix.size() && - Value.substr(0, Prefix.size()) == Prefix; -} - -std::filesystem::path uniquePath(const std::filesystem::path Model) noexcept { - using size_type = std::filesystem::path::string_type::size_type; - using value_type = std::filesystem::path::value_type; - static const auto Hex = "0123456789abcdef"sv; - std::random_device Device; - std::default_random_engine Engine(Device()); - std::uniform_int_distribution<size_type> Distribution(0, Hex.size() - 1); - auto String = Model.native(); - for (size_type N = String.size(), I = 0; I < N; ++I) { - if (String[I] == static_cast<value_type>('%')) { - String[I] = static_cast<value_type>(Hex[Distribution(Engine)]); - } - } - return String; -} - -std::filesystem::path createTemp(const std::filesystem::path Model) noexcept { - while (true) { - auto Result = uniquePath(Model); - std::error_code Error; - if (!std::filesystem::exists(Result, Error)) { - if (Error) { - return {}; - } - return Result; - } - } -} - } // namespace -struct WasmEdge::AOT::Compiler::CompileContext { - LLVM::Context &LLContext; +struct LLVM::Compiler::CompileContext { + LLVM::Context LLContext; LLVM::Module &LLModule; LLVM::Attribute Cold; LLVM::Attribute NoAlias; @@ -294,6 +133,7 @@ struct WasmEdge::AOT::Compiler::CompileContext { LLVM::Attribute NoReturn; LLVM::Attribute ReadOnly; LLVM::Attribute StrictFP; + LLVM::Attribute UWTable; LLVM::Attribute NoStackArgProbe; LLVM::Type VoidTy; LLVM::Type Int8Ty; @@ -319,7 +159,6 @@ struct WasmEdge::AOT::Compiler::CompileContext { LLVM::Type IntrinsicsTableTy; LLVM::Type IntrinsicsTablePtrTy; LLVM::Message SubtargetFeatures; - bool IsCustomSection; #if defined(__x86_64__) #if defined(__XOP__) @@ -363,8 +202,8 @@ struct WasmEdge::AOT::Compiler::CompileContext { std::vector<LLVM::Type> Globals; LLVM::Value IntrinsicsTable; LLVM::FunctionCallee Trap; - CompileContext(LLVM::Context &C, LLVM::Module &M, bool IsGenericBinary, - bool IsCustomSection) noexcept + CompileContext(LLVM::Context C, LLVM::Module &M, + bool IsGenericBinary) noexcept : LLContext(C), LLModule(M), Cold(LLVM::Attribute::createEnum(C, LLVM::Core::Cold, 0)), NoAlias(LLVM::Attribute::createEnum(C, LLVM::Core::NoAlias, 0)), @@ -372,6 +211,8 @@ struct WasmEdge::AOT::Compiler::CompileContext { NoReturn(LLVM::Attribute::createEnum(C, LLVM::Core::NoReturn, 0)), ReadOnly(LLVM::Attribute::createEnum(C, LLVM::Core::ReadOnly, 0)), StrictFP(LLVM::Attribute::createEnum(C, LLVM::Core::StrictFP, 0)), + UWTable(LLVM::Attribute::createEnum(C, LLVM::Core::UWTable, + LLVM::Core::UWTableDefault)), NoStackArgProbe( LLVM::Attribute::createString(C, "no-stack-arg-probe"sv, {})), VoidTy(LLContext.getVoidTy()), Int8Ty(LLContext.getInt8Ty()), @@ -410,24 +251,23 @@ struct WasmEdge::AOT::Compiler::CompileContext { ExecCtxPtrTy(ExecCtxTy.getPointerTo()), IntrinsicsTableTy(LLVM::Type::getArrayType( Int8PtrTy, - static_cast<uint32_t>(AST::Module::Intrinsics::kIntrinsicMax))), + static_cast<uint32_t>(Executable::Intrinsics::kIntrinsicMax))), IntrinsicsTablePtrTy(IntrinsicsTableTy.getPointerTo()), - IsCustomSection(IsCustomSection), IntrinsicsTable(LLModule.addGlobal(IntrinsicsTablePtrTy, true, LLVMExternalLinkage, LLVM::Value(), "intrinsics")) { Trap.Ty = LLVM::Type::getFunctionType(VoidTy, {Int32Ty}); Trap.Fn = LLModule.addFunction(Trap.Ty, LLVMPrivateLinkage, "trap"); - Trap.Fn.setVisibility(LLVMProtectedVisibility); Trap.Fn.setDSOLocal(true); Trap.Fn.addFnAttr(NoStackArgProbe); Trap.Fn.addFnAttr(StrictFP); + Trap.Fn.addFnAttr(UWTable); Trap.Fn.addFnAttr(NoReturn); Trap.Fn.addFnAttr(Cold); Trap.Fn.addFnAttr(NoInline); LLModule.addGlobal(Int32Ty, true, LLVMExternalLinkage, - LLVM::Value::getConstInt(Int32Ty, kBinaryVersion), + LLVM::Value::getConstInt(Int32Ty, AOT::kBinaryVersion), "version"); if (!IsGenericBinary) { @@ -474,7 +314,7 @@ struct WasmEdge::AOT::Compiler::CompileContext { LLVM::BasicBlock::create(LLContext, Trap.Fn, "entry")); auto FnTy = LLVM::Type::getFunctionType(VoidTy, {Int32Ty}); auto CallTrap = Builder.createCall( - getIntrinsic(Builder, AST::Module::Intrinsics::kTrap, FnTy), + getIntrinsic(Builder, Executable::Intrinsics::kTrap, FnTy), {Trap.Fn.getFirstParam()}); CallTrap.addCallSiteAttribute(NoReturn); Builder.createUnreachable(); @@ -523,7 +363,7 @@ struct WasmEdge::AOT::Compiler::CompileContext { return Builder.createExtractValue(ExecCtx, 6); } LLVM::FunctionCallee getIntrinsic(LLVM::Builder &Builder, - AST::Module::Intrinsics Index, + Executable::Intrinsics Index, LLVM::Type Ty) noexcept { const auto Value = static_cast<uint32_t>(Index); auto PtrTy = Ty.getPointerTo(); @@ -561,11 +401,11 @@ namespace { using namespace WasmEdge; -static bool isVoidReturn(Span<const WasmEdge::ValType> ValTypes) noexcept { +static bool isVoidReturn(Span<const ValType> ValTypes) noexcept { return ValTypes.empty(); } -static LLVM::Type toLLVMType(LLVM::Context &LLContext, +static LLVM::Type toLLVMType(LLVM::Context LLContext, const ValType &ValType) noexcept { switch (ValType.getCode()) { case TypeCode::I32: @@ -586,7 +426,7 @@ static LLVM::Type toLLVMType(LLVM::Context &LLContext, } static std::vector<LLVM::Type> -toLLVMTypeVector(LLVM::Context &LLContext, +toLLVMTypeVector(LLVM::Context LLContext, Span<const ValType> ValTypes) noexcept { std::vector<LLVM::Type> Result; Result.reserve(ValTypes.size()); @@ -597,14 +437,14 @@ toLLVMTypeVector(LLVM::Context &LLContext, } static std::vector<LLVM::Type> -toLLVMArgsType(LLVM::Context &LLContext, LLVM::Type ExecCtxPtrTy, +toLLVMArgsType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy, Span<const ValType> ValTypes) noexcept { auto Result = toLLVMTypeVector(LLContext, ValTypes); Result.insert(Result.begin(), ExecCtxPtrTy); return Result; } -static LLVM::Type toLLVMRetsType(LLVM::Context &LLContext, +static LLVM::Type toLLVMRetsType(LLVM::Context LLContext, Span<const ValType> ValTypes) noexcept { if (isVoidReturn(ValTypes)) { return LLContext.getVoidTy(); @@ -620,7 +460,7 @@ static LLVM::Type toLLVMRetsType(LLVM::Context &LLContext, return LLVM::Type::getStructType(Result); } -static LLVM::Type toLLVMType(LLVM::Context &LLContext, LLVM::Type ExecCtxPtrTy, +static LLVM::Type toLLVMType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy, const AST::FunctionType &FuncType) noexcept { auto ArgsTy = toLLVMArgsType(LLContext, ExecCtxPtrTy, FuncType.getParamTypes()); @@ -628,7 +468,7 @@ static LLVM::Type toLLVMType(LLVM::Context &LLContext, LLVM::Type ExecCtxPtrTy, return LLVM::Type::getFunctionType(RetTy, ArgsTy); } -static LLVM::Value toLLVMConstantZero(LLVM::Context &LLContext, +static LLVM::Value toLLVMConstantZero(LLVM::Context LLContext, const ValType &ValType) noexcept { switch (ValType.getCode()) { case TypeCode::I32: @@ -653,13 +493,12 @@ class FunctionCompiler { struct Control; public: - FunctionCompiler(AOT::Compiler::CompileContext &Context, + FunctionCompiler(LLVM::Compiler::CompileContext &Context, LLVM::FunctionCallee F, Span<const ValType> Locals, bool Interruptible, bool InstructionCounting, - bool GasMeasuring, bool OptNone) noexcept + bool GasMeasuring) noexcept : Context(Context), LLContext(Context.LLContext), - Interruptible(Interruptible), OptNone(OptNone), F(F), - Builder(LLContext) { + Interruptible(Interruptible), F(F), Builder(LLContext) { if (F.Fn) { Builder.positionAtEnd(LLVM::BasicBlock::create(LLContext, F.Fn, "entry")); ExecCtx = Builder.createLoad(Context.ExecCtxTy, F.Fn.getFirstParam()); @@ -961,7 +800,34 @@ class FunctionCompiler { break; case OpCode::Ref__null: { std::array<uint8_t, 16> Val = {0}; - std::copy_n(Instr.getValType().getRawData().cbegin(), 8, Val.begin()); + // For null references, the dynamic type down scaling is needed. + ValType VType; + if (Instr.getValType().isAbsHeapType()) { + switch (Instr.getValType().getHeapTypeCode()) { + case TypeCode::NullFuncRef: + case TypeCode::FuncRef: + VType = TypeCode::NullFuncRef; + break; + case TypeCode::NullExternRef: + case TypeCode::ExternRef: + VType = TypeCode::NullExternRef; + break; + case TypeCode::NullRef: + case TypeCode::AnyRef: + case TypeCode::EqRef: + case TypeCode::I31Ref: + case TypeCode::StructRef: + case TypeCode::ArrayRef: + VType = TypeCode::NullRef; + break; + default: + assumingUnreachable(); + } + } else { + // TODO: GC - AOT: support other composite here. + VType = TypeCode::NullFuncRef; + } + std::copy_n(VType.getRawData().cbegin(), 8, Val.begin()); auto Vector = LLVM::Value::getConstVector8(LLContext, Val); stackPush(Builder.createBitCast(Vector, Context.Int64x2Ty)); break; @@ -977,7 +843,7 @@ class FunctionCompiler { break; case OpCode::Ref__func: stackPush(Builder.createCall( - Context.getIntrinsic(Builder, AST::Module::Intrinsics::kRefFunc, + Context.getIntrinsic(Builder, Executable::Intrinsics::kRefFunc, LLVM::Type::getFunctionType(Context.Int64x2Ty, {Context.Int32Ty}, false)), @@ -1032,7 +898,7 @@ class FunctionCompiler { auto Idx = stackPop(); stackPush(Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kTableGet, + Builder, Executable::Intrinsics::kTableGet, LLVM::Type::getFunctionType(Context.Int64x2Ty, {Context.Int32Ty, Context.Int32Ty}, false)), @@ -1044,7 +910,7 @@ class FunctionCompiler { auto Idx = stackPop(); Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kTableSet, + Builder, Executable::Intrinsics::kTableSet, LLVM::Type::getFunctionType( Context.Int64Ty, {Context.Int32Ty, Context.Int32Ty, Context.Int64x2Ty}, @@ -1058,7 +924,7 @@ class FunctionCompiler { auto Dst = stackPop(); Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kTableInit, + Builder, Executable::Intrinsics::kTableInit, LLVM::Type::getFunctionType(Context.VoidTy, {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty, Context.Int32Ty, @@ -1070,7 +936,7 @@ class FunctionCompiler { } case OpCode::Elem__drop: { Builder.createCall( - Context.getIntrinsic(Builder, AST::Module::Intrinsics::kElemDrop, + Context.getIntrinsic(Builder, Executable::Intrinsics::kElemDrop, LLVM::Type::getFunctionType( Context.VoidTy, {Context.Int32Ty}, false)), {LLContext.getInt32(Instr.getTargetIndex())}); @@ -1082,7 +948,7 @@ class FunctionCompiler { auto Dst = stackPop(); Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kTableCopy, + Builder, Executable::Intrinsics::kTableCopy, LLVM::Type::getFunctionType(Context.VoidTy, {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty, Context.Int32Ty, @@ -1097,7 +963,7 @@ class FunctionCompiler { auto Val = stackPop(); stackPush(Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kTableGrow, + Builder, Executable::Intrinsics::kTableGrow, LLVM::Type::getFunctionType( Context.Int32Ty, {Context.Int32Ty, Context.Int64x2Ty, Context.Int32Ty}, @@ -1107,7 +973,7 @@ class FunctionCompiler { } case OpCode::Table__size: { stackPush(Builder.createCall( - Context.getIntrinsic(Builder, AST::Module::Intrinsics::kTableSize, + Context.getIntrinsic(Builder, Executable::Intrinsics::kTableSize, LLVM::Type::getFunctionType(Context.Int32Ty, {Context.Int32Ty}, false)), @@ -1119,7 +985,7 @@ class FunctionCompiler { auto Val = stackPop(); auto Off = stackPop(); Builder.createCall( - Context.getIntrinsic(Builder, AST::Module::Intrinsics::kTableFill, + Context.getIntrinsic(Builder, Executable::Intrinsics::kTableFill, LLVM::Type::getFunctionType( Context.Int32Ty, {Context.Int32Ty, Context.Int32Ty, @@ -1227,7 +1093,7 @@ class FunctionCompiler { break; case OpCode::Memory__size: stackPush(Builder.createCall( - Context.getIntrinsic(Builder, AST::Module::Intrinsics::kMemSize, + Context.getIntrinsic(Builder, Executable::Intrinsics::kMemSize, LLVM::Type::getFunctionType(Context.Int32Ty, {Context.Int32Ty}, false)), @@ -1237,7 +1103,7 @@ class FunctionCompiler { auto Diff = stackPop(); stackPush(Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kMemGrow, + Builder, Executable::Intrinsics::kMemGrow, LLVM::Type::getFunctionType(Context.Int32Ty, {Context.Int32Ty, Context.Int32Ty}, false)), @@ -1250,7 +1116,7 @@ class FunctionCompiler { auto Dst = stackPop(); Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kMemInit, + Builder, Executable::Intrinsics::kMemInit, LLVM::Type::getFunctionType(Context.VoidTy, {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty, Context.Int32Ty, @@ -1262,7 +1128,7 @@ class FunctionCompiler { } case OpCode::Data__drop: { Builder.createCall( - Context.getIntrinsic(Builder, AST::Module::Intrinsics::kDataDrop, + Context.getIntrinsic(Builder, Executable::Intrinsics::kDataDrop, LLVM::Type::getFunctionType( Context.VoidTy, {Context.Int32Ty}, false)), {LLContext.getInt32(Instr.getTargetIndex())}); @@ -1274,7 +1140,7 @@ class FunctionCompiler { auto Dst = stackPop(); Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kMemCopy, + Builder, Executable::Intrinsics::kMemCopy, LLVM::Type::getFunctionType(Context.VoidTy, {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty, Context.Int32Ty, @@ -1290,7 +1156,7 @@ class FunctionCompiler { auto Off = stackPop(); Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kMemFill, + Builder, Executable::Intrinsics::kMemFill, LLVM::Type::getFunctionType(Context.VoidTy, {Context.Int32Ty, Context.Int32Ty, Context.Int8Ty, Context.Int32Ty}, @@ -3443,7 +3309,7 @@ class FunctionCompiler { stackPush(Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kMemoryAtomicNotify, + Builder, Executable::Intrinsics::kMemoryAtomicNotify, LLVM::Type::getFunctionType( Context.Int32Ty, {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty}, false)), @@ -3462,7 +3328,7 @@ class FunctionCompiler { stackPush(Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kMemoryAtomicWait, + Builder, Executable::Intrinsics::kMemoryAtomicWait, LLVM::Type::getFunctionType(Context.Int32Ty, {Context.Int32Ty, Context.Int32Ty, Context.Int64Ty, Context.Int64Ty, @@ -3485,7 +3351,7 @@ class FunctionCompiler { Offset); auto Ptr = Builder.createBitCast(VPtr, TargetType.getPointerTo()); - auto Load = Builder.createLoad(TargetType, Ptr, OptNone); + auto Load = Builder.createLoad(TargetType, Ptr, true); Load.setAlignment(1 << Alignment); Load.setOrdering(LLVMAtomicOrderingSequentiallyConsistent); @@ -3514,7 +3380,7 @@ class FunctionCompiler { Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Offset); auto Ptr = Builder.createBitCast(VPtr, TargetType.getPointerTo()); - auto Store = Builder.createStore(V, Ptr, OptNone); + auto Store = Builder.createStore(V, Ptr, true); Store.setAlignment(1 << Alignment); Store.setOrdering(LLVMAtomicOrderingSequentiallyConsistent); } @@ -3717,7 +3583,7 @@ class FunctionCompiler { { auto FPtr = Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kTableGetFuncSymbol, + Builder, Executable::Intrinsics::kTableGetFuncSymbol, LLVM::Type::getFunctionType( FTy.getPointerTo(), {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty}, false)), @@ -3776,7 +3642,7 @@ class FunctionCompiler { Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kCallIndirect, + Builder, Executable::Intrinsics::kCallIndirect, LLVM::Type::getFunctionType(Context.VoidTy, {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty, Context.Int8PtrTy, @@ -3857,7 +3723,7 @@ class FunctionCompiler { { auto FPtr = Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kTableGetFuncSymbol, + Builder, Executable::Intrinsics::kTableGetFuncSymbol, LLVM::Type::getFunctionType( FTy.getPointerTo(), {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty}, false)), @@ -3910,7 +3776,7 @@ class FunctionCompiler { Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kCallIndirect, + Builder, Executable::Intrinsics::kCallIndirect, LLVM::Type::getFunctionType(Context.VoidTy, {Context.Int32Ty, Context.Int32Ty, Context.Int32Ty, Context.Int8PtrTy, @@ -3972,7 +3838,7 @@ class FunctionCompiler { { auto FPtr = Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kRefGetFuncSymbol, + Builder, Executable::Intrinsics::kRefGetFuncSymbol, LLVM::Type::getFunctionType(FTy.getPointerTo(), {Context.Int64x2Ty}, false)), {Ref}); @@ -4029,7 +3895,7 @@ class FunctionCompiler { Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kCallRef, + Builder, Executable::Intrinsics::kCallRef, LLVM::Type::getFunctionType( Context.VoidTy, {Context.Int64x2Ty, Context.Int8PtrTy, Context.Int8PtrTy}, @@ -4093,7 +3959,7 @@ class FunctionCompiler { { auto FPtr = Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kRefGetFuncSymbol, + Builder, Executable::Intrinsics::kRefGetFuncSymbol, LLVM::Type::getFunctionType(FTy.getPointerTo(), {Context.Int64x2Ty}, false)), {Ref}); @@ -4144,7 +4010,7 @@ class FunctionCompiler { Builder.createCall( Context.getIntrinsic( - Builder, AST::Module::Intrinsics::kCallRef, + Builder, Executable::Intrinsics::kCallRef, LLVM::Type::getFunctionType( Context.VoidTy, {Context.Int64x2Ty, Context.Int8PtrTy, Context.Int8PtrTy}, @@ -4184,7 +4050,7 @@ class FunctionCompiler { auto VPtr = Builder.createInBoundsGEP1( Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Off); auto Ptr = Builder.createBitCast(VPtr, LoadTy.getPointerTo()); - auto LoadInst = Builder.createLoad(LoadTy, Ptr, OptNone); + auto LoadInst = Builder.createLoad(LoadTy, Ptr, true); LoadInst.setAlignment(1 << Alignment); stackPush(LoadInst); } @@ -4255,7 +4121,7 @@ class FunctionCompiler { auto VPtr = Builder.createInBoundsGEP1( Context.Int8Ty, Context.getMemory(Builder, ExecCtx, MemoryIndex), Off); auto Ptr = Builder.createBitCast(VPtr, LoadTy.getPointerTo()); - auto StoreInst = Builder.createStore(V, Ptr, OptNone); + auto StoreInst = Builder.createStore(V, Ptr, true); StoreInst.setAlignment(1 << Alignment); } void compileSplatOp(LLVM::Type VectorTy) noexcept { @@ -5112,8 +4978,8 @@ class FunctionCompiler { return Value; } - AOT::Compiler::CompileContext &Context; - LLVM::Context &LLContext; + LLVM::Compiler::CompileContext &Context; + LLVM::Context LLContext; std::vector<std::pair<LLVM::Type, LLVM::Value>> Local; std::vector<LLVM::Value> Stack; LLVM::Value LocalInstrCount = nullptr; @@ -5121,7 +4987,6 @@ class FunctionCompiler { std::unordered_map<ErrCode::Value, LLVM::BasicBlock> TrapBB; bool IsUnreachable = false; bool Interruptible = false; - bool OptNone = false; struct Control { size_t StackSize; bool Unreachable; @@ -5162,342 +5027,12 @@ std::vector<LLVM::Value> unpackStruct(LLVM::Builder &Builder, return Ret; } -// Write output object and link -Expect<void> outputNativeLibrary(const std::filesystem::path &OutputPath, - const LLVM::MemoryBuffer &OSVec) noexcept { - spdlog::info("output start"); - std::filesystem::path ObjectName; - { - // tempfile - std::filesystem::path OPath(OutputPath); -#if WASMEDGE_OS_WINDOWS - OPath.replace_extension("%%%%%%%%%%.obj"sv); -#else - OPath.replace_extension("%%%%%%%%%%.o"sv); -#endif - ObjectName = createTemp(OPath); - if (ObjectName.empty()) { - // TODO:return error - spdlog::error("so file creation failed:{}", OPath.u8string()); - return WasmEdge::Unexpect(WasmEdge::ErrCode::Value::IllegalPath); - } - std::ofstream OS(ObjectName, std::ios_base::binary); - OS.write(OSVec.data(), static_cast<std::streamsize>(OSVec.size())); - OS.close(); - } - - // link - bool LinkResult = false; -#if WASMEDGE_OS_MACOS - const auto OSVersion = getOSVersion(); - const auto SDKVersion = getSDKVersion(); -#if LLVM_VERSION_MAJOR >= 14 - // LLVM 14 replaces the older mach_o lld implementation with the new one. - // So we need to change the namespace after LLVM 14.x released. - // Reference: https://reviews.llvm.org/D114842 - LinkResult = lld::macho::link( -#else - LinkResult = lld::mach_o::link( -#endif - std::initializer_list<const char *> { - "lld", "-arch", -#if defined(__x86_64__) - "x86_64", -#elif defined(__aarch64__) - "arm64", -#else -#error Unsupported architecture on the MacOS! -#endif -#if LLVM_VERSION_MAJOR >= 14 - // LLVM 14 replaces the older mach_o lld implementation with the new - // one. And it require -arch and -platform_version to always be - // specified. Reference: https://reviews.llvm.org/D97799 - "-platform_version", "macos", OSVersion.c_str(), SDKVersion.c_str(), -#else - "-sdk_version", SDKVersion.c_str(), -#endif - "-dylib", "-demangle", "-macosx_version_min", OSVersion.c_str(), - "-syslibroot", - "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk", - ObjectName.u8string().c_str(), "-o", - OutputPath.u8string().c_str() //, - //"-lSystem" - }, -#elif WASMEDGE_OS_LINUX - LinkResult = lld::elf::link( - std::initializer_list<const char *>{"ld.lld", "--shared", "--gc-sections", - "--discard-all", ObjectName.c_str(), - "-o", OutputPath.u8string().c_str()}, -#elif WASMEDGE_OS_WINDOWS - LinkResult = lld::coff::link( - std::initializer_list<const char *>{ - "lld-link", "-dll", "-base:0", "-nologo", - ObjectName.u8string().c_str(), - ("-out:" + OutputPath.u8string()).c_str()}, -#endif - -#if LLVM_VERSION_MAJOR >= 14 - llvm::outs(), llvm::errs(), false, false -#elif LLVM_VERSION_MAJOR >= 10 - false, llvm::outs(), llvm::errs() -#else - false, llvm::errs() -#endif - ); - -#if LLVM_VERSION_MAJOR >= 14 - lld::CommonLinkerContext::destroy(); -#endif - - if (LinkResult) { - std::error_code Error; - std::filesystem::remove(ObjectName, Error); -#if WASMEDGE_OS_WINDOWS - std::filesystem::path LibPath(OutputPath); - LibPath.replace_extension(".lib"sv); - std::filesystem::remove(LibPath, Error); -#endif - - spdlog::info("compile done"); - } else { - spdlog::error("link error"); - } - -#if WASMEDGE_OS_MACOS - // codesign - if (LinkResult) { - pid_t PID = ::fork(); - if (PID == -1) { - spdlog::error("codesign error on fork:{}", std::strerror(errno)); - } else if (PID == 0) { - execlp("/usr/bin/codesign", "codesign", "-s", "-", - OutputPath.u8string().c_str(), nullptr); - std::exit(256); - } else { - int ChildStat; - waitpid(PID, &ChildStat, 0); - if (const int Status = WEXITSTATUS(ChildStat); Status != 0) { - spdlog::error("codesign exited with status {}", Status); - } - } - } -#endif - - return {}; -} - -Expect<void> outputWasmLibrary(const std::filesystem::path &OutputPath, - Span<const Byte> Data, - const LLVM::MemoryBuffer &OSVec) noexcept { - std::filesystem::path SharedObjectName; - { - // tempfile - std::filesystem::path SOPath(OutputPath); - SOPath.replace_extension("%%%%%%%%%%" WASMEDGE_LIB_EXTENSION); - SharedObjectName = createTemp(SOPath); - if (SharedObjectName.empty()) { - // TODO:return error - spdlog::error("so file creation failed:{}", SOPath.u8string()); - return WasmEdge::Unexpect(WasmEdge::ErrCode::Value::IllegalPath); - } - std::ofstream OS(SharedObjectName, std::ios_base::binary); - OS.write(OSVec.data(), static_cast<std::streamsize>(OSVec.size())); - OS.close(); - } - - if (auto Res = outputNativeLibrary(SharedObjectName, OSVec); unlikely(!Res)) { - return Unexpect(Res); - } - - LLVM::MemoryBuffer SOFile; - if (auto [Res, ErrorMessage] = - LLVM::MemoryBuffer::getFile(SharedObjectName.u8string().c_str()); - unlikely(ErrorMessage)) { - spdlog::error("object file open error:{}", ErrorMessage.string_view()); - return WasmEdge::Unexpect(WasmEdge::ErrCode::Value::IllegalPath); - } else { - SOFile = std::move(Res); - } - - LLVM::Context Context; - LLVM::Binary ObjFile; - if (auto [Res, ErrorMessage] = LLVM::Binary::create(SOFile, Context); - unlikely(ErrorMessage)) { - spdlog::error("object file parse error:{}", ErrorMessage.string_view()); - return WasmEdge::Unexpect(WasmEdge::ErrCode::Value::IllegalPath); - } else { - ObjFile = std::move(Res); - } - - std::string OSCustomSecVec; - { - std::ostringstream OS; - WriteName(OS, "wasmedge"sv); - WriteU32(OS, WasmEdge::AOT::kBinaryVersion); - -#if WASMEDGE_OS_LINUX - WriteByte(OS, UINT8_C(1)); -#elif WASMEDGE_OS_MACOS - WriteByte(OS, UINT8_C(2)); -#elif WASMEDGE_OS_WINDOWS - WriteByte(OS, UINT8_C(3)); -#else -#error Unsupported operating system! -#endif - -#if defined(__x86_64__) - WriteByte(OS, UINT8_C(1)); -#elif defined(__aarch64__) - WriteByte(OS, UINT8_C(2)); -#elif defined(__riscv) && __riscv_xlen == 64 - WriteByte(OS, UINT8_C(3)); -#elif defined(__arm__) && __ARM_ARCH == 7 - WriteByte(OS, UINT8_C(4)); -#else -#error Unsupported hardware architecture! -#endif - - std::vector<std::pair<std::string, uint64_t>> SymbolTable; -#if !WASMEDGE_OS_WINDOWS - for (auto Symbol = ObjFile.symbols(); - Symbol && !ObjFile.isSymbolEnd(Symbol); Symbol.next()) { - SymbolTable.emplace_back(Symbol.getName(), Symbol.getAddress()); - } -#else - for (auto &Symbol : - llvm::object::unwrap<llvm::object::COFFObjectFile>(ObjFile.unwrap()) - ->export_directories()) { - llvm::StringRef Name; - if (auto Error = Symbol.getSymbolName(Name); unlikely(!!Error)) { - continue; - } else if (Name.empty()) { - continue; - } - uint32_t Offset = 0; - if (auto Error = Symbol.getExportRVA(Offset); unlikely(!!Error)) { - continue; - } - SymbolTable.emplace_back(Name.str(), Offset); - } -#endif - uint64_t VersionAddress = 0, IntrinsicsAddress = 0; - std::vector<uint64_t> Types; - std::vector<uint64_t> Codes; - uint64_t CodesMin = std::numeric_limits<uint64_t>::max(); - for (const auto &[Name, Address] : SymbolTable) { - if (Name == SYMBOL("version"sv)) { - VersionAddress = Address; - } else if (Name == SYMBOL("intrinsics"sv)) { - IntrinsicsAddress = Address; - } else if (startsWith(Name, SYMBOL("t"sv))) { - uint64_t Index = 0; - std::from_chars(Name.data() + SYMBOL("t"sv).size(), - Name.data() + Name.size(), Index); - if (Types.size() < Index + 1) { - Types.resize(Index + 1); - } - Types[Index] = Address; - } else if (startsWith(Name, SYMBOL("f"sv))) { - uint64_t Index = 0; - std::from_chars(Name.data() + SYMBOL("f"sv).size(), - Name.data() + Name.size(), Index); - if (Codes.size() < Index + 1) { - Codes.resize(Index + 1); - } - CodesMin = std::min(CodesMin, Index); - Codes[Index] = Address; - } - } - if (CodesMin != std::numeric_limits<uint64_t>::max()) { - Codes.erase(Codes.begin(), - Codes.begin() + static_cast<int64_t>(CodesMin)); - } - WriteU64(OS, VersionAddress); - WriteU64(OS, IntrinsicsAddress); - WriteU64(OS, Types.size()); - for (const uint64_t TypeAddress : Types) { - WriteU64(OS, TypeAddress); - } - WriteU64(OS, Codes.size()); - for (const uint64_t CodeAddress : Codes) { - WriteU64(OS, CodeAddress); - } - - uint32_t SectionCount = 0; - for (auto Section = ObjFile.sections(); !ObjFile.isSectionEnd(Section); - Section.next()) { - if (Section.getSize() == 0) { - continue; - } - if (!Section.isText() && !Section.isData() && !Section.isBSS()) { - continue; - } - ++SectionCount; - } - WriteU32(OS, SectionCount); - - for (auto Section = ObjFile.sections(); !ObjFile.isSectionEnd(Section); - Section.next()) { - if (Section.getSize() == 0) { - continue; - } - std::vector<char> Content; - if (auto Res = Section.getContents(); unlikely(Res.empty())) { - assumingUnreachable(); - } else { - Content.assign(Res.begin(), Res.end()); - } - if (Section.isPData()) { - WriteByte(OS, UINT8_C(4)); - } else if (Section.isText()) { - WriteByte(OS, UINT8_C(1)); - } else if (Section.isData()) { - WriteByte(OS, UINT8_C(2)); - } else if (Section.isBSS()) { - WriteByte(OS, UINT8_C(3)); - } else { - continue; - } - - WriteU64(OS, Section.getAddress()); - WriteU64(OS, Content.size()); - WriteName(OS, std::string_view(Content.data(), Content.size())); - } - OSCustomSecVec = OS.str(); - } - - spdlog::info("output start"); - - std::filesystem::path OutputPathTmp(OutputPath); - OutputPathTmp.replace_extension("%%%%%%%%%%.wasm"); - OutputPathTmp = createTemp(OutputPathTmp); - if (OutputPathTmp.empty()) { - return WasmEdge::Unexpect(WasmEdge::ErrCode::Value::IllegalPath); - } - std::ofstream OS(OutputPathTmp, std::ios_base::binary); - if (!OS) { - spdlog::error("output failed."); - return Unexpect(ErrCode::Value::IllegalPath); - } - OS.write(reinterpret_cast<const char *>(Data.data()), - static_cast<std::streamsize>(Data.size())); - // Custom section id - WriteByte(OS, UINT8_C(0x00)); - WriteName(OS, std::string_view(OSCustomSecVec.data(), OSCustomSecVec.size())); - - std::error_code Error; - std::filesystem::remove(SharedObjectName, Error); - std::filesystem::rename(OutputPathTmp, OutputPath); - return {}; -} - } // namespace namespace WasmEdge { -namespace AOT { +namespace LLVM { -Expect<void> Compiler::compile(Span<const Byte> Data, const AST::Module &Module, - std::filesystem::path OutputPath) noexcept { +Expect<Data> Compiler::compile(const AST::Module &Module) noexcept { // Check the module is validated. if (unlikely(!Module.getIsValidated())) { spdlog::error(ErrCode::Value::NotValidated); @@ -5506,26 +5041,17 @@ Expect<void> Compiler::compile(Span<const Byte> Data, const AST::Module &Module, std::unique_lock Lock(Mutex); spdlog::info("compile start"); - std::filesystem::path LLPath(OutputPath); - LLPath.replace_extension("ll"sv); LLVM::Core::init(); - LLVM::Context LLContext; - LLVM::Module LLModule(LLContext, LLPath.u8string().c_str()); + LLVM::Data D; + auto LLContext = D.extract().LLContext(); + auto &LLModule = D.extract().LLModule; LLModule.setTarget(LLVM::getDefaultTargetTriple().unwrap()); LLModule.addFlag(LLVMModuleFlagBehaviorError, "PIC Level"sv, 2); -#if WASMEDGE_OS_MACOS - { - const auto [Major, Minor] = getSDKVersionPair(); - LLModule.addFlag(LLVMModuleFlagBehaviorError, "SDK Version"sv, - LLVM::Value::getConstVector32(LLContext, {Major, Minor})); - } -#endif + CompileContext NewContext(LLContext, LLModule, - Conf.getCompilerConfigure().isGenericBinary(), - Conf.getCompilerConfigure().getOutputFormat() == - CompilerConfigure::OutputFormat::Wasm); + Conf.getCompilerConfigure().isGenericBinary()); struct RAIICleanup { RAIICleanup(CompileContext *&Context, CompileContext &NewContext) : Context(Context) { @@ -5552,75 +5078,18 @@ Expect<void> Compiler::compile(Span<const Byte> Data, const AST::Module &Module, compile(Module.getExportSection()); // StartSection is not required to compile -#if WASMEDGE_OS_WINDOWS - { - // create dummy dllmain function - auto FTy = LLVM::Type::getFunctionType(Context->LLContext.getInt32Ty(), {}); - auto F = Context->LLModule.addFunction(FTy, LLVMExternalLinkage, - "_DllMainCRTStartup"); - F.setVisibility(LLVMProtectedVisibility); - F.setDSOLocal(true); - F.addFnAttr(Context->NoStackArgProbe); - F.addFnAttr(Context->StrictFP); - F.addFnAttr(Context->NoReturn); - LLVM::Builder Builder(Context->LLContext); - Builder.positionAtEnd( - LLVM::BasicBlock::create(Context->LLContext, F, "entry")); - Builder.createRet(Context->LLContext.getInt32(1u)); - - auto A = LLModule.addAlias(F.getType(), F, "_fltused"); - A.setLinkage(LLVMExternalLinkage); - A.setVisibility(LLVMProtectedVisibility); - A.setDSOLocal(true); - } -#endif - - if (!Context->IsCustomSection) { - // create wasm.code and wasm.size - auto Int32Ty = Context->Int32Ty; - auto Content = LLVM::Value::getConstString( - LLContext, {reinterpret_cast<const char *>(Data.data()), Data.size()}, - true); - LLModule.addGlobal(Content.getType(), true, LLVMExternalLinkage, Content, - "wasm.code"); - LLModule.addGlobal(Int32Ty, true, LLVMExternalLinkage, - LLVM::Value::getConstInt(Int32Ty, Data.size()), - "wasm.size"); - } - - // set dllexport - for (auto GV = LLModule.getFirstGlobal(); GV; GV = GV.getNextGlobal()) { - if (GV.getLinkage() == LLVMExternalLinkage) { - GV.setVisibility(LLVMProtectedVisibility); - GV.setDSOLocal(true); - GV.setDLLStorageClass(LLVMDLLExportStorageClass); - } - } - - if (Conf.getCompilerConfigure().isDumpIR()) { - if (auto ErrorMessage = LLModule.printModuleToFile("wasm.ll"); - unlikely(ErrorMessage)) { - spdlog::error("wasm.ll open error:{}", ErrorMessage.string_view()); - return WasmEdge::Unexpect(WasmEdge::ErrCode::Value::IllegalPath); - } - } - spdlog::info("verify start"); LLModule.verify(LLVMPrintMessageAction); - spdlog::info("optimize start"); - // optimize + codegen - auto Triple = LLModule.getTarget(); + spdlog::info("optimize start"); + auto &TM = D.extract().TM; { - LLVM::TargetMachine TM; - { - auto [TheTarget, ErrorMessage] = LLVM::Target::getFromTriple(Triple); - if (ErrorMessage) { - // TODO:return error - spdlog::error("lookupTarget failed:{}", ErrorMessage.string_view()); - return Unexpect(ErrCode::Value::IllegalPath); - } - + auto Triple = LLModule.getTarget(); + auto [TheTarget, ErrorMessage] = LLVM::Target::getFromTriple(Triple); + if (ErrorMessage) { + spdlog::error("getFromTriple failed:{}", ErrorMessage.string_view()); + return Unexpect(ErrCode::Value::IllegalPath); + } else { std::string CPUName; #if defined(__riscv) && __riscv_xlen == 64 CPUName = "generic-rv64"s; @@ -5634,90 +5103,69 @@ Expect<void> Compiler::compile(Span<const Byte> Data, const AST::Module &Module, TM = LLVM::TargetMachine::create( TheTarget, Triple, CPUName.c_str(), - Context->SubtargetFeatures.unwrap(), + LLVM::getHostCPUFeatures().unwrap(), toLLVMCodeGenLevel( Conf.getCompilerConfigure().getOptimizationLevel()), LLVMRelocPIC, LLVMCodeModelDefault); } #if LLVM_VERSION_MAJOR >= 13 - { - auto PBO = LLVM::PassBuilderOptions::create(); - LLVM::Error Error = PBO.runPasses( - LLModule, - toLLVMLevel(Conf.getCompilerConfigure().getOptimizationLevel()), TM); - if (Error) { - spdlog::error("{}"sv, Error.message().string_view()); - } + auto PBO = LLVM::PassBuilderOptions::create(); + if (auto Error = PBO.runPasses( + LLModule, + toLLVMLevel(Conf.getCompilerConfigure().getOptimizationLevel()), + TM)) { + spdlog::error("{}"sv, Error.message().string_view()); } #else - { - auto FP = LLVM::PassManager::createForModule(LLModule); - auto MP = LLVM::PassManager::create(); + auto FP = LLVM::PassManager::createForModule(LLModule); + auto MP = LLVM::PassManager::create(); - TM.addAnalysisPasses(MP); - TM.addAnalysisPasses(FP); - { - auto PMB = LLVM::PassManagerBuilder::create(); - auto [OptLevel, SizeLevel] = - toLLVMLevel(Conf.getCompilerConfigure().getOptimizationLevel()); - PMB.setOptLevel(OptLevel); - PMB.setSizeLevel(SizeLevel); - PMB.populateFunctionPassManager(FP); - PMB.populateModulePassManager(MP); - } - if (Conf.getCompilerConfigure().getOptimizationLevel() == - CompilerConfigure::OptimizationLevel::O0) { - FP.addTailCallEliminationPass(); - } - - FP.initializeFunctionPassManager(); - for (auto Fn = LLModule.getFirstFunction(); Fn; - Fn = Fn.getNextFunction()) { - FP.runFunctionPassManager(Fn); - } - FP.finalizeFunctionPassManager(); - MP.runPassManager(LLModule); - } -#endif - - // Set initializer for constant value - if (auto IntrinsicsTable = LLModule.getNamedGlobal("intrinsics")) { - IntrinsicsTable.setInitializer( - LLVM::Value::getConstNull(IntrinsicsTable.getType())); - IntrinsicsTable.setGlobalConstant(false); + TM.addAnalysisPasses(MP); + TM.addAnalysisPasses(FP); + { + auto PMB = LLVM::PassManagerBuilder::create(); + auto [OptLevel, SizeLevel] = + toLLVMLevel(Conf.getCompilerConfigure().getOptimizationLevel()); + PMB.setOptLevel(OptLevel); + PMB.setSizeLevel(SizeLevel); + PMB.populateFunctionPassManager(FP); + PMB.populateModulePassManager(MP); } - - if (Conf.getCompilerConfigure().isDumpIR()) { - if (auto ErrorMessage = LLModule.printModuleToFile("wasm-opt.ll")) { - // TODO:return error - spdlog::error("printModuleToFile failed"); - return Unexpect(ErrCode::Value::IllegalPath); - } + switch (Conf.getCompilerConfigure().getOptimizationLevel()) { + case CompilerConfigure::OptimizationLevel::O0: + case CompilerConfigure::OptimizationLevel::O1: + FP.addTailCallEliminationPass(); + break; + default: + break; } - spdlog::info("codegen start"); - auto [OSVec, ErrorMessage] = - TM.emitToMemoryBuffer(LLModule, LLVMObjectFile); - if (ErrorMessage) { - // TODO:return error - spdlog::error("addPassesToEmitFile failed"); - return Unexpect(ErrCode::Value::IllegalPath); + FP.initializeFunctionPassManager(); + for (auto Fn = LLModule.getFirstFunction(); Fn; Fn = Fn.getNextFunction()) { + FP.runFunctionPassManager(Fn); } + FP.finalizeFunctionPassManager(); + MP.runPassManager(LLModule); +#endif + } - if (Context->IsCustomSection) { - if (auto Res = outputWasmLibrary(OutputPath, Data, OSVec); - unlikely(!Res)) { - return Unexpect(Res); - } - } else { - if (auto Res = outputNativeLibrary(OutputPath, OSVec); unlikely(!Res)) { - return Unexpect(Res); - } - } + // Set initializer for constant value + if (auto IntrinsicsTable = LLModule.getNamedGlobal("intrinsics")) { + IntrinsicsTable.setInitializer( + LLVM::Value::getConstNull(IntrinsicsTable.getType())); + IntrinsicsTable.setGlobalConstant(false); + } else { + auto IntrinsicsTableTy = LLVM::Type::getArrayType( + LLContext.getInt8Ty().getPointerTo(), + static_cast<uint32_t>(Executable::Intrinsics::kIntrinsicMax)); + LLModule.addGlobal( + IntrinsicsTableTy.getPointerTo(), false, LLVMExternalLinkage, + LLVM::Value::getConstNull(IntrinsicsTableTy), "intrinsics"); } - return {}; + spdlog::info("optimize done"); + return Expect<Data>{std::move(D)}; } void Compiler::compile(const AST::TypeSection &TypeSec) noexcept { @@ -5726,8 +5174,8 @@ void Compiler::compile(const AST::TypeSection &TypeSec) noexcept { {Context->ExecCtxPtrTy, Context->Int8PtrTy, Context->Int8PtrTy, Context->Int8PtrTy}, false); - const auto &FuncTypes = TypeSec.getContent(); - const auto Size = FuncTypes.size(); + auto SubTypes = TypeSec.getContent(); + const auto Size = SubTypes.size(); if (Size == 0) { return; } @@ -5736,102 +5184,110 @@ void Compiler::compile(const AST::TypeSection &TypeSec) noexcept { // Iterate and compile types. for (size_t I = 0; I < Size; ++I) { - const auto &FuncType = FuncTypes[I]; - const auto Name = fmt::format("t{}"sv, Context->FunctionTypes.size()); + if (SubTypes[I].getCompositeType().isFunc()) { + const auto &FuncType = SubTypes[I].getCompositeType().getFuncType(); + const auto Name = fmt::format("t{}"sv, Context->FunctionTypes.size()); - // Check function type is unique - { - bool Unique = true; - for (size_t J = 0; J < I; ++J) { - const auto &OldFuncType = *Context->FunctionTypes[J]; - if (OldFuncType == FuncType) { - Unique = false; - Context->FunctionTypes.push_back(&OldFuncType); - auto F = Context->FunctionWrappers[J]; - Context->FunctionWrappers.push_back(F); - auto A = Context->LLModule.addAlias(F.getType(), F, Name.c_str()); - A.setLinkage(LLVMExternalLinkage); - A.setVisibility(LLVMProtectedVisibility); - A.setDSOLocal(true); - A.setDLLStorageClass(LLVMDLLExportStorageClass); - break; + // Check function type is unique + { + bool Unique = true; + for (size_t J = 0; J < I; ++J) { + if (const auto OldFuncType = Context->FunctionTypes[J]) { + if (*OldFuncType == FuncType) { + Unique = false; + Context->FunctionTypes.push_back(OldFuncType); + auto F = Context->FunctionWrappers[J]; + Context->FunctionWrappers.push_back(F); + auto A = Context->LLModule.addAlias(WrapperTy, F, Name.c_str()); + A.setLinkage(LLVMExternalLinkage); + A.setVisibility(LLVMProtectedVisibility); + A.setDSOLocal(true); + A.setDLLStorageClass(LLVMDLLExportStorageClass); + break; + } + } + } + if (!Unique) { + continue; } } - if (!Unique) { - continue; - } - } - // Create Wrapper - auto F = Context->LLModule.addFunction(WrapperTy, LLVMExternalLinkage, - Name.c_str()); - { - F.setVisibility(LLVMProtectedVisibility); - F.setDSOLocal(true); - F.setDLLStorageClass(LLVMDLLExportStorageClass); - F.addFnAttr(Context->NoStackArgProbe); - F.addFnAttr(Context->StrictFP); - F.addParamAttr(0, Context->ReadOnly); - F.addParamAttr(0, Context->NoAlias); - F.addParamAttr(1, Context->NoAlias); - F.addParamAttr(2, Context->NoAlias); - F.addParamAttr(3, Context->NoAlias); - - LLVM::Builder Builder(Context->LLContext); - Builder.positionAtEnd( - LLVM::BasicBlock::create(Context->LLContext, F, "entry")); - - auto FTy = - toLLVMType(Context->LLContext, Context->ExecCtxPtrTy, FuncType); - auto RTy = FTy.getReturnType(); - std::vector<LLVM::Type> FPTy(FTy.getNumParams()); - FTy.getParamTypes(FPTy); - - const size_t ArgCount = FPTy.size() - 1; - const size_t RetCount = - RTy.isVoidTy() ? 0 - : (RTy.isStructTy() ? RTy.getStructNumElements() : 1); - auto ExecCtxPtr = F.getFirstParam(); - auto RawFunc = LLVM::FunctionCallee{ - FTy, - Builder.createBitCast(ExecCtxPtr.getNextParam(), FTy.getPointerTo())}; - auto RawArgs = ExecCtxPtr.getNextParam().getNextParam(); - auto RawRets = RawArgs.getNextParam(); - - std::vector<LLVM::Value> Args; - Args.reserve(FTy.getNumParams()); - Args.push_back(ExecCtxPtr); - for (size_t J = 0; J < ArgCount; ++J) { - auto ArgTy = FPTy[J + 1]; - auto VPtr = Builder.createConstInBoundsGEP1_64(Context->Int8Ty, RawArgs, - J * kValSize); - auto Ptr = Builder.createBitCast(VPtr, ArgTy.getPointerTo()); - Args.push_back(Builder.createLoad(ArgTy, Ptr)); - } - - auto Ret = Builder.createCall(RawFunc, Args); - if (RTy.isVoidTy()) { - // nothing to do - } else if (RTy.isStructTy()) { - auto Rets = unpackStruct(Builder, Ret); - for (size_t J = 0; J < RetCount; ++J) { + // Create Wrapper + auto F = Context->LLModule.addFunction(WrapperTy, LLVMExternalLinkage, + Name.c_str()); + { + F.setVisibility(LLVMProtectedVisibility); + F.setDSOLocal(true); + F.setDLLStorageClass(LLVMDLLExportStorageClass); + F.addFnAttr(Context->NoStackArgProbe); + F.addFnAttr(Context->StrictFP); + F.addFnAttr(Context->UWTable); + F.addParamAttr(0, Context->ReadOnly); + F.addParamAttr(0, Context->NoAlias); + F.addParamAttr(1, Context->NoAlias); + F.addParamAttr(2, Context->NoAlias); + F.addParamAttr(3, Context->NoAlias); + + LLVM::Builder Builder(Context->LLContext); + Builder.positionAtEnd( + LLVM::BasicBlock::create(Context->LLContext, F, "entry")); + + auto FTy = + toLLVMType(Context->LLContext, Context->ExecCtxPtrTy, FuncType); + auto RTy = FTy.getReturnType(); + std::vector<LLVM::Type> FPTy(FTy.getNumParams()); + FTy.getParamTypes(FPTy); + + const size_t ArgCount = FPTy.size() - 1; + const size_t RetCount = + RTy.isVoidTy() + ? 0 + : (RTy.isStructTy() ? RTy.getStructNumElements() : 1); + auto ExecCtxPtr = F.getFirstParam(); + auto RawFunc = LLVM::FunctionCallee{ + FTy, Builder.createBitCast(ExecCtxPtr.getNextParam(), + FTy.getPointerTo())}; + auto RawArgs = ExecCtxPtr.getNextParam().getNextParam(); + auto RawRets = RawArgs.getNextParam(); + + std::vector<LLVM::Value> Args; + Args.reserve(FTy.getNumParams()); + Args.push_back(ExecCtxPtr); + for (size_t J = 0; J < ArgCount; ++J) { + auto ArgTy = FPTy[J + 1]; auto VPtr = Builder.createConstInBoundsGEP1_64(Context->Int8Ty, - RawRets, J * kValSize); - auto Ptr = - Builder.createBitCast(VPtr, Rets[J].getType().getPointerTo()); - Builder.createStore(Rets[J], Ptr); + RawArgs, J * kValSize); + auto Ptr = Builder.createBitCast(VPtr, ArgTy.getPointerTo()); + Args.push_back(Builder.createLoad(ArgTy, Ptr)); } - } else { - auto VPtr = - Builder.createConstInBoundsGEP1_64(Context->Int8Ty, RawRets, 0); - auto Ptr = Builder.createBitCast(VPtr, Ret.getType().getPointerTo()); - Builder.createStore(Ret, Ptr); + + auto Ret = Builder.createCall(RawFunc, Args); + if (RTy.isVoidTy()) { + // nothing to do + } else if (RTy.isStructTy()) { + auto Rets = unpackStruct(Builder, Ret); + for (size_t J = 0; J < RetCount; ++J) { + auto VPtr = Builder.createConstInBoundsGEP1_64( + Context->Int8Ty, RawRets, J * kValSize); + auto Ptr = + Builder.createBitCast(VPtr, Rets[J].getType().getPointerTo()); + Builder.createStore(Rets[J], Ptr); + } + } else { + auto VPtr = + Builder.createConstInBoundsGEP1_64(Context->Int8Ty, RawRets, 0); + auto Ptr = Builder.createBitCast(VPtr, Ret.getType().getPointerTo()); + Builder.createStore(Ret, Ptr); + } + Builder.createRetVoid(); } - Builder.createRetVoid(); + // Copy wrapper, param and return lists to module instance. + Context->FunctionTypes.push_back(&FuncType); + Context->FunctionWrappers.push_back(F); + } else { + Context->FunctionTypes.push_back(nullptr); + Context->FunctionWrappers.push_back(LLVM::Value()); } - // Copy wrapper, param and return lists to module instance. - Context->FunctionTypes.push_back(&FuncType); - Context->FunctionWrappers.push_back(F); } } @@ -5853,18 +5309,14 @@ void Compiler::compile(const AST::ImportSection &ImportSec) noexcept { auto FTy = toLLVMType(Context->LLContext, Context->ExecCtxPtrTy, FuncType); auto RTy = FTy.getReturnType(); - const auto Linkage = - Context->IsCustomSection ? LLVMPrivateLinkage : LLVMExternalLinkage; auto F = LLVM::FunctionCallee{ - FTy, Context->LLModule.addFunction( - FTy, Linkage, fmt::format("f{}"sv, FuncID).c_str())}; - F.Fn.setVisibility(LLVMProtectedVisibility); + FTy, + Context->LLModule.addFunction(FTy, LLVMInternalLinkage, + fmt::format("f{}"sv, FuncID).c_str())}; F.Fn.setDSOLocal(true); - if (!Context->IsCustomSection) { - F.Fn.setDLLStorageClass(LLVMDLLExportStorageClass); - } F.Fn.addFnAttr(Context->NoStackArgProbe); F.Fn.addFnAttr(Context->StrictFP); + F.Fn.addFnAttr(Context->UWTable); F.Fn.addParamAttr(0, Context->ReadOnly); F.Fn.addParamAttr(0, Context->NoAlias); @@ -5907,7 +5359,7 @@ void Compiler::compile(const AST::ImportSection &ImportSec) noexcept { Builder.createCall( Context->getIntrinsic( - Builder, AST::Module::Intrinsics::kCall, + Builder, Executable::Intrinsics::kCall, LLVM::Type::getFunctionType( Context->VoidTy, {Context->Int32Ty, Context->Int8PtrTy, Context->Int8PtrTy}, @@ -6001,6 +5453,7 @@ void Compiler::compile(const AST::FunctionSection &FuncSec, F.Fn.setDLLStorageClass(LLVMDLLExportStorageClass); F.Fn.addFnAttr(Context->NoStackArgProbe); F.Fn.addFnAttr(Context->StrictFP); + F.Fn.addFnAttr(Context->UWTable); F.Fn.addParamAttr(0, Context->ReadOnly); F.Fn.addParamAttr(0, Context->NoAlias); @@ -6021,14 +5474,12 @@ void Compiler::compile(const AST::FunctionSection &FuncSec, FunctionCompiler FC(*Context, F, Locals, Conf.getCompilerConfigure().isInterruptible(), Conf.getStatisticsConfigure().isInstructionCounting(), - Conf.getStatisticsConfigure().isCostMeasuring(), - Conf.getCompilerConfigure().getOptimizationLevel() == - CompilerConfigure::OptimizationLevel::O0); + Conf.getStatisticsConfigure().isCostMeasuring()); auto Type = Context->resolveBlockType(T); FC.compile(*Code, std::move(Type)); F.Fn.eliminateUnreachableBlocks(); } } -} // namespace AOT -} // namespace WasmEdge +} // namespace LLVM +} // namespace WasmEdge \ No newline at end of file diff --git a/lib/llvm/data.cpp b/lib/llvm/data.cpp new file mode 100644 index 000000000000..b9f3727953d3 --- /dev/null +++ b/lib/llvm/data.cpp @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "llvm/data.h" +#include "data.h" +#include "llvm.h" + +namespace LLVM = WasmEdge::LLVM; + +LLVM::Data::Data() noexcept : Context(std::make_unique<DataContext>()) {} + +LLVM::Data::~Data() noexcept {} + +LLVM::Data::Data(LLVM::Data &&RHS) noexcept : Context(std::move(RHS.Context)) {} +LLVM::Data &LLVM::Data::operator=(LLVM::Data &&RHS) noexcept { + using std::swap; + swap(Context, RHS.Context); + return *this; +} diff --git a/lib/llvm/data.h b/lib/llvm/data.h new file mode 100644 index 000000000000..9ab1a525e28d --- /dev/null +++ b/lib/llvm/data.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC +#pragma once + +#include "llvm.h" +#include "llvm/data.h" + +struct WasmEdge::LLVM::Data::DataContext { + LLVM::OrcThreadSafeContext TSContext; + LLVM::Module LLModule; + LLVM::TargetMachine TM; + DataContext() noexcept : TSContext(), LLModule(LLContext(), "wasm") {} + LLVM::Context LLContext() noexcept { return TSContext.getContext(); } +}; diff --git a/lib/llvm/jit.cpp b/lib/llvm/jit.cpp new file mode 100644 index 000000000000..5313d236d2c0 --- /dev/null +++ b/lib/llvm/jit.cpp @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "llvm/jit.h" +#include "common/spdlog.h" + +#include "data.h" +#include "llvm.h" + +namespace LLVM = WasmEdge::LLVM; +using namespace std::literals; + +namespace WasmEdge::LLVM { + +JITLibrary::JITLibrary(OrcLLJIT JIT) noexcept + : J(std::make_unique<OrcLLJIT>(std::move(JIT)).release()) {} + +JITLibrary::~JITLibrary() noexcept { + std::unique_ptr<OrcLLJIT> JIT(std::exchange(J, nullptr)); +} + +Symbol<const Executable::IntrinsicsTable *> +JITLibrary::getIntrinsics() noexcept { + if (auto Symbol = J->lookup<const IntrinsicsTable *>("intrinsics")) { + return createSymbol<const IntrinsicsTable *>(*Symbol); + } else { + spdlog::error("{}"sv, Symbol.error().message().string_view()); + return {}; + } +} + +std::vector<Symbol<Executable::Wrapper>> +JITLibrary::getTypes(size_t Size) noexcept { + std::vector<Symbol<Wrapper>> Result; + Result.reserve(Size); + for (size_t I = 0; I < Size; ++I) { + const std::string Name = fmt::format("t{}"sv, I); + if (auto Symbol = J->lookup<Wrapper>(Name.c_str())) { + Result.push_back(createSymbol<Wrapper>(*Symbol)); + } else { + spdlog::error("{}"sv, Symbol.error().message().string_view()); + Result.emplace_back(); + } + } + + return Result; +} + +std::vector<Symbol<void>> JITLibrary::getCodes(size_t Offset, + size_t Size) noexcept { + std::vector<Symbol<void>> Result; + Result.reserve(Size); + for (size_t I = 0; I < Size; ++I) { + const std::string Name = fmt::format("f{}"sv, I + Offset); + if (auto Symbol = J->lookup<void>(Name.c_str())) { + Result.push_back(createSymbol<void>(*Symbol)); + } else { + spdlog::error("{}"sv, Symbol.error().message().string_view()); + Result.emplace_back(); + } + } + + return Result; +} + +Expect<std::shared_ptr<Executable>> JIT::load(Data D) noexcept { + spdlog::info("jit load start"); + + OrcLLJIT J; + if (auto Res = OrcLLJIT::create(); !Res) { + spdlog::error("{}"sv, Res.error().message().string_view()); + return Unexpect(ErrCode::Value::HostFuncError); + } else { + J = std::move(*Res); + } + + auto &LLModule = D.extract().LLModule; + + if (Conf.getCompilerConfigure().isDumpIR()) { + if (auto ErrorMessage = LLModule.printModuleToFile("wasm-jit.ll")) { + spdlog::error("printModuleToFile failed"); + } + } + + auto MainJD = J.getMainJITDylib(); + if (auto Err = J.addLLVMIRModule( + MainJD, + OrcThreadSafeModule(LLModule.release(), D.extract().TSContext))) { + spdlog::error("{}"sv, Err.message().string_view()); + return Unexpect(ErrCode::Value::HostFuncError); + } + + spdlog::info("jit load end"); + + return std::make_shared<JITLibrary>(std::move(J)); +} +} // namespace WasmEdge::LLVM diff --git a/lib/aot/llvm.h b/lib/llvm/llvm.h similarity index 77% rename from lib/aot/llvm.h rename to lib/llvm/llvm.h index d7179f29019c..0999ac23ac63 100644 --- a/lib/aot/llvm.h +++ b/lib/llvm/llvm.h @@ -1,5 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC +#pragma once #include "common/errcode.h" #include "common/span.h" @@ -7,6 +8,7 @@ #include <llvm-c/Core.h> #include <llvm-c/Error.h> #include <llvm-c/Object.h> +#include <llvm-c/Orc.h> #include <llvm-c/Target.h> #include <llvm-c/TargetMachine.h> #include <llvm-c/Types.h> @@ -15,6 +17,40 @@ #include <utility> #include <vector> +#if LLVM_VERSION_MAJOR >= 12 +#include <llvm-c/LLJIT.h> +#endif + +#if LLVM_VERSION_MAJOR < 12 && WASMEDGE_OS_WINDOWS +using LLVMOrcObjectLayerRef = struct LLVMOrcOpaqueObjectLayer *; +using LLVMOrcLLJITBuilderObjectLinkingLayerCreatorFunction = + LLVMOrcObjectLayerRef (*)(void *Ctx, LLVMOrcExecutionSessionRef ES, + const char *Triple) noexcept; +static void LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator( + LLVMOrcLLJITBuilderRef Builder, + LLVMOrcLLJITBuilderObjectLinkingLayerCreatorFunction F, void *Ctx) noexcept; +#endif +#if LLVM_VERSION_MAJOR < 13 +using LLVMOrcMaterializationResponsibilityRef = + struct LLVMOrcOpaqueMaterializationResponsibility *; +using LLVMOrcIRTransformLayerRef = struct LLVMOrcOpaqueIRTransformLayer *; +using LLVMOrcIRTransformLayerTransformFunction = + LLVMErrorRef (*)(void *Ctx, LLVMOrcThreadSafeModuleRef *ModInOut, + LLVMOrcMaterializationResponsibilityRef MR) noexcept; +using LLVMOrcGenericIRModuleOperationFunction = + LLVMErrorRef (*)(void *Ctx, LLVMModuleRef M) noexcept; +static LLVMOrcIRTransformLayerRef +LLVMOrcLLJITGetIRTransformLayer(LLVMOrcLLJITRef J) noexcept; +static void LLVMOrcIRTransformLayerSetTransform( + LLVMOrcIRTransformLayerRef IRTransformLayer, + LLVMOrcIRTransformLayerTransformFunction TransformFunction, + void *Ctx) noexcept; +static LLVMErrorRef +LLVMOrcThreadSafeModuleWithModuleDo(LLVMOrcThreadSafeModuleRef TSM, + LLVMOrcGenericIRModuleOperationFunction F, + void *Ctx) noexcept; +#endif + #if LLVM_VERSION_MAJOR >= 13 #include <llvm-c/Transforms/PassBuilder.h> #else @@ -28,7 +64,7 @@ #define __x86_64__ 1 #endif -namespace WasmEdge::AOT::LLVM { +namespace WasmEdge::LLVM { class Core { public: @@ -92,6 +128,12 @@ class Core { static inline unsigned int NoReturn = 0; static inline unsigned int ReadOnly = 0; static inline unsigned int StrictFP = 0; + static inline unsigned int UWTable = 0; +#if LLVM_VERSION_MAJOR >= 15 + static constexpr inline const unsigned int UWTableDefault = 2; +#else + static constexpr inline const unsigned int UWTableDefault = 0; +#endif static inline unsigned int InvariantGroup = 0; @@ -169,8 +211,9 @@ class Core { NoReturn = getEnumAttributeKind("noreturn"sv); ReadOnly = getEnumAttributeKind("readonly"sv); StrictFP = getEnumAttributeKind("strictfp"sv); + UWTable = getEnumAttributeKind("uwtable"sv); - InvariantGroup = getMetadataKind("invariant.group"); + InvariantGroup = getMetadataKind("invariant.group"sv); } template <typename... ArgsT> @@ -205,16 +248,8 @@ class BasicBlock; class Context { public: constexpr Context(LLVMContextRef R) noexcept : Ref(R) {} - Context(const Context &) = delete; - Context &operator=(const Context &) = delete; - Context(Context &&C) noexcept : Context() { swap(*this, C); } - Context &operator=(Context &&C) noexcept { - swap(*this, C); - return *this; - } - - Context() noexcept : Ref(LLVMContextCreate()) {} - ~Context() noexcept { LLVMContextDispose(Ref); } + Context(const Context &) = default; + Context &operator=(const Context &) = default; constexpr operator bool() const noexcept { return Ref != nullptr; } constexpr auto &unwrap() const noexcept { return Ref; } @@ -260,7 +295,7 @@ class Module { return *this; } - Module(Context &C, const char *Name) noexcept + Module(const Context &C, const char *Name) noexcept : Ref(LLVMModuleCreateWithNameInContext(Name, C.unwrap())) {} ~Module() noexcept { LLVMDisposeModule(Ref); } @@ -281,12 +316,14 @@ class Module { uint32_t Val) noexcept; inline Value getFirstGlobal() noexcept; inline Value getFirstFunction() noexcept; + inline Value getNamedFunction(const char *Name) noexcept; inline Message printModuleToFile(const char *File) noexcept; inline Message verify(LLVMVerifierFailureAction Action) noexcept; constexpr operator bool() const noexcept { return Ref != nullptr; } constexpr auto &unwrap() const noexcept { return Ref; } constexpr auto &unwrap() noexcept { return Ref; } + LLVMModuleRef release() noexcept { return std::exchange(Ref, nullptr); } friend void swap(Module &LHS, Module &RHS) noexcept { using std::swap; swap(LHS.Ref, RHS.Ref); @@ -341,6 +378,7 @@ class Error { constexpr operator bool() const noexcept { return Ref != nullptr; } constexpr auto &unwrap() const noexcept { return Ref; } constexpr auto &unwrap() noexcept { return Ref; } + LLVMErrorRef release() noexcept { return std::exchange(Ref, nullptr); } friend void swap(Error &LHS, Error &RHS) noexcept { using std::swap; swap(LHS.Ref, RHS.Ref); @@ -713,6 +751,11 @@ class Value { LLVM_FOR_EACH_VALUE_SUBCLASS(DECLARE_VALUE_CHECK) #undef DECLARE_VALUE_CHECK + std::string_view getValueName() noexcept { + size_t Size; + const auto Ptr = LLVMGetValueName2(Ref, &Size); + return {Ptr, Size}; + } inline void addFnAttr(const Attribute &A) noexcept; inline void addParamAttr(unsigned Index, const Attribute &A) noexcept; inline void addCallSiteAttribute(const Attribute &A) noexcept; @@ -723,8 +766,10 @@ class Value { Value getNextParam() noexcept { return LLVMGetNextParam(Ref); } Value getNextGlobal() noexcept { return LLVMGetNextGlobal(Ref); } Value getNextFunction() noexcept { return LLVMGetNextFunction(Ref); } + unsigned int countBasicBlocks() noexcept { return LLVMCountBasicBlocks(Ref); } Type getType() const noexcept { return LLVMTypeOf(Ref); } + Value getInitializer() noexcept { return LLVMGetInitializer(Ref); } void setInitializer(Value ConstantVal) noexcept { LLVMSetInitializer(Ref, ConstantVal.unwrap()); } @@ -756,6 +801,11 @@ class Value { void setOrdering(LLVMAtomicOrdering Ordering) noexcept { LLVMSetOrdering(Ref, Ordering); } + std::string_view getName() noexcept { + size_t Length; + auto Data = LLVMGetValueName2(Ref, &Length); + return {Data, Length}; + } inline void addCase(Value OnVal, BasicBlock Dest) noexcept; inline void addDestination(BasicBlock Dest) noexcept; @@ -830,10 +880,10 @@ class Attribute { uint64_t Val) noexcept { return LLVMCreateEnumAttribute(C.unwrap(), KindID, Val); } - static Attribute createString(Context &C, std::string_view KindID, + static Attribute createString(Context &C, std::string_view Kind, std::string_view Val) noexcept { return LLVMCreateStringAttribute( - C.unwrap(), KindID.data(), static_cast<unsigned int>(KindID.size()), + C.unwrap(), Kind.data(), static_cast<unsigned int>(Kind.size()), Val.data(), static_cast<unsigned int>(Val.size())); } @@ -854,7 +904,9 @@ Value Module::addGlobal(Type Ty, bool IsConstant, LLVMLinkage Linkage, Value G = LLVMAddGlobal(Ref, Ty.unwrap(), Name); G.setLinkage(Linkage); G.setGlobalConstant(IsConstant); - G.setInitializer(Initializer); + if (Initializer) { + G.setInitializer(Initializer); + } return G; } @@ -892,6 +944,10 @@ void Module::addFlag(LLVMModuleFlagBehavior Behavior, std::string_view Key, Value Module::getFirstGlobal() noexcept { return LLVMGetFirstGlobal(Ref); } Value Module::getFirstFunction() noexcept { return LLVMGetFirstFunction(Ref); } +Value Module::getNamedFunction(const char *Name) noexcept { + return LLVMGetNamedFunction(Ref, Name); +} + Message Module::printModuleToFile(const char *Filename) noexcept { Message M; LLVMPrintModuleToFile(Ref, Filename, &M.unwrap()); @@ -1535,7 +1591,7 @@ class Builder { Value getConstrainedFPExcept() noexcept { using namespace std::literals; auto Ctx = getCtx(); - auto ExceptStr = "fpexcept.ignore"sv; + auto ExceptStr = "fpexcept.strict"sv; auto ExceptMDS = LLVMMDStringInContext2(Ctx, ExceptStr.data(), ExceptStr.size()); return LLVMMetadataAsValue(Ctx, ExceptMDS); @@ -1797,7 +1853,8 @@ class PassBuilderOptions { LLVMPassBuilderOptionsSetMergeFunctions(Ref, MergeFunctions); } - Error runPasses(Module &M, const char *Passes, TargetMachine &TM) noexcept { + Error runPasses(Module &M, const char *Passes, + const TargetMachine &TM = nullptr) noexcept { return LLVMRunPasses(M.unwrap(), Passes, TM.unwrap(), Ref); } @@ -1844,6 +1901,7 @@ class SectionIterator { inline bool isData() const noexcept; inline bool isBSS() const noexcept; inline bool isPData() const noexcept; + inline bool isEHFrame() const noexcept; private: LLVMSectionIteratorRef Ref = nullptr; @@ -1931,13 +1989,242 @@ class Binary { LLVMBinaryRef Ref = nullptr; }; -} // namespace WasmEdge::AOT::LLVM +class OrcThreadSafeContext { +public: + constexpr OrcThreadSafeContext(LLVMOrcThreadSafeContextRef R) noexcept + : Ref(R) {} + OrcThreadSafeContext(const OrcThreadSafeContext &) = delete; + OrcThreadSafeContext &operator=(const OrcThreadSafeContext &) = delete; + OrcThreadSafeContext(OrcThreadSafeContext &&B) noexcept + : OrcThreadSafeContext() { + swap(*this, B); + } + OrcThreadSafeContext &operator=(OrcThreadSafeContext &&B) noexcept { + swap(*this, B); + return *this; + } + + OrcThreadSafeContext() noexcept : Ref(LLVMOrcCreateNewThreadSafeContext()) {} + ~OrcThreadSafeContext() noexcept { LLVMOrcDisposeThreadSafeContext(Ref); } + + constexpr operator bool() const noexcept { return Ref != nullptr; } + constexpr auto &unwrap() const noexcept { return Ref; } + constexpr auto &unwrap() noexcept { return Ref; } + LLVMOrcThreadSafeContextRef release() noexcept { + return std::exchange(Ref, nullptr); + } + friend void swap(OrcThreadSafeContext &LHS, + OrcThreadSafeContext &RHS) noexcept { + using std::swap; + swap(LHS.Ref, RHS.Ref); + } + + Context getContext() noexcept { + return LLVMOrcThreadSafeContextGetContext(Ref); + } + +private: + LLVMOrcThreadSafeContextRef Ref = nullptr; +}; + +class OrcThreadSafeModule { +public: + constexpr OrcThreadSafeModule() noexcept = default; + constexpr OrcThreadSafeModule(LLVMOrcThreadSafeModuleRef R) noexcept + : Ref(R) {} + OrcThreadSafeModule(const OrcThreadSafeModule &) = delete; + OrcThreadSafeModule &operator=(const OrcThreadSafeModule &) = delete; + OrcThreadSafeModule(OrcThreadSafeModule &&B) noexcept + : OrcThreadSafeModule() { + swap(*this, B); + } + OrcThreadSafeModule &operator=(OrcThreadSafeModule &&B) noexcept { + swap(*this, B); + return *this; + } + + OrcThreadSafeModule(Module &&M, OrcThreadSafeContext &C) noexcept + : Ref(LLVMOrcCreateNewThreadSafeModule(M.release(), C.unwrap())) {} + ~OrcThreadSafeModule() noexcept { LLVMOrcDisposeThreadSafeModule(Ref); } + + constexpr operator bool() const noexcept { return Ref != nullptr; } + constexpr auto &unwrap() const noexcept { return Ref; } + constexpr auto &unwrap() noexcept { return Ref; } + LLVMOrcThreadSafeModuleRef release() noexcept { + return std::exchange(Ref, nullptr); + } + friend void swap(OrcThreadSafeModule &LHS, + OrcThreadSafeModule &RHS) noexcept { + using std::swap; + swap(LHS.Ref, RHS.Ref); + } + Error withModuleDo(LLVMOrcGenericIRModuleOperationFunction F, + void *Ctx) noexcept { + return LLVMOrcThreadSafeModuleWithModuleDo(Ref, F, Ctx); + } + +private: + LLVMOrcThreadSafeModuleRef Ref = nullptr; +}; + +class OrcJITDylib { +public: + constexpr OrcJITDylib() noexcept = default; + constexpr OrcJITDylib(LLVMOrcJITDylibRef R) noexcept : Ref(R) {} + OrcJITDylib(const OrcJITDylib &) = delete; + OrcJITDylib &operator=(const OrcJITDylib &) = delete; + OrcJITDylib(OrcJITDylib &&B) noexcept : OrcJITDylib() { swap(*this, B); } + OrcJITDylib &operator=(OrcJITDylib &&B) noexcept { + swap(*this, B); + return *this; + } + + constexpr operator bool() const noexcept { return Ref != nullptr; } + constexpr auto &unwrap() const noexcept { return Ref; } + constexpr auto &unwrap() noexcept { return Ref; } + friend void swap(OrcJITDylib &LHS, OrcJITDylib &RHS) noexcept { + using std::swap; + swap(LHS.Ref, RHS.Ref); + } + +private: + LLVMOrcJITDylibRef Ref = nullptr; +}; + +class OrcIRTransformLayer { +public: + constexpr OrcIRTransformLayer() noexcept = default; + constexpr OrcIRTransformLayer(LLVMOrcIRTransformLayerRef R) noexcept + : Ref(R) {} + OrcIRTransformLayer(const OrcIRTransformLayer &) = delete; + OrcIRTransformLayer &operator=(const OrcIRTransformLayer &) = delete; + OrcIRTransformLayer(OrcIRTransformLayer &&B) noexcept + : OrcIRTransformLayer() { + swap(*this, B); + } + OrcIRTransformLayer &operator=(OrcIRTransformLayer &&B) noexcept { + swap(*this, B); + return *this; + } + + constexpr operator bool() const noexcept { return Ref != nullptr; } + constexpr auto &unwrap() const noexcept { return Ref; } + constexpr auto &unwrap() noexcept { return Ref; } + friend void swap(OrcIRTransformLayer &LHS, + OrcIRTransformLayer &RHS) noexcept { + using std::swap; + swap(LHS.Ref, RHS.Ref); + } + + void setTransform(LLVMOrcIRTransformLayerTransformFunction TransformFunction, + void *Ctx) noexcept { + LLVMOrcIRTransformLayerSetTransform(Ref, TransformFunction, Ctx); + } + +private: + LLVMOrcIRTransformLayerRef Ref = nullptr; +}; + +class OrcLLJIT { +public: + constexpr OrcLLJIT() noexcept = default; + constexpr OrcLLJIT(LLVMOrcLLJITRef R) noexcept : Ref(R) {} + OrcLLJIT(const OrcLLJIT &) = delete; + OrcLLJIT &operator=(const OrcLLJIT &) = delete; + OrcLLJIT(OrcLLJIT &&B) noexcept : OrcLLJIT() { swap(*this, B); } + OrcLLJIT &operator=(OrcLLJIT &&B) noexcept { + swap(*this, B); + return *this; + } + + ~OrcLLJIT() noexcept { LLVMOrcDisposeLLJIT(Ref); } + + constexpr operator bool() const noexcept { return Ref != nullptr; } + constexpr auto &unwrap() const noexcept { return Ref; } + constexpr auto &unwrap() noexcept { return Ref; } + friend void swap(OrcLLJIT &LHS, OrcLLJIT &RHS) noexcept { + using std::swap; + swap(LHS.Ref, RHS.Ref); + } + + static cxx20::expected<OrcLLJIT, Error> create() noexcept { + OrcLLJIT Result; + if (auto Err = LLVMOrcCreateLLJIT(&Result.Ref, getBuilder())) { + return cxx20::unexpected(Err); + } else { + return Result; + } + } + + OrcJITDylib getMainJITDylib() noexcept { + return LLVMOrcLLJITGetMainJITDylib(Ref); + } + + Error addLLVMIRModule(const OrcJITDylib &L, OrcThreadSafeModule M) noexcept { + return LLVMOrcLLJITAddLLVMIRModule(Ref, L.unwrap(), M.release()); + } + + template <typename T> + cxx20::expected<T *, Error> lookup(const char *Name) noexcept { + LLVMOrcJITTargetAddress Addr; + if (auto Err = LLVMOrcLLJITLookup(Ref, &Addr, Name)) { + return cxx20::unexpected(Err); + } + return reinterpret_cast<T *>(Addr); + } + + OrcIRTransformLayer getIRTransformLayer() noexcept { + return LLVMOrcLLJITGetIRTransformLayer(Ref); + } + +private: + LLVMOrcLLJITRef Ref = nullptr; + + static inline LLVMOrcLLJITBuilderRef getBuilder() noexcept; +}; + +} // namespace WasmEdge::LLVM #include <llvm/IR/GlobalValue.h> #include <llvm/Object/ObjectFile.h> #include <llvm/Transforms/Utils/BasicBlockUtils.h> +#if LLVM_VERSION_MAJOR < 12 || WASMEDGE_OS_WINDOWS +#include <llvm/ExecutionEngine/Orc/Core.h> +#endif +#if LLVM_VERSION_MAJOR < 13 +#include <llvm/ExecutionEngine/Orc/LLJIT.h> +#include <llvm/Support/CBindingWrapping.h> +#include <llvm/Support/Error.h> +#endif + +#if WASMEDGE_OS_WINDOWS +#include <llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h> +#include <llvm/ExecutionEngine/SectionMemoryManager.h> +#include <llvm/Support/Process.h> +#include <system/winapi.h> +#endif + +namespace llvm { +#if WASMEDGE_OS_WINDOWS +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(orc::ExecutionSession, + LLVMOrcExecutionSessionRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(orc::ObjectLayer, LLVMOrcObjectLayerRef) +#endif +#if LLVM_VERSION_MAJOR < 12 +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(orc::LLJITBuilder, LLVMOrcLLJITBuilderRef) +#endif +#if LLVM_VERSION_MAJOR < 13 +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(orc::ThreadSafeModule, + LLVMOrcThreadSafeModuleRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(orc::IRTransformLayer, + LLVMOrcIRTransformLayerRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(orc::MaterializationResponsibility, + LLVMOrcMaterializationResponsibilityRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(orc::LLJIT, LLVMOrcLLJITRef) +#endif +} // namespace llvm -namespace WasmEdge::AOT::LLVM { +namespace WasmEdge::LLVM { void Value::setDSOLocal(bool Local) noexcept { llvm::cast<llvm::GlobalValue>(reinterpret_cast<llvm::Value *>(Ref)) @@ -1973,4 +2260,292 @@ bool SectionIterator::isPData() const noexcept { #endif } -} // namespace WasmEdge::AOT::LLVM +bool SectionIterator::isEHFrame() const noexcept { +#if WASMEDGE_OS_LINUX + using namespace std::literals; + return ".eh_frame"sv == getName(); +#elif WASMEDGE_OS_MACOS + using namespace std::literals; + return "__eh_frame"sv == getName(); +#else + return false; +#endif +} + +#if WASMEDGE_OS_WINDOWS +class DefaultMMapper final : public llvm::SectionMemoryManager::MemoryMapper { +public: + llvm::sys::MemoryBlock allocateMappedMemory( + llvm::SectionMemoryManager::AllocationPurpose /*Purpose*/, + size_t NumBytes, const llvm::sys::MemoryBlock *const NearBlock, + unsigned Flags, std::error_code &EC) override { + return llvm::sys::Memory::allocateMappedMemory(NumBytes, NearBlock, Flags, + EC); + } + std::error_code protectMappedMemory(const llvm::sys::MemoryBlock &Block, + unsigned Flags) override { + return llvm::sys::Memory::protectMappedMemory(Block, Flags); + } + + std::error_code releaseMappedMemory(llvm::sys::MemoryBlock &M) override { + return llvm::sys::Memory::releaseMappedMemory(M); + } +}; + +class ContiguousSectionMemoryManager : public llvm::RTDyldMemoryManager { +public: + explicit ContiguousSectionMemoryManager( + llvm::SectionMemoryManager::MemoryMapper *UnownedMM = nullptr) + : MMapper(UnownedMM), OwnedMMapper(nullptr) { + if (!MMapper) { + OwnedMMapper = std::make_unique<DefaultMMapper>(); + MMapper = OwnedMMapper.get(); + } + } + + ~ContiguousSectionMemoryManager() noexcept override { + using namespace std::literals; + if (Preallocated.allocatedSize() != 0) { + auto EC = MMapper->releaseMappedMemory(Preallocated); + if (EC) { + spdlog::error("releaseMappedMemory failed with error: {}"sv, + EC.message()); + } + } + } + + bool needsToReserveAllocationSpace() override { return true; } + + void reserveAllocationSpace(uintptr_t CodeSize, llvm::Align CodeAlign, + uintptr_t RODataSize, llvm::Align RODataAlign, + uintptr_t RWDataSize, + llvm::Align RWDataAlign) override { + using namespace std::literals; + assuming(Preallocated.allocatedSize() == 0); + + static const size_t PageSize = llvm::sys::Process::getPageSizeEstimate(); + assuming(CodeAlign.value() <= PageSize); + assuming(RODataAlign.value() <= PageSize); + assuming(RWDataAlign.value() <= PageSize); + CodeSize = roundUpTo(CodeSize + CodeAlign.value(), PageSize); + RODataSize = roundUpTo(RODataSize + RODataAlign.value(), PageSize); + RWDataSize = roundUpTo(RWDataSize + RWDataAlign.value(), PageSize); + const uintptr_t TotalSize = + CodeSize + RODataSize + RWDataSize + PageSize * 3; + + std::error_code EC; + Preallocated = MMapper->allocateMappedMemory( + llvm::SectionMemoryManager::AllocationPurpose::Code, TotalSize, nullptr, + llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE, EC); + if (EC) { + spdlog::error("allocateMappedMemory failed with error: {}"sv, + EC.message()); + return; + } + + auto base = reinterpret_cast<std::uintptr_t>(Preallocated.base()); + CodeMem = CodeFree = + llvm::sys::MemoryBlock(reinterpret_cast<void *>(base), CodeSize); + base += CodeSize; + RODataMem = RODataFree = + llvm::sys::MemoryBlock(reinterpret_cast<void *>(base), RODataSize); + base += RODataSize; + RWDataMem = RWDataFree = + llvm::sys::MemoryBlock(reinterpret_cast<void *>(base), RWDataSize); + } + + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned /*SectionID*/, + llvm::StringRef /*SectionName*/, + bool IsReadOnly) override { + if (IsReadOnly) { + return Allocate(RODataFree, Size, Alignment); + } else { + return Allocate(RWDataFree, Size, Alignment); + } + } + + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned /*SectionID*/, + llvm::StringRef /*SectionName*/) override { + return Allocate(CodeFree, Size, Alignment); + } + + bool finalizeMemory(std::string *ErrMsg) override { + std::error_code EC; + + EC = MMapper->protectMappedMemory(CodeMem, llvm::sys::Memory::MF_READ | + llvm::sys::Memory::MF_EXEC); + if (EC) { + if (ErrMsg) { + *ErrMsg = EC.message(); + } + return true; + } + EC = MMapper->protectMappedMemory(RODataMem, llvm::sys::Memory::MF_READ); + if (EC) { + if (ErrMsg) { + *ErrMsg = EC.message(); + } + return true; + } + + llvm::sys::Memory::InvalidateInstructionCache(CodeMem.base(), + CodeMem.allocatedSize()); + return false; + } + +private: + llvm::sys::MemoryBlock Preallocated; + + // Sections must be in the order code < rodata < rwdata. + llvm::sys::MemoryBlock CodeMem; + llvm::sys::MemoryBlock RODataMem; + llvm::sys::MemoryBlock RWDataMem; + + llvm::sys::MemoryBlock CodeFree; + llvm::sys::MemoryBlock RODataFree; + llvm::sys::MemoryBlock RWDataFree; + + llvm::SectionMemoryManager::MemoryMapper *MMapper; + std::unique_ptr<llvm::SectionMemoryManager::MemoryMapper> OwnedMMapper; + + uint8_t *Allocate(llvm::sys::MemoryBlock &FreeBlock, std::uintptr_t Size, + unsigned alignment) { + using namespace std::literals; + const auto Base = reinterpret_cast<uintptr_t>(FreeBlock.base()); + const auto Start = roundUpTo(Base, alignment); + const uintptr_t PaddedSize = (Start - Base) + Size; + if (PaddedSize > FreeBlock.allocatedSize()) { + spdlog::error("Failed to satisfy suballocation request for {}"sv, Size); + return nullptr; + } + FreeBlock = + llvm::sys::MemoryBlock(reinterpret_cast<void *>(Base + PaddedSize), + FreeBlock.allocatedSize() - PaddedSize); + return reinterpret_cast<uint8_t *>(Start); + } + + static uintptr_t roundUpTo(uintptr_t Value, uintptr_t Divisor) noexcept { + return ((Value + (Divisor - 1)) / Divisor) * Divisor; + } +}; + +// Register stack unwind info for JIT functions +class Win64EHManager : public ContiguousSectionMemoryManager { + using Base = ContiguousSectionMemoryManager; + uint64_t CodeAddress = 0; + +public: + ~Win64EHManager() noexcept override {} + + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, + llvm::StringRef SectionName) override { + using namespace std::literals; + const auto Allocated = + Base::allocateCodeSection(Size, Alignment, SectionID, SectionName); + if (SectionName == llvm::StringRef(".text"sv)) { + CodeAddress = reinterpret_cast<uint64_t>(Allocated); + } + return Allocated; + } + + void registerEHFrames(uint8_t *Addr, uint64_t /*LoadAddr*/, + size_t Size) noexcept override { + using namespace std::literals; + winapi::RUNTIME_FUNCTION_ *const FunctionTable = + reinterpret_cast<winapi::RUNTIME_FUNCTION_ *>(Addr); + const uint32_t EntryCount = + static_cast<uint32_t>(Size / sizeof(winapi::RUNTIME_FUNCTION_)); + if (EntryCount == 0) + return; + // Calculate object image base address by assuming that address of the first + // function is equal to the address of the code section + const auto ImageBase = CodeAddress - FunctionTable[0].BeginAddress; + winapi::RtlAddFunctionTable(FunctionTable, EntryCount, ImageBase); + EHFrames.push_back({Addr, Size}); + } + void deregisterEHFrames() noexcept override { + using namespace std::literals; + for (auto &Frame : EHFrames) { + winapi::RtlDeleteFunctionTable( + reinterpret_cast<winapi::RUNTIME_FUNCTION_ *>(Frame.Addr)); + } + EHFrames.clear(); + } +}; + +LLVMOrcLLJITBuilderRef OrcLLJIT::getBuilder() noexcept { + using llvm::unwrap; + using llvm::wrap; + const LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder(); + LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator( + Builder, + [](void *, LLVMOrcExecutionSessionRef ES, const char *) noexcept { + auto Layer = std::make_unique<llvm::orc::RTDyldObjectLinkingLayer>( + *unwrap(ES), []() { return std::make_unique<Win64EHManager>(); }); + Layer->setOverrideObjectFlagsWithResponsibilityFlags(true); + Layer->setAutoClaimResponsibilityForObjectSymbols(true); + return wrap(static_cast<llvm::orc::ObjectLayer *>(Layer.release())); + }, + nullptr); + return Builder; +} +#else +LLVMOrcLLJITBuilderRef OrcLLJIT::getBuilder() noexcept { return nullptr; } +#endif + +} // namespace WasmEdge::LLVM + +#if LLVM_VERSION_MAJOR < 12 && WASMEDGE_OS_WINDOWS +void LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator( + LLVMOrcLLJITBuilderRef Builder, + LLVMOrcLLJITBuilderObjectLinkingLayerCreatorFunction F, + void *Ctx) noexcept { + using llvm::unwrap; + using llvm::wrap; + unwrap(Builder)->setObjectLinkingLayerCreator( + [=](llvm::orc::ExecutionSession &ES, const llvm::Triple &TT) { + auto TTStr = TT.str(); + return std::unique_ptr<llvm::orc::ObjectLayer>( + unwrap(F(Ctx, wrap(&ES), TTStr.c_str()))); + }); +} +#endif +#if LLVM_VERSION_MAJOR < 13 +LLVMOrcIRTransformLayerRef +LLVMOrcLLJITGetIRTransformLayer(LLVMOrcLLJITRef J) noexcept { + using llvm::unwrap; + using llvm::wrap; + return wrap(&(unwrap(J)->getIRTransformLayer())); +} +void LLVMOrcIRTransformLayerSetTransform( + LLVMOrcIRTransformLayerRef IRTransformLayer, + LLVMOrcIRTransformLayerTransformFunction TransformFunction, + void *Ctx) noexcept { + using llvm::unwrap; + using llvm::wrap; + unwrap(IRTransformLayer) + ->setTransform([=](llvm::orc::ThreadSafeModule TSM, + llvm::orc::MaterializationResponsibility &R) + -> llvm::Expected<llvm::orc::ThreadSafeModule> { + LLVMOrcThreadSafeModuleRef TSMRef = + wrap(new llvm::orc::ThreadSafeModule(std::move(TSM))); + if (LLVMErrorRef Err = TransformFunction(Ctx, &TSMRef, wrap(&R))) { + return unwrap(Err); + } + return std::move(*unwrap(TSMRef)); + }); +} + +LLVMErrorRef +LLVMOrcThreadSafeModuleWithModuleDo(LLVMOrcThreadSafeModuleRef TSM, + LLVMOrcGenericIRModuleOperationFunction F, + void *Ctx) noexcept { + using llvm::unwrap; + using llvm::wrap; + return wrap(unwrap(TSM)->withModuleDo( + [&](llvm::Module &M) { return unwrap(F(Ctx, wrap(&M))); })); +} +#endif diff --git a/lib/loader/CMakeLists.txt b/lib/loader/CMakeLists.txt index c763ae34d3ae..2b65a2c2d57f 100644 --- a/lib/loader/CMakeLists.txt +++ b/lib/loader/CMakeLists.txt @@ -1,10 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_library(wasmedgeLoaderFileMgr filemgr.cpp - ldmgr.cpp shared_library.cpp + aot_section.cpp ) target_link_libraries(wasmedgeLoaderFileMgr @@ -23,13 +23,13 @@ endif() wasmedge_add_library(wasmedgeLoader ast/component.cpp - ast/component/sort.cpp - ast/component/instance.cpp - ast/component/alias.cpp + ast/component/component_alias.cpp + ast/component/component_canonical.cpp + ast/component/component_import_export.cpp + ast/component/component_instance.cpp + ast/component/component_start.cpp + ast/component/component_sort.cpp ast/component/component_type.cpp - ast/component/canonical.cpp - ast/component/start.cpp - ast/component/import_export.cpp ast/module.cpp ast/section.cpp ast/description.cpp diff --git a/lib/loader/aot_section.cpp b/lib/loader/aot_section.cpp new file mode 100644 index 000000000000..22e7bc1c1f8a --- /dev/null +++ b/lib/loader/aot_section.cpp @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "loader/aot_section.h" +#include "common/spdlog.h" +#include "system/allocator.h" + +#if WASMEDGE_OS_LINUX || WASMEDGE_OS_MACOS +extern "C" { +extern void __register_frame(void *); +extern void __deregister_frame(void *); +} +#endif + +namespace { +inline constexpr uint64_t roundDownPageBoundary(const uint64_t Value) { +// ARM64 Mac has a special page size +#if WASMEDGE_OS_MACOS && defined(__aarch64__) + return Value & ~UINT64_C(16383); +#else + return Value & ~UINT64_C(4095); +#endif +} +inline constexpr uint64_t roundUpPageBoundary(const uint64_t Value) { +// ARM64 Mac has a special page size +#if WASMEDGE_OS_MACOS && defined(__aarch64__) + return roundDownPageBoundary(Value + UINT64_C(16383)); +#else + return roundDownPageBoundary(Value + UINT64_C(4095)); +#endif +} +} // namespace + +namespace WasmEdge::Loader { + +Expect<void> AOTSection::load(const AST::AOTSection &AOTSec) noexcept { + BinarySize = 0; + for (const auto &Section : AOTSec.getSections()) { + const auto Offset = std::get<1>(Section); + const auto Size = std::get<2>(Section); + BinarySize = std::max(BinarySize, Offset + Size); + } + BinarySize = roundUpPageBoundary(BinarySize); + + Binary = Allocator::allocate_chunk(BinarySize); + if (unlikely(!Binary)) { + spdlog::error(ErrCode::Value::MemoryOutOfBounds); + return Unexpect(ErrCode::Value::MemoryOutOfBounds); + } + + std::vector<std::pair<uint8_t *, uint64_t>> ExecutableRanges; + for (const auto &Section : AOTSec.getSections()) { + const auto Offset = std::get<1>(Section); + const auto Size = std::get<2>(Section); + const auto &Content = std::get<3>(Section); + if (Size > BinarySize || Offset > BinarySize || + Offset + Size > BinarySize || Content.size() > Size) { + return Unexpect(ErrCode::Value::IntegerTooLarge); + } + std::copy(Content.begin(), Content.end(), Binary + Offset); + switch (std::get<0>(Section)) { + case 1: { // Text + const auto O = roundDownPageBoundary(Offset); + const auto S = roundUpPageBoundary(Size + (Offset - O)); + ExecutableRanges.emplace_back(Binary + O, S); + break; + } + case 2: // Data + break; + case 3: // BSS + break; +#if WASMEDGE_OS_LINUX + case 4: // EHFrame + EHFrameAddress = reinterpret_cast<void *>(Binary + Offset); + break; +#elif WASMEDGE_OS_MACOS + case 4: // EHFrame + EHFrameAddress = reinterpret_cast<uint8_t *>(Binary + Offset); + EHFrameSize = Size; + break; +#elif WASMEDGE_OS_WINDOWS + case 4: // PData + PDataAddress = reinterpret_cast<void *>(Binary + Offset); + PDataSize = + static_cast<uint32_t>(Size / sizeof(winapi::RUNTIME_FUNCTION_)); + break; +#endif + default: + return Unexpect(ErrCode::Value::IntegerTooLarge); + } + } + + for (const auto &[Pointer, Size] : ExecutableRanges) { + if (!Allocator::set_chunk_executable(Pointer, Size)) { + spdlog::error(ErrCode::Value::MemoryOutOfBounds); + spdlog::error(" set_chunk_executable failed:{}", std::strerror(errno)); + return Unexpect(ErrCode::Value::MemoryOutOfBounds); + } + } + + IntrinsicsAddress = AOTSec.getIntrinsicsAddress(); + TypesAddress = AOTSec.getTypesAddress(); + CodesAddress = AOTSec.getCodesAddress(); + +#if WASMEDGE_OS_LINUX + if (EHFrameAddress) { + __register_frame(EHFrameAddress); + } +#elif WASMEDGE_OS_MACOS + if (EHFrameAddress) { + auto Iter = EHFrameAddress; + const auto End = EHFrameAddress + EHFrameSize - 4; + + while (Iter < End) { + if (Iter != EHFrameAddress) { + __register_frame(Iter); + } + const uint32_t Length = *reinterpret_cast<const uint32_t *>(Iter); + Iter += Length + 4; + } + } +#elif WASMEDGE_OS_WINDOWS + if (PDataSize != 0) { + winapi::RtlAddFunctionTable( + static_cast<winapi::PRUNTIME_FUNCTION_>(PDataAddress), PDataSize, + reinterpret_cast<winapi::ULONG_PTR_>(Binary)); + } +#endif + + return {}; +} + +void AOTSection::unload() noexcept { + if (Binary) { +#if WASMEDGE_OS_LINUX + if (EHFrameAddress) { + __deregister_frame(EHFrameAddress); + } +#elif WASMEDGE_OS_MACOS + if (EHFrameAddress) { + auto Iter = EHFrameAddress; + const auto End = EHFrameAddress + EHFrameSize - 4; + + while (Iter < End) { + if (Iter != EHFrameAddress) { + __deregister_frame(Iter); + } + const uint32_t Length = *reinterpret_cast<const uint32_t *>(Iter); + Iter += Length + 4; + } + } +#elif WASMEDGE_OS_WINDOWS + if (PDataSize != 0) { + winapi::RtlDeleteFunctionTable( + static_cast<winapi::PRUNTIME_FUNCTION_>(PDataAddress)); + } +#endif + Allocator::set_chunk_readable_writable(Binary, BinarySize); + Allocator::release_chunk(Binary, BinarySize); + Binary = nullptr; + } +} + +} // namespace WasmEdge::Loader diff --git a/lib/loader/ast/component.cpp b/lib/loader/ast/component.cpp index dee412aa64c8..1690bb36d150 100644 --- a/lib/loader/ast/component.cpp +++ b/lib/loader/ast/component.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" #include "spdlog/common.h" @@ -31,6 +31,7 @@ Expect<std::pair<std::vector<Byte>, std::vector<Byte>>> Loader::loadPreamble() { } std::vector<Byte> WasmMagic = {0x00, 0x61, 0x73, 0x6D}; if (*Magic != WasmMagic) { + spdlog::error("Might an invalid wasm file"); return logLoadError(ErrCode::Value::MalformedMagic, FMgr.getLastOffset(), ASTNodeAttr::Component); } @@ -56,7 +57,6 @@ Loader::loadUnit() { Mod->getMagic() = WasmMagic; Mod->getVersion() = Ver; if (!Conf.getRuntimeConfigure().isForceInterpreter()) { - if (auto Res = loadModuleAOT(Mod->getAOTSection()); !Res) { return Unexpect(Res); } @@ -97,6 +97,8 @@ Loader::loadUnit() { } Expect<void> Loader::loadComponent(AST::Component::Component &Comp) { + using namespace AST::Component; + while (auto ResSecId = FMgr.readByte()) { if (!ResSecId) { return logLoadError(ResSecId.error(), FMgr.getLastOffset(), @@ -107,103 +109,120 @@ Expect<void> Loader::loadComponent(AST::Component::Component &Comp) { switch (NewSectionId) { case 0x00: - Comp.getCustomSections().emplace_back(); - if (auto Res = loadSection(Comp.getCustomSections().back()); !Res) { + Comp.getSections().emplace_back(); + if (auto Res = loadSection( + Comp.getSections().back().emplace<AST::CustomSection>()); + !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } break; case 0x01: - if (auto Res = loadSection(Comp.getCoreModuleSection()); !Res) { + Comp.getSections().emplace_back(); + if (auto Res = loadSection( + Comp.getSections().back().emplace<AST::CoreModuleSection>()); + !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } break; case 0x02: { - AST::Component::CoreInstanceSection Sec; - if (auto Res = loadSection(Sec); !Res) { + Comp.getSections().emplace_back(); + if (auto Res = loadSection( + Comp.getSections().back().emplace<CoreInstanceSection>()); + !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } - Comp.getCoreInstanceSection().push_back(Sec); break; } case 0x03: { - AST::Component::CoreTypeSection Sec; - if (auto Res = loadSection(Sec); !Res) { + Comp.getSections().emplace_back(); + if (auto Res = + loadSection(Comp.getSections().back().emplace<CoreTypeSection>()); + !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } - Comp.getCoreTypeSection().push_back(Sec); break; } case 0x04: - if (auto Res = loadSection(Comp.getComponentSection()); !Res) { + Comp.getSections().emplace_back(); + if (auto Res = loadSection( + Comp.getSections().back().emplace<ComponentSection>()); + !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } break; case 0x05: { - AST::Component::InstanceSection Sec; - if (auto Res = loadSection(Sec); !Res) { + Comp.getSections().emplace_back(); + if (auto Res = + loadSection(Comp.getSections().back().emplace<InstanceSection>()); + !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } - Comp.getInstanceSection().push_back(Sec); break; } case 0x06: { - AST::Component::AliasSection Sec; - if (auto Res = loadSection(Sec); !Res) { + Comp.getSections().emplace_back(); + if (auto Res = + loadSection(Comp.getSections().back().emplace<AliasSection>()); + !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } - Comp.getAliasSection().push_back(Sec); break; } case 0x07: { - AST::Component::TypeSection Sec; - if (auto Res = loadSection(Sec); !Res) { + Comp.getSections().emplace_back(); + if (auto Res = + loadSection(Comp.getSections().back().emplace<TypeSection>()); + !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } - Comp.getTypeSection().push_back(Sec); break; } case 0x08: { - AST::Component::CanonSection Sec; - if (auto Res = loadSection(Sec); !Res) { + Comp.getSections().emplace_back(); + if (auto Res = + loadSection(Comp.getSections().back().emplace<CanonSection>()); + !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } - Comp.getCanonSection().push_back(Sec); break; } case 0x09: { - AST::Component::Start S; - if (auto Res = loadStart(S); !Res) { + Comp.getSections().emplace_back(); + if (auto Res = + loadSection(Comp.getSections().back().emplace<StartSection>()); + !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } - Comp.getStartSection().getContent().push_back(S); break; } case 0x0A: { - AST::Component::ImportSection Sec; - if (auto Res = loadSection(Sec); !Res) { + Comp.getSections().emplace_back(); + if (auto Res = + loadSection(Comp.getSections().back().emplace<ImportSection>()); + !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } - Comp.getImportSection().push_back(Sec); break; } case 0x0B: { - AST::Component::ExportSection Sec; - if (auto Res = loadSection(Sec); !Res) { + Comp.getSections().emplace_back(); + if (auto Res = + loadSection(Comp.getSections().back().emplace<ExportSection>()); + !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } - Comp.getExportSection().push_back(Sec); break; } default: diff --git a/lib/loader/ast/component/alias.cpp b/lib/loader/ast/component/component_alias.cpp similarity index 97% rename from lib/loader/ast/component/alias.cpp rename to lib/loader/ast/component/component_alias.cpp index b12ba255eb05..c4a5ffb20478 100644 --- a/lib/loader/ast/component/alias.cpp +++ b/lib/loader/ast/component/component_alias.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" #include <cstdint> diff --git a/lib/loader/ast/component/canonical.cpp b/lib/loader/ast/component/component_canonical.cpp similarity index 98% rename from lib/loader/ast/component/canonical.cpp rename to lib/loader/ast/component/component_canonical.cpp index 93db7cf748d3..974cfbc3bca3 100644 --- a/lib/loader/ast/component/canonical.cpp +++ b/lib/loader/ast/component/component_canonical.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" namespace WasmEdge { diff --git a/lib/loader/ast/component/import_export.cpp b/lib/loader/ast/component/component_import_export.cpp similarity index 95% rename from lib/loader/ast/component/import_export.cpp rename to lib/loader/ast/component/component_import_export.cpp index b18f0ab50ec4..33cf59b9cb3e 100644 --- a/lib/loader/ast/component/import_export.cpp +++ b/lib/loader/ast/component/component_import_export.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" namespace WasmEdge { diff --git a/lib/loader/ast/component/instance.cpp b/lib/loader/ast/component/component_instance.cpp similarity index 98% rename from lib/loader/ast/component/instance.cpp rename to lib/loader/ast/component/component_instance.cpp index 0153e73bc334..f88d9eacc749 100644 --- a/lib/loader/ast/component/instance.cpp +++ b/lib/loader/ast/component/component_instance.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" #include <cstdint> diff --git a/lib/loader/ast/component/sort.cpp b/lib/loader/ast/component/component_sort.cpp similarity index 97% rename from lib/loader/ast/component/sort.cpp rename to lib/loader/ast/component/component_sort.cpp index e8e016cd2e98..68ff6fe75a5e 100644 --- a/lib/loader/ast/component/sort.cpp +++ b/lib/loader/ast/component/component_sort.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" #include <cstdint> diff --git a/lib/loader/ast/component/start.cpp b/lib/loader/ast/component/component_start.cpp similarity index 93% rename from lib/loader/ast/component/start.cpp rename to lib/loader/ast/component/component_start.cpp index 963258e29546..a8863e3d3538 100644 --- a/lib/loader/ast/component/start.cpp +++ b/lib/loader/ast/component/component_start.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" namespace WasmEdge { diff --git a/lib/loader/ast/component/type.cpp b/lib/loader/ast/component/type.cpp index 7afd5270b165..0045b643802d 100644 --- a/lib/loader/ast/component/type.cpp +++ b/lib/loader/ast/component/type.cpp @@ -312,14 +312,13 @@ Expect<void> Loader::loadType(ComponentType &Ty) { } Expect<void> Loader::loadComponentDecl(ComponentDecl &Decl) { - auto Pos = FMgr.getLastOffset(); - auto Res = FMgr.readByte(); + auto Res = FMgr.peekByte(); if (!Res) { return Unexpect(Res); } else if (*Res != 0x03U) { - FMgr.seek(Pos); return loadInstanceDecl(Decl.emplace<InstanceDecl>()); } else { + FMgr.readByte(); return loadImportDecl(Decl.emplace<ImportDecl>()); } } @@ -363,7 +362,7 @@ Expect<void> Loader::loadType(FuncType &Ty) { // ps:<paramlist> rs:<resultlist> // => (func ps rs) if (auto Res = loadVec<TypeSection>( - Ty.getParamList(), [this](LabelValType LV) { return loadType(LV); }); + Ty.getParamList(), [this](LabelValType &LV) { return loadType(LV); }); !Res) { return Unexpect(Res); } @@ -613,4 +612,4 @@ Expect<void> Loader::loadExportDecl(CoreExportDecl &Decl) { } } // namespace Loader -} // namespace WasmEdge +} // namespace WasmEdge \ No newline at end of file diff --git a/lib/loader/ast/description.cpp b/lib/loader/ast/description.cpp index fcfe5a66885b..ee0ab2d22d3f 100644 --- a/lib/loader/ast/description.cpp +++ b/lib/loader/ast/description.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" @@ -66,6 +66,15 @@ Expect<void> Loader::loadDesc(AST::ImportDesc &ImpDesc) { } return {}; } + case ExternalType::Tag: { + if (!Conf.hasProposal(Proposal::ExceptionHandling)) { + return logNeedProposal(ErrCode::Value::MalformedImportKind, + Proposal::ExceptionHandling, FMgr.getLastOffset(), + ASTNodeAttr::Module); + } + // Read the Tag type node. + return loadType(ImpDesc.getExternalTagType()); + } default: return logLoadError(ErrCode::Value::MalformedImportKind, FMgr.getLastOffset(), ASTNodeAttr::Desc_Import); @@ -96,6 +105,13 @@ Expect<void> Loader::loadDesc(AST::ExportDesc &ExpDesc) { case ExternalType::Memory: case ExternalType::Global: break; + case ExternalType::Tag: + if (!Conf.hasProposal(Proposal::ExceptionHandling)) { + return logNeedProposal(ErrCode::Value::MalformedImportKind, + Proposal::ExceptionHandling, FMgr.getLastOffset(), + ASTNodeAttr::Module); + } + break; default: return logLoadError(ErrCode::Value::MalformedExportKind, FMgr.getLastOffset(), ASTNodeAttr::Desc_Export); diff --git a/lib/loader/ast/expression.cpp b/lib/loader/ast/expression.cpp index 9a095524e8a5..a32978dd2e96 100644 --- a/lib/loader/ast/expression.cpp +++ b/lib/loader/ast/expression.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" diff --git a/lib/loader/ast/instruction.cpp b/lib/loader/ast/instruction.cpp index f5b1679be61b..2ae84e65eca1 100644 --- a/lib/loader/ast/instruction.cpp +++ b/lib/loader/ast/instruction.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" @@ -12,23 +12,124 @@ namespace Loader { // OpCode loader. See "include/loader/loader.h". Expect<OpCode> Loader::loadOpCode() { - uint16_t Payload; + uint8_t Prefix; if (auto B1 = FMgr.readByte()) { - Payload = (*B1); + Prefix = (*B1); } else { return Unexpect(B1); } - if (Payload == 0xFCU || Payload == 0xFDU || Payload == 0xFEU) { - // 2-bytes OpCode case. + if (Prefix >= 0xFBU && Prefix <= 0xFEU) { + // Multi-byte OpCode case. + uint32_t Extend; if (auto B2 = FMgr.readU32()) { - Payload <<= 8; - Payload += static_cast<uint16_t>(*B2); + Extend = (*B2); } else { return Unexpect(B2); } + if (Prefix == 0xFBU) { + switch (Extend) { +#define UseOpCode +#define Line(NAME, STRING, PREFIX) +#define Line_FB(NAME, STRING, PREFIX, EXTEND) \ + case EXTEND: \ + return OpCode::NAME; +#define Line_FC(NAME, STRING, PREFIX, EXTEND) +#define Line_FD(NAME, STRING, PREFIX, EXTEND) +#define Line_FE(NAME, STRING, PREFIX, EXTEND) +#include "common/enum.inc" +#undef Line +#undef Line_FB +#undef Line_FC +#undef Line_FD +#undef Line_FE +#undef UseOpCode + default: + return Unexpect(ErrCode::Value::IllegalOpCode); + } + } else if (Prefix == 0xFCU) { + switch (Extend) { +#define UseOpCode +#define Line(NAME, STRING, PREFIX) +#define Line_FB(NAME, STRING, PREFIX, EXTEND) +#define Line_FC(NAME, STRING, PREFIX, EXTEND) \ + case EXTEND: \ + return OpCode::NAME; +#define Line_FD(NAME, STRING, PREFIX, EXTEND) +#define Line_FE(NAME, STRING, PREFIX, EXTEND) +#include "common/enum.inc" +#undef Line +#undef Line_FB +#undef Line_FC +#undef Line_FD +#undef Line_FE +#undef UseOpCode + default: + return Unexpect(ErrCode::Value::IllegalOpCode); + } + } else if (Prefix == 0xFDU) { + switch (Extend) { +#define UseOpCode +#define Line(NAME, STRING, PREFIX) +#define Line_FB(NAME, STRING, PREFIX, EXTEND) +#define Line_FC(NAME, STRING, PREFIX, EXTEND) +#define Line_FD(NAME, STRING, PREFIX, EXTEND) \ + case EXTEND: \ + return OpCode::NAME; +#define Line_FE(NAME, STRING, PREFIX, EXTEND) +#include "common/enum.inc" +#undef Line +#undef Line_FB +#undef Line_FC +#undef Line_FD +#undef Line_FE +#undef UseOpCode + default: + return Unexpect(ErrCode::Value::IllegalOpCode); + } + } else { + switch (Extend) { +#define UseOpCode +#define Line(NAME, STRING, PREFIX) +#define Line_FB(NAME, STRING, PREFIX, EXTEND) +#define Line_FC(NAME, STRING, PREFIX, EXTEND) +#define Line_FD(NAME, STRING, PREFIX, EXTEND) +#define Line_FE(NAME, STRING, PREFIX, EXTEND) \ + case EXTEND: \ + return OpCode::NAME; +#include "common/enum.inc" +#undef Line +#undef Line_FB +#undef Line_FC +#undef Line_FD +#undef Line_FE +#undef UseOpCode + default: + return Unexpect(ErrCode::Value::IllegalOpCode); + } + } + } else { + // Single-byte OpCode case. + switch (Prefix) { +#define UseOpCode +#define Line(NAME, STRING, PREFIX) \ + case PREFIX: \ + return OpCode::NAME; +#define Line_FB(NAME, STRING, PREFIX, EXTEND) +#define Line_FC(NAME, STRING, PREFIX, EXTEND) +#define Line_FD(NAME, STRING, PREFIX, EXTEND) +#define Line_FE(NAME, STRING, PREFIX, EXTEND) +#include "common/enum.inc" +#undef Line +#undef Line_FB +#undef Line_FC +#undef Line_FD +#undef Line_FE +#undef UseOpCode + default: + return Unexpect(ErrCode::Value::IllegalOpCode); + } } - return static_cast<OpCode>(Payload); } // Load instruction sequence. See "include/loader/loader.h". @@ -55,49 +156,58 @@ Expect<AST::InstrVec> Loader::loadInstrSeq(std::optional<uint64_t> SizeBound) { ASTNodeAttr::Instruction); } - // Process the instructions which contain a block. - if (Code == OpCode::Block || Code == OpCode::Loop || Code == OpCode::If) { - BlockStack.push_back(std::make_pair(Code, Cnt)); - } else if (Code == OpCode::Else) { + auto logIllegalOpCode = [this, &Offset, + &SizeBound]() -> Unexpected<ErrCode> { + if (SizeBound.has_value() && FMgr.getOffset() > SizeBound.value()) { + return logLoadError(ErrCode::Value::ENDCodeExpected, Offset, + ASTNodeAttr::Instruction); + } else { + return logLoadError(ErrCode::Value::IllegalOpCode, Offset, + ASTNodeAttr::Instruction); + } + }; + + // Process the instruction which contains a block. + switch (Code) { + case OpCode::Block: + case OpCode::Loop: + case OpCode::If: + // LEGACY-EH: remove the `Try` after deprecating legacy EH. + case OpCode::Try: + case OpCode::Try_table: + BlockStack.emplace_back(Code, Cnt); + break; + case OpCode::Else: { if (BlockStack.size() == 0 || BlockStack.back().first != OpCode::If) { // An Else instruction appeared outside the If-block. - if (SizeBound.has_value() && FMgr.getOffset() > SizeBound.value()) { - return logLoadError(ErrCode::Value::ENDCodeExpected, Offset, - ASTNodeAttr::Instruction); - } else { - return logLoadError(ErrCode::Value::IllegalOpCode, Offset, - ASTNodeAttr::Instruction); - } + return logIllegalOpCode(); } uint32_t Pos = BlockStack.back().second; if (Instrs[Pos].getJumpElse() > 0) { // An Else instruction appeared before in this If-block. - if (SizeBound.has_value() && FMgr.getOffset() > SizeBound.value()) { - return logLoadError(ErrCode::Value::ENDCodeExpected, Offset, - ASTNodeAttr::Instruction); - } else { - return logLoadError(ErrCode::Value::IllegalOpCode, Offset, - ASTNodeAttr::Instruction); - } + return logIllegalOpCode(); } Instrs[Pos].setJumpElse(Cnt - Pos); - } else if (Code == OpCode::End) { - if (BlockStack.size() > 0) { - uint32_t Pos = BlockStack.back().second; - Instrs[Pos].setJumpEnd(Cnt - Pos); - if (BlockStack.back().first == OpCode::If) { - if (Instrs[Pos].getJumpElse() == 0) { - // If block without else. Set the else jump the same as end jump. - Instrs[Pos].setJumpElse(Cnt - Pos); - } else { - const uint32_t ElsePos = Pos + Instrs[Pos].getJumpElse(); - Instrs[ElsePos].setJumpEnd(Cnt - ElsePos); - } - } - BlockStack.pop_back(); - } else { - IsReachEnd = true; + break; + } + // LEGACY-EH: remove the `Catch` cases after deprecating legacy EH. + case OpCode::Catch: + case OpCode::Catch_all: { + if (BlockStack.size() == 0 || BlockStack.back().first != OpCode::Try) { + // A Catch/Catch_all instruction appeared outside a try-block. + return logIllegalOpCode(); + } + auto Pos = BlockStack.back().second; + auto &CatchClause = Instrs[Pos].getTryCatch().Catch; + if (CatchClause.size() > 0 && CatchClause.back().IsAll) { + // A Catch shouldn't behind a Catch_all in the same block. + // And also a try block may contain only one Catch_all instruction. + return logIllegalOpCode(); } + break; + } + default: + break; } // Create the instruction node and load contents. @@ -105,12 +215,56 @@ Expect<AST::InstrVec> Loader::loadInstrSeq(std::optional<uint64_t> SizeBound) { if (auto Res = loadInstruction(Instrs.back()); !Res) { return Unexpect(Res); } + if (Code == OpCode::End) { - if (IsReachEnd) { - Instrs.back().setLast(true); + // Post process the End instruction. + if (BlockStack.size() > 0) { + Instrs.back().setExprLast(false); + const auto &[BackOp, Pos] = BlockStack.back(); + if (BackOp == OpCode::Block || BackOp == OpCode::Loop || + BackOp == OpCode::If) { + Instrs.back().setTryBlockLast(false); + // LEGACY-EH: remove this after deprecating legacy EH. + Instrs.back().setLegacyTryBlockLast(false); + Instrs[Pos].setJumpEnd(Cnt - Pos); + if (BackOp == OpCode::If) { + if (Instrs[Pos].getJumpElse() == 0) { + // If block without else. Set the else jump the same as end jump. + Instrs[Pos].setJumpElse(Cnt - Pos); + } else { + const uint32_t ElsePos = Pos + Instrs[Pos].getJumpElse(); + Instrs[ElsePos].setJumpEnd(Cnt - ElsePos); + } + } + } else if (BackOp == OpCode::Try_table) { + Instrs.back().setTryBlockLast(true); + // LEGACY-EH: remove this after deprecating legacy EH. + Instrs.back().setLegacyTryBlockLast(false); + Instrs[Pos].getTryCatch().JumpEnd = Cnt - Pos; + } else if (BackOp == OpCode::Try) { + // LEGACY-EH: remove the `Try` case after deprecating legacy EH. + Instrs.back().setTryBlockLast(false); + Instrs.back().setLegacyTryBlockLast(true); + Instrs[Pos].getTryCatch().JumpEnd = Cnt - Pos; + } + BlockStack.pop_back(); } else { - Instrs.back().setLast(false); + Instrs.back().setExprLast(true); + IsReachEnd = true; } + } else if (Code == OpCode::Catch || Code == OpCode::Catch_all) { + // LEGACY-EH: remove these cases after deprecating legacy EH. + uint32_t Pos = BlockStack.back().second; + auto &CatchClause = Instrs[Pos].getTryCatch().Catch; + auto &CatchDesc = Instrs.back().getCatchLegacy(); + CatchDesc.CatchPCOffset = Cnt - Pos; + CatchDesc.CatchIndex = static_cast<uint32_t>(CatchClause.size()); + CatchClause.push_back({true, + Code == OpCode::Catch_all, + false, + Code == OpCode::Catch ? CatchDesc.TagIndex : 0, + 0, + {0, 0, 0, 0}}); } Cnt++; } while (!IsReachEnd); @@ -159,11 +313,18 @@ Expect<void> Loader::loadInstruction(AST::Instruction &Instr) { if (auto Res = readU32(Instr.getMemoryAlign()); unlikely(!Res)) { return Unexpect(Res); } - if (Conf.hasProposal(Proposal::MultiMemories) && - Instr.getMemoryAlign() >= 64) { - Instr.getMemoryAlign() -= 64; - if (auto Res = readU32(Instr.getTargetIndex()); unlikely(!Res)) { - return Unexpect(Res); + if (Instr.getMemoryAlign() >= 128) { + return logLoadError(ErrCode::Value::InvalidStoreAlignment, + FMgr.getLastOffset(), ASTNodeAttr::Instruction); + } else if (Instr.getMemoryAlign() >= 64) { + if (Conf.hasProposal(Proposal::MultiMemories)) { + Instr.getMemoryAlign() -= 64; + if (auto Res = readU32(Instr.getTargetIndex()); unlikely(!Res)) { + return Unexpect(Res); + } + } else { + return logLoadError(ErrCode::Value::InvalidStoreAlignment, + FMgr.getLastOffset(), ASTNodeAttr::Instruction); } } if (auto Res = readU32(Instr.getMemoryOffset()); unlikely(!Res)) { @@ -185,18 +346,7 @@ Expect<void> Loader::loadInstruction(AST::Instruction &Instr) { return {}; }; - switch (Instr.getOpCode()) { - // Control instructions. - case OpCode::Unreachable: - case OpCode::Nop: - case OpCode::Return: - case OpCode::End: - case OpCode::Else: - return {}; - - case OpCode::Block: - case OpCode::Loop: - case OpCode::If: { + auto readBlockType = [this](BlockType &Dst) -> Expect<void> { auto StartOffset = FMgr.getOffset(); // Read the block return type. if (auto Res = FMgr.readS33()) { @@ -204,13 +354,13 @@ Expect<void> Loader::loadInstruction(AST::Instruction &Instr) { TypeCode TypeByte = static_cast<TypeCode>((*Res) & INT64_C(0x7F)); if (TypeByte == TypeCode::Epsilon) { // Empty case. - Instr.setEmptyBlockType(); + Dst.setEmpty(); } else { // Value type case. Seek back to the origin offset and read the // valtype. FMgr.seek(StartOffset); if (auto TypeRes = loadValType(ASTNodeAttr::Instruction)) { - Instr.setBlockType(*TypeRes); + Dst.setData(*TypeRes); } else { // The AST node information is handled. return Unexpect(TypeRes); @@ -223,30 +373,110 @@ Expect<void> Loader::loadInstruction(AST::Instruction &Instr) { Proposal::MultiValue, FMgr.getLastOffset(), ASTNodeAttr::Instruction); } - Instr.setBlockType(static_cast<uint32_t>(*Res)); + Dst.setData(static_cast<uint32_t>(*Res)); } } else { return logLoadError(Res.error(), FMgr.getLastOffset(), ASTNodeAttr::Instruction); } return {}; + }; + + switch (Instr.getOpCode()) { + // Control instructions. + case OpCode::Unreachable: + case OpCode::Nop: + case OpCode::Return: + case OpCode::Throw_ref: + case OpCode::End: + case OpCode::Else: + // LEGACY-EH: remove the `Catch_all` case after deprecating legacy EH. + case OpCode::Catch_all: + return {}; + + case OpCode::Block: + case OpCode::Loop: + case OpCode::If: + return readBlockType(Instr.getBlockType()); + + case OpCode::Try_table: { + Instr.setTryCatch(); + // Read the result type. + if (auto Res = readBlockType(Instr.getTryCatch().ResType); !Res) { + return Unexpect(Res); + } + uint32_t VecCnt = 0; + // Read the vector of catch. + if (auto Res = loadVecCnt()) { + VecCnt = *Res; + } else { + return logLoadError(Res.error(), FMgr.getLastOffset(), + ASTNodeAttr::Instruction); + } + Instr.getTryCatch().Catch.resize(VecCnt); + for (uint32_t I = 0; I < VecCnt; ++I) { + auto &Desc = Instr.getTryCatch().Catch[I]; + // Read the catch flag. + if (auto Res = FMgr.readByte()) { + // LEGACY-EH: remove this flag after deprecating legacy EH. + Desc.IsLegacy = false; + Desc.IsRef = (*Res & 0x01U) ? true : false; + Desc.IsAll = (*Res & 0x02U) ? true : false; + } else { + return logLoadError(Res.error(), FMgr.getLastOffset(), + ASTNodeAttr::Instruction); + } + if (!Desc.IsAll) { + // Read the tag index. + if (auto Res = readU32(Desc.TagIndex); !Res) { + return Unexpect(Res); + } + } + // Read the label index. + if (auto Res = readU32(Desc.LabelIndex); !Res) { + return Unexpect(Res); + } + } + return {}; } + // LEGACY-EH: remove the `Try` case after deprecating legacy EH. + case OpCode::Try: + Instr.setTryCatch(); + return readBlockType(Instr.getTryCatch().ResType); + + // LEGACY-EH: remove the `Catch` case after deprecating legacy EH. + case OpCode::Catch: + return readU32(Instr.getCatchLegacy().TagIndex); + + case OpCode::Throw: + return readU32(Instr.getTargetIndex()); + + // LEGACY-EH: remove the `Rethrow` case after deprecating legacy EH. + case OpCode::Rethrow: + spdlog::error(ErrCode::Value::IllegalOpCode); + spdlog::error(" Deprecated `rethrow` instruction."); + return Unexpect(ErrCode::Value::IllegalOpCode); + case OpCode::Br: case OpCode::Br_if: case OpCode::Br_on_null: case OpCode::Br_on_non_null: return readU32(Instr.getJump().TargetIndex); + // LEGACY-EH: remove the `Delegate` case after deprecating legacy EH. + case OpCode::Delegate: + spdlog::error(ErrCode::Value::IllegalOpCode); + spdlog::error(" Deprecated `delegate` instruction."); + return Unexpect(ErrCode::Value::IllegalOpCode); + case OpCode::Br_table: { uint32_t VecCnt = 0; // Read the vector of labels. - if (auto Res = readU32(VecCnt); unlikely(!Res)) { - return Unexpect(Res); - } - if (VecCnt / 2 > FMgr.getRemainSize()) { - // Too many label for Br_table. - return logLoadError(ErrCode::Value::IntegerTooLong, FMgr.getLastOffset(), + if (auto Res = loadVecCnt()) { + VecCnt = *Res; + } else { + return logLoadError(Res.error(), FMgr.getLastOffset(), ASTNodeAttr::Instruction); } Instr.setLabelListSize(VecCnt + 1); @@ -288,6 +518,8 @@ Expect<void> Loader::loadInstruction(AST::Instruction &Instr) { // Reference Instructions. case OpCode::Ref__null: + case OpCode::Ref__test_null: + case OpCode::Ref__cast_null: if (auto Res = loadHeapType(TypeCode::RefNull, ASTNodeAttr::Instruction)) { Instr.setValType(*Res); } else { @@ -295,11 +527,85 @@ Expect<void> Loader::loadInstruction(AST::Instruction &Instr) { return Unexpect(Res); } return {}; + case OpCode::Ref__test: + case OpCode::Ref__cast: + if (auto Res = loadHeapType(TypeCode::Ref, ASTNodeAttr::Instruction)) { + Instr.setValType(*Res); + } else { + // The AST node information is handled. + return Unexpect(Res); + } + return {}; case OpCode::Ref__is_null: + case OpCode::Ref__eq: case OpCode::Ref__as_non_null: return {}; case OpCode::Ref__func: + case OpCode::Struct__new: + case OpCode::Struct__new_default: + case OpCode::Array__new: + case OpCode::Array__new_default: + case OpCode::Array__get: + case OpCode::Array__get_s: + case OpCode::Array__get_u: + case OpCode::Array__set: + case OpCode::Array__fill: return readU32(Instr.getTargetIndex()); + case OpCode::Struct__get: + case OpCode::Struct__get_s: + case OpCode::Struct__get_u: + case OpCode::Struct__set: + case OpCode::Array__new_fixed: + case OpCode::Array__new_data: + case OpCode::Array__new_elem: + case OpCode::Array__copy: + case OpCode::Array__init_data: + case OpCode::Array__init_elem: + if (auto Res = readU32(Instr.getTargetIndex()); unlikely(!Res)) { + return Unexpect(Res); + } + return readU32(Instr.getSourceIndex()); + case OpCode::Br_on_cast: + case OpCode::Br_on_cast_fail: { + // Read the flag. + uint8_t Flag = 0U; + if (auto Res = readU8(Flag); !Res) { + return logLoadError(Res.error(), FMgr.getLastOffset(), + ASTNodeAttr::Instruction); + } + // Read the label index. + uint32_t LabelIdx = 0U; + if (auto Res = readU32(LabelIdx); !Res) { + return logLoadError(Res.error(), FMgr.getLastOffset(), + ASTNodeAttr::Instruction); + } + // Read the heap types. + Instr.setBrCast(LabelIdx); + if (auto Res = + loadHeapType(((Flag & 0x01U) ? TypeCode::RefNull : TypeCode::Ref), + ASTNodeAttr::Instruction)) { + Instr.getBrCast().RType1 = *Res; + } else { + return logLoadError(Res.error(), FMgr.getLastOffset(), + ASTNodeAttr::Instruction); + } + if (auto Res = + loadHeapType(((Flag & 0x02U) ? TypeCode::RefNull : TypeCode::Ref), + ASTNodeAttr::Instruction)) { + Instr.getBrCast().RType2 = *Res; + } else { + return logLoadError(Res.error(), FMgr.getLastOffset(), + ASTNodeAttr::Instruction); + } + return {}; + } + case OpCode::Array__len: + case OpCode::Any__convert_extern: + case OpCode::Extern__convert_any: + case OpCode::Ref__i31: + case OpCode::I31__get_s: + case OpCode::I31__get_u: + return {}; // Parametric Instructions. case OpCode::Drop: @@ -307,12 +613,11 @@ Expect<void> Loader::loadInstruction(AST::Instruction &Instr) { return {}; case OpCode::Select_t: { // Read the vector of value types. - uint32_t VecCnt; - if (auto Res = readU32(VecCnt); unlikely(!Res)) { - return Unexpect(Res); - } - if (VecCnt / 2 > FMgr.getRemainSize()) { - return logLoadError(ErrCode::Value::IntegerTooLong, FMgr.getLastOffset(), + uint32_t VecCnt = 0; + if (auto Res = loadVecCnt()) { + VecCnt = *Res; + } else { + return logLoadError(Res.error(), FMgr.getLastOffset(), ASTNodeAttr::Instruction); } Instr.setValTypeListSize(VecCnt); @@ -872,6 +1177,28 @@ Expect<void> Loader::loadInstruction(AST::Instruction &Instr) { case OpCode::F64x2__nearest: return {}; + case OpCode::I8x16__relaxed_swizzle: + case OpCode::I32x4__relaxed_trunc_f32x4_s: + case OpCode::I32x4__relaxed_trunc_f32x4_u: + case OpCode::I32x4__relaxed_trunc_f64x2_s_zero: + case OpCode::I32x4__relaxed_trunc_f64x2_u_zero: + case OpCode::F32x4__relaxed_madd: + case OpCode::F32x4__relaxed_nmadd: + case OpCode::F64x2__relaxed_madd: + case OpCode::F64x2__relaxed_nmadd: + case OpCode::I8x16__relaxed_laneselect: + case OpCode::I16x8__relaxed_laneselect: + case OpCode::I32x4__relaxed_laneselect: + case OpCode::I64x2__relaxed_laneselect: + case OpCode::F32x4__relaxed_min: + case OpCode::F32x4__relaxed_max: + case OpCode::F64x2__relaxed_min: + case OpCode::F64x2__relaxed_max: + case OpCode::I16x8__relaxed_q15mulr_s: + case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s: + case OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s: + return {}; + // Atomic Memory Instructions. case OpCode::Atomic__fence: return readCheckZero(Instr.getTargetIndex()); @@ -946,8 +1273,7 @@ Expect<void> Loader::loadInstruction(AST::Instruction &Instr) { return readMemImmediate(); default: - return logLoadError(ErrCode::Value::IllegalOpCode, Instr.getOffset(), - ASTNodeAttr::Instruction); + assumingUnreachable(); } } diff --git a/lib/loader/ast/module.cpp b/lib/loader/ast/module.cpp index 2597b105dbb1..adcc5e287583 100644 --- a/lib/loader/ast/module.cpp +++ b/lib/loader/ast/module.cpp @@ -1,7 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC +#include "loader/aot_section.h" #include "loader/loader.h" +#include "loader/shared_library.h" #include <bitset> #include <cstddef> @@ -21,7 +23,7 @@ Expect<void> Loader::loadModuleInBound(AST::Module &Mod, // Variables to record the loaded section types. HasDataSection = false; - std::bitset<0x0DU> Secs; + std::bitset<0x0EU> Secs; uint64_t Offset = FMgr.getOffset(); @@ -147,6 +149,19 @@ Expect<void> Loader::loadModuleInBound(AST::Module &Mod, HasDataSection = true; Secs.set(NewSectionId); break; + case 0x0D: + // This section is for ExceptionHandling proposal. + if (!Conf.hasProposal(Proposal::ExceptionHandling)) { + return logNeedProposal(ErrCode::Value::MalformedSection, + Proposal::ExceptionHandling, + FMgr.getLastOffset(), ASTNodeAttr::Module); + } + if (auto Res = loadSection(Mod.getTagSection()); !Res) { + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); + return Unexpect(Res); + } + Secs.set(NewSectionId); + break; default: return logLoadError(ErrCode::Value::MalformedSection, FMgr.getLastOffset(), ASTNodeAttr::Module); @@ -155,6 +170,9 @@ Expect<void> Loader::loadModuleInBound(AST::Module &Mod, Offset = FMgr.getOffset(); } + setTagFunctionType(Mod.getTagSection(), Mod.getImportSection(), + Mod.getTypeSection()); + // Verify the function section and code section are matched. if (Mod.getFunctionSection().getContent().size() != Mod.getCodeSection().getContent().size()) { @@ -181,16 +199,21 @@ Expect<void> Loader::loadModule(AST::Module &Mod) { return loadModuleInBound(Mod, std::nullopt); } -// Load compiled function from loadable manager. See "include/loader/loader.h". -Expect<void> Loader::loadCompiled(AST::Module &Mod) { - auto &FuncTypes = Mod.getTypeSection().getContent(); - for (size_t I = 0; I < FuncTypes.size(); ++I) { - const std::string Name = "t" + std::to_string(I); - if (auto Symbol = - LMgr.getSymbol<AST::FunctionType::Wrapper>(Name.c_str())) { - FuncTypes[I].setSymbol(std::move(Symbol)); +// Setup symbols from loaded binary. See "include/loader/loader.h". +Expect<void> Loader::loadExecutable(AST::Module &Mod, + std::shared_ptr<Executable> Exec) { + spdlog::info("load executable start"); + auto &SubTypes = Mod.getTypeSection().getContent(); + for (auto &SubType : SubTypes) { + if (unlikely(!SubType.getCompositeType().isFunc())) { + // TODO: GC - AOT: implement other composite types. + spdlog::error(ErrCode::Value::MalformedSection); + spdlog::error(" Currently AOT not support GC proposal yet."); + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); + return Unexpect(ErrCode::Value::MalformedSection); } } + size_t Offset = 0; for (const auto &ImpDesc : Mod.getImportSection().getContent()) { if (ImpDesc.getExternalType() == ExternalType::Function) { @@ -198,69 +221,72 @@ Expect<void> Loader::loadCompiled(AST::Module &Mod) { } } auto &CodeSegs = Mod.getCodeSection().getContent(); - for (size_t I = 0; I < CodeSegs.size(); ++I) { - const std::string Name = "f" + std::to_string(I + Offset); - if (auto Symbol = LMgr.getSymbol<void>(Name.c_str())) { - CodeSegs[I].setSymbol(std::move(Symbol)); - } - } - return {}; -} - -Expect<void> Loader::loadUniversalWASM(AST::Module &Mod) { - bool FallBackInterpreter = false; - auto Library = std::make_shared<SharedLibrary>(); - if (auto Res = Library->load(Mod.getAOTSection()); unlikely(!Res)) { - spdlog::error(" AOT section -- library load failed:{} , use " - "interpreter mode instead.", - Res.error()); - FallBackInterpreter = true; - } // Check the symbols. - auto FuncTypeSymbols = Library->getTypes<AST::FunctionType::Wrapper>(); - auto CodeSymbols = Library->getCodes<void>(); - auto IntrinsicsSymbol = - Library->getIntrinsics<const AST::Module::IntrinsicsTable *>(); - auto &FuncTypes = Mod.getTypeSection().getContent(); - auto &CodeSegs = Mod.getCodeSection().getContent(); - if (!FallBackInterpreter && - unlikely(FuncTypeSymbols.size() != FuncTypes.size())) { + auto FuncTypeSymbols = Exec->getTypes(SubTypes.size()); + auto CodeSymbols = Exec->getCodes(Offset, CodeSegs.size()); + auto IntrinsicsSymbol = Exec->getIntrinsics(); + if (unlikely(FuncTypeSymbols.size() != SubTypes.size())) { spdlog::error(" AOT section -- number of types not matching:{} {}, " "use interpreter mode instead.", - FuncTypeSymbols.size(), FuncTypes.size()); - FallBackInterpreter = true; + FuncTypeSymbols.size(), SubTypes.size()); + return Unexpect(ErrCode::Value::IllegalGrammar); } - if (!FallBackInterpreter && unlikely(CodeSymbols.size() != CodeSegs.size())) { + if (unlikely(CodeSymbols.size() != CodeSegs.size())) { spdlog::error(" AOT section -- number of codes not matching:{} {}, " "use interpreter mode instead.", CodeSymbols.size(), CodeSegs.size()); - FallBackInterpreter = true; + return Unexpect(ErrCode::Value::IllegalGrammar); } - if (!FallBackInterpreter && unlikely(!IntrinsicsSymbol)) { + if (unlikely(!IntrinsicsSymbol)) { spdlog::error(" AOT section -- intrinsics table symbol not found, use " "interpreter mode instead."); - FallBackInterpreter = true; + return Unexpect(ErrCode::Value::IllegalGrammar); } // Set the symbols into the module. - if (!FallBackInterpreter) { - for (size_t I = 0; I < FuncTypes.size(); ++I) { - FuncTypes[I].setSymbol(std::move(FuncTypeSymbols[I])); - } - for (size_t I = 0; I < CodeSegs.size(); ++I) { - CodeSegs[I].setSymbol(std::move(CodeSymbols[I])); + for (size_t I = 0; I < SubTypes.size(); ++I) { + SubTypes[I].getCompositeType().getFuncType().setSymbol( + std::move(FuncTypeSymbols[I])); + } + for (size_t I = 0; I < CodeSegs.size(); ++I) { + CodeSegs[I].setSymbol(std::move(CodeSymbols[I])); + } + Mod.setSymbol(std::move(IntrinsicsSymbol)); + if (!Conf.getRuntimeConfigure().isForceInterpreter()) { + // If the configure is set to force interpreter mode, not to set the + // symbol. + if (auto &Symbol = Mod.getSymbol()) { + *Symbol = IntrinsicsTable; } - Mod.setSymbol(std::move(IntrinsicsSymbol)); - } else { - // Fallback to the interpreter mode case: Re-read the code section. - WASMType = InputType::WASM; - FMgr.seek(Mod.getCodeSection().getStartOffset()); - if (auto Res = loadSection(Mod.getCodeSection()); !Res) { - spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); - return Unexpect(Res); + } + spdlog::info("load executable end"); + + return {}; +} + +Expect<void> Loader::loadUniversalWASM(AST::Module &Mod) { + if (!Conf.getRuntimeConfigure().isForceInterpreter()) { + auto Exec = std::make_shared<AOTSection>(); + if (auto Res = Exec->load(Mod.getAOTSection()); unlikely(!Res)) { + spdlog::error(" AOT section -- library load failed:{} , use " + "interpreter mode instead.", + Res.error()); + } else { + if (loadExecutable(Mod, Exec)) { + return {}; + } } } + + // Fallback to the interpreter mode case: Re-read the code section. + WASMType = InputType::WASM; + FMgr.seek(Mod.getCodeSection().getStartOffset()); + if (auto Res = loadSection(Mod.getCodeSection()); !Res) { + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); + return Unexpect(Res); + } + return {}; } diff --git a/lib/loader/ast/section.cpp b/lib/loader/ast/section.cpp index a6ba7b04f83b..ad214493c291 100644 --- a/lib/loader/ast/section.cpp +++ b/lib/loader/ast/section.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" @@ -12,19 +12,6 @@ namespace WasmEdge { namespace Loader { -// Load content size. See "include/loader/loader.h". -Expect<uint32_t> Loader::loadSectionSize(ASTNodeAttr Node) { - if (auto Res = FMgr.readU32()) { - if (unlikely(FMgr.getRemainSize() < (*Res))) { - return logLoadError(ErrCode::Value::LengthOutOfBounds, - FMgr.getLastOffset(), Node); - } - return *Res; - } else { - return logLoadError(Res.error(), FMgr.getLastOffset(), Node); - } -} - // Load content of custom section. See "include/loader/loader.h". Expect<void> Loader::loadSection(AST::CustomSection &Sec) { return loadSectionContent(Sec, [this, &Sec]() -> Expect<void> { @@ -55,10 +42,57 @@ Expect<void> Loader::loadSection(AST::CustomSection &Sec) { // Load vector of type section. See "include/loader/loader.h". Expect<void> Loader::loadSection(AST::TypeSection &Sec) { - return loadSectionContent(Sec, [this, &Sec]() { - return loadSectionContentVec(Sec, [this](AST::FunctionType &FuncType) { - return loadType(FuncType); - }); + return loadSectionContent(Sec, [this, &Sec]() -> Expect<void> { + // Read the recursive type vector size. + uint32_t VecCnt = 0; + if (auto Res = loadVecCnt()) { + VecCnt = *Res; + } else { + return logLoadError(Res.error(), FMgr.getLastOffset(), + ASTNodeAttr::Sec_Type); + } + // Read the recursive types. + Sec.getContent().clear(); + uint32_t SubTypeCnt = 0; + for (uint32_t I = 0; I < VecCnt; I++) { + if (auto CodeByte = FMgr.peekByte()) { + TypeCode Code = static_cast<TypeCode>(*CodeByte); + if (Code == TypeCode::Rec) { + // Case: 0x4E vec(subtype). + FMgr.readByte(); + uint32_t RecVecCnt = 0; + if (auto Res = loadVecCnt()) { + RecVecCnt = *Res; + } else { + return logLoadError(Res.error(), FMgr.getLastOffset(), + ASTNodeAttr::Sec_Type); + } + for (uint32_t J = 0; J < RecVecCnt; ++J) { + Sec.getContent().emplace_back(); + if (auto Res = loadType(Sec.getContent().back()); unlikely(!Res)) { + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Type)); + return Unexpect(Res); + } + Sec.getContent().back().setRecursiveInfo(J, RecVecCnt); + Sec.getContent().back().setTypeIndex(SubTypeCnt); + SubTypeCnt++; + } + } else { + // Case: subtype. + Sec.getContent().emplace_back(); + Sec.getContent().back().setTypeIndex(SubTypeCnt); + SubTypeCnt++; + if (auto Res = loadType(Sec.getContent().back()); unlikely(!Res)) { + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Type)); + return Unexpect(Res); + } + } + } else { + return logLoadError(CodeByte.error(), FMgr.getLastOffset(), + ASTNodeAttr::Sec_Type); + } + } + return {}; }); } @@ -175,6 +209,13 @@ Expect<void> Loader::loadSection(AST::DataCountSection &Sec) { }); } +Expect<void> Loader::loadSection(AST::TagSection &Sec) { + return loadSectionContent(Sec, [this, &Sec]() { + return loadSectionContentVec( + Sec, [this](AST::TagType &TgType) { return loadType(TgType); }); + }); +} + Expect<void> Loader::loadSection(AST::Component::ComponentSection &Sec) { auto ResPreamble = Loader::loadPreamble(); if (!ResPreamble) { @@ -194,7 +235,7 @@ Expect<void> Loader::loadSection(AST::Component::ComponentSection &Sec) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } - Sec.getContent().push_back(NestedComp); + Sec.getContent() = NestedComp; return {}; } @@ -224,7 +265,7 @@ Expect<void> Loader::loadSection(AST::CoreModuleSection &Sec) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); return Unexpect(Res); } - Sec.getContent().push_back(CoreMod); + Sec.getContent() = CoreMod; return {}; }); } @@ -267,6 +308,12 @@ Expect<void> Loader::loadSection(AST::Component::TypeSection &Sec) { }); } +Expect<void> Loader::loadSection(AST::Component::StartSection &Sec) { + return loadSectionContent(Sec, [this, &Sec]() -> Expect<void> { + return loadStart(Sec.getContent()); + }); +} + Expect<void> Loader::loadSection(AST::Component::CanonSection &Sec) { return loadSectionContent(Sec, [this, &Sec]() { return loadSectionContentVec( diff --git a/lib/loader/ast/segment.cpp b/lib/loader/ast/segment.cpp index 47bb5d8a6606..192cc5212b31 100644 --- a/lib/loader/ast/segment.cpp +++ b/lib/loader/ast/segment.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" @@ -12,8 +12,7 @@ namespace Loader { // Load binary of TableSegment node. See "include/loader/loader.h". Expect<void> Loader::loadSegment(AST::TableSegment &TabSeg) { // Check the first byte is the reftype in table type or not. - auto StartOffset = FMgr.getOffset(); - if (auto CheckByte = FMgr.readByte()) { + if (auto CheckByte = FMgr.peekByte()) { if (*CheckByte == 0x40U) { // Table segment case is for FunctionReferences proposal. if (!Conf.hasProposal(Proposal::FunctionReferences)) { @@ -21,6 +20,7 @@ Expect<void> Loader::loadSegment(AST::TableSegment &TabSeg) { Proposal::FunctionReferences, FMgr.getLastOffset(), ASTNodeAttr::Seg_Table); } + FMgr.readByte(); // Check the second byte. if (auto Res = FMgr.readByte()) { @@ -45,8 +45,7 @@ Expect<void> Loader::loadSegment(AST::TableSegment &TabSeg) { return Unexpect(Res); } } else { - // The table type case. Seek back 1 byte and read the table type. - FMgr.seek(StartOffset); + // The table type case. if (auto Res = loadType(TabSeg.getTableType()); unlikely(!Res)) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table)); return Unexpect(Res); @@ -231,28 +230,10 @@ Expect<void> Loader::loadSegment(AST::ElementSegment &ElemSeg) { } [[fallthrough]]; case 0x04: { - uint32_t VecCnt = 0; - if (auto Res = FMgr.readU32(); unlikely(!Res)) { - return logLoadError(Res.error(), FMgr.getLastOffset(), - ASTNodeAttr::Seg_Element); - } else { - VecCnt = *Res; - if (VecCnt / 2 > FMgr.getRemainSize()) { - return logLoadError(ErrCode::Value::IntegerTooLong, - FMgr.getLastOffset(), ASTNodeAttr::Seg_Element); - } - } - ElemSeg.getInitExprs().clear(); - ElemSeg.getInitExprs().reserve(VecCnt); - for (uint32_t I = 0; I < VecCnt; ++I) { - ElemSeg.getInitExprs().emplace_back(); - if (auto Res = loadExpression(ElemSeg.getInitExprs().back()); - unlikely(!Res)) { - spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element)); - return Unexpect(Res); - } - } - break; + return loadVec<AST::ElementSegment>( + ElemSeg.getInitExprs(), [this](AST::Expression &Expr) -> Expect<void> { + return loadExpression(Expr); + }); } default: @@ -275,19 +256,14 @@ Expect<void> Loader::loadSegment(AST::CodeSegment &CodeSeg) { // Read the vector of local variable counts and types. uint32_t VecCnt = 0; - if (auto Res = FMgr.readU32()) { + if (auto Res = loadVecCnt()) { VecCnt = *Res; - if (VecCnt / 2 > FMgr.getRemainSize()) { - return logLoadError(ErrCode::Value::IntegerTooLong, FMgr.getLastOffset(), - ASTNodeAttr::Seg_Code); - } - - CodeSeg.getLocals().clear(); - CodeSeg.getLocals().reserve(VecCnt); } else { return logLoadError(Res.error(), FMgr.getLastOffset(), - ASTNodeAttr::Seg_Code); + ASTNodeAttr::Seg_Element); } + CodeSeg.getLocals().clear(); + CodeSeg.getLocals().reserve(VecCnt); uint32_t TotalLocalCnt = 0; for (uint32_t I = 0; I < VecCnt; ++I) { uint32_t LocalCnt = 0; @@ -389,12 +365,8 @@ Expect<void> Loader::loadSegment(AST::DataSegment &DataSeg) { { // Read initialization data. uint32_t VecCnt = 0; - if (auto Res = FMgr.readU32()) { + if (auto Res = loadVecCnt()) { VecCnt = *Res; - if (VecCnt / 2 > FMgr.getRemainSize()) { - return logLoadError(ErrCode::Value::IntegerTooLong, - FMgr.getLastOffset(), ASTNodeAttr::Seg_Data); - } } else { return logLoadError(Res.error(), FMgr.getLastOffset(), ASTNodeAttr::Seg_Data); diff --git a/lib/loader/ast/type.cpp b/lib/loader/ast/type.cpp index e4ff1aef6453..24adc7cbf09e 100644 --- a/lib/loader/ast/type.cpp +++ b/lib/loader/ast/type.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" @@ -12,7 +12,11 @@ namespace Loader { Expect<ValType> Loader::loadHeapType(TypeCode TC, ASTNodeAttr From) { if (auto Res = FMgr.readS33()) { if (*Res < 0) { - // FuncRef or ExternRef case. + if (*Res < -64) { + // For checking the invalid s33 value which is larger than 1 byte. + return logLoadError(ErrCode::Value::MalformedRefType, + FMgr.getLastOffset(), From); + } TypeCode HTCode = static_cast<TypeCode>(static_cast<uint8_t>((*Res) & INT64_C(0x7F))); switch (HTCode) { @@ -29,6 +33,26 @@ Expect<ValType> Loader::loadHeapType(TypeCode TC, ASTNodeAttr From) { [[fallthrough]]; case TypeCode::FuncRef: return ValType(TC, HTCode); + case TypeCode::NullFuncRef: + case TypeCode::NullExternRef: + case TypeCode::NullRef: + case TypeCode::AnyRef: + case TypeCode::EqRef: + case TypeCode::I31Ref: + case TypeCode::StructRef: + case TypeCode::ArrayRef: + if (!Conf.hasProposal(Proposal::GC)) { + return logNeedProposal(ErrCode::Value::MalformedRefType, Proposal::GC, + FMgr.getLastOffset(), From); + } + return ValType(TC, HTCode); + case TypeCode::ExnRef: + if (!Conf.hasProposal(Proposal::ExceptionHandling)) { + return logNeedProposal(ErrCode::Value::MalformedValType, + Proposal::ExceptionHandling, + FMgr.getLastOffset(), From); + } + return ValType(TC, HTCode); default: return logLoadError(ErrCode::Value::MalformedRefType, FMgr.getLastOffset(), From); @@ -66,6 +90,19 @@ Expect<ValType> Loader::loadRefType(ASTNodeAttr From) { // The FuncRef (0x70) is always allowed in the RefType even if the // reference-types proposal not enabled. return ValType(Code); + case TypeCode::NullFuncRef: + case TypeCode::NullExternRef: + case TypeCode::NullRef: + case TypeCode::AnyRef: + case TypeCode::EqRef: + case TypeCode::I31Ref: + case TypeCode::StructRef: + case TypeCode::ArrayRef: + if (!Conf.hasProposal(Proposal::GC)) { + return logNeedProposal(FailCode, Proposal::GC, FMgr.getLastOffset(), + From); + } + return ValType(Code); case TypeCode::Ref: case TypeCode::RefNull: { if (!Conf.hasProposal(Proposal::FunctionReferences)) { @@ -83,7 +120,7 @@ Expect<ValType> Loader::loadRefType(ASTNodeAttr From) { } // Load binary and decode ValType. See "include/loader/loader.h". -Expect<ValType> Loader::loadValType(ASTNodeAttr From) { +Expect<ValType> Loader::loadValType(ASTNodeAttr From, bool IsStorageType) { if (auto Res = FMgr.readByte()) { TypeCode Code = static_cast<TypeCode>(*Res); switch (Code) { @@ -98,6 +135,16 @@ Expect<ValType> Loader::loadValType(ASTNodeAttr From) { case TypeCode::F32: case TypeCode::F64: return ValType(Code); + case TypeCode::I8: + case TypeCode::I16: + if (!IsStorageType) { + break; + } + if (!Conf.hasProposal(Proposal::GC)) { + return logNeedProposal(ErrCode::Value::MalformedValType, Proposal::GC, + FMgr.getLastOffset(), From); + } + return ValType(Code); case TypeCode::FuncRef: if (!Conf.hasProposal(Proposal::ReferenceTypes) && !Conf.hasProposal(Proposal::BulkMemoryOperations)) { @@ -113,6 +160,26 @@ Expect<ValType> Loader::loadValType(ASTNodeAttr From) { From); } return ValType(Code); + case TypeCode::NullFuncRef: + case TypeCode::NullExternRef: + case TypeCode::NullRef: + case TypeCode::AnyRef: + case TypeCode::EqRef: + case TypeCode::I31Ref: + case TypeCode::StructRef: + case TypeCode::ArrayRef: + if (!Conf.hasProposal(Proposal::GC)) { + return logNeedProposal(ErrCode::Value::MalformedValType, Proposal::GC, + FMgr.getLastOffset(), From); + } + return ValType(Code); + case TypeCode::ExnRef: + if (!Conf.hasProposal(Proposal::ExceptionHandling)) { + return logNeedProposal(ErrCode::Value::MalformedValType, + Proposal::ExceptionHandling, + FMgr.getLastOffset(), From); + } + return ValType(Code); case TypeCode::Ref: case TypeCode::RefNull: if (!Conf.hasProposal(Proposal::FunctionReferences)) { @@ -122,14 +189,89 @@ Expect<ValType> Loader::loadValType(ASTNodeAttr From) { } return loadHeapType(Code, From); default: - return logLoadError(ErrCode::Value::MalformedValType, - FMgr.getLastOffset(), From); + break; + } + } else { + return logLoadError(Res.error(), FMgr.getLastOffset(), From); + } + return logLoadError(ErrCode::Value::MalformedValType, FMgr.getLastOffset(), + From); +} + +Expect<ValMut> Loader::loadMutability(ASTNodeAttr From) { + if (auto Res = FMgr.readByte()) { + switch (static_cast<ValMut>(*Res)) { + case ValMut::Const: + case ValMut::Var: + return static_cast<ValMut>(*Res); + default: + return logLoadError(ErrCode::Value::InvalidMut, FMgr.getLastOffset(), + From); } } else { return logLoadError(Res.error(), FMgr.getLastOffset(), From); } } +Expect<void> Loader::loadFieldType(AST::FieldType &FType) { + if (auto Res = loadValType(ASTNodeAttr::Type_Rec, true)) { + FType.setStorageType(*Res); + } else { + // The error code logging is handled. + return Unexpect(Res); + } + if (auto Res = loadMutability(ASTNodeAttr::Type_Rec)) { + FType.setValMut(*Res); + } else { + // The error code logging is handled. + return Unexpect(Res); + } + return {}; +} + +Expect<void> Loader::loadCompositeType(AST::CompositeType &CType) { + if (auto CodeByte = FMgr.readByte()) { + switch (static_cast<TypeCode>(*CodeByte)) { + case TypeCode::Array: { + AST::FieldType FType; + if (auto Res = loadFieldType(FType); unlikely(!Res)) { + return Unexpect(Res); + } + CType.setArrayType(std::move(FType)); + return {}; + } + case TypeCode::Struct: { + std::vector<AST::FieldType> FList; + if (auto Res = loadVec<AST::SubType>( + FList, + [this](AST::FieldType &FType) -> Expect<void> { + // The error code logging is handled. + return loadFieldType(FType); + }); + !Res) { + return Unexpect(Res); + } + CType.setStructType(std::move(FList)); + return {}; + } + case TypeCode::Func: { + AST::FunctionType FuncType; + if (auto Res = loadType(FuncType); unlikely(!Res)) { + return Unexpect(Res); + } + CType.setFunctionType(std::move(FuncType)); + return {}; + } + default: + return logLoadError(ErrCode::Value::IntegerTooLong, FMgr.getLastOffset(), + ASTNodeAttr::Type_Rec); + } + } else { + return logLoadError(CodeByte.error(), FMgr.getLastOffset(), + ASTNodeAttr::Type_Rec); + } +} + // Load binary to construct Limit node. See "include/loader/loader.h". Expect<void> Loader::loadLimit(AST::Limit &Lim) { // Read limit. @@ -186,69 +328,77 @@ Expect<void> Loader::loadLimit(AST::Limit &Lim) { return {}; } -// Load binary to construct FunctionType node. See "include/loader/loader.h". -Expect<void> Loader::loadType(AST::FunctionType &FuncType) { - uint32_t VecCnt = 0; - - // Read type of Func (0x60). - if (auto Res = FMgr.readByte()) { - if (static_cast<TypeCode>(*Res) != TypeCode::Func) { - return logLoadError(ErrCode::Value::IntegerTooLong, FMgr.getLastOffset(), - ASTNodeAttr::Type_Function); +// Load binary to construct SubType node. See "include/loader/loader.h". +Expect<void> Loader::loadType(AST::SubType &SType) { + if (auto CodeByte = FMgr.peekByte()) { + switch (static_cast<TypeCode>(*CodeByte)) { + default: + // Case: comptype. + SType.setFinal(true); + return loadCompositeType(SType.getCompositeType()); + case TypeCode::Sub: + // Case: 0x50 vec(typeidx) comptype. + SType.setFinal(false); + break; + case TypeCode::SubFinal: + // Case: 0x4F vec(typeidx) comptype. + SType.setFinal(true); + break; } - } else { - return logLoadError(Res.error(), FMgr.getLastOffset(), - ASTNodeAttr::Type_Function); - } - - // Read vector of parameter types. - if (auto Res = FMgr.readU32()) { - VecCnt = *Res; - if (VecCnt / 2 > FMgr.getRemainSize()) { - return logLoadError(ErrCode::Value::IntegerTooLong, FMgr.getLastOffset(), - ASTNodeAttr::Type_Function); + FMgr.readByte(); + if (auto Res = loadVec<AST::SubType>( + SType.getSuperTypeIndices(), + [this](uint32_t &Idx) -> Expect<void> { + if (auto Num = FMgr.readU32()) { + Idx = *Num; + } else { + return logLoadError(Num.error(), FMgr.getLastOffset(), + ASTNodeAttr::Type_Sub); + } + return {}; + }); + !Res) { + return Unexpect(Res); } - FuncType.getParamTypes().clear(); - FuncType.getParamTypes().reserve(VecCnt); + return loadCompositeType(SType.getCompositeType()); } else { - return logLoadError(Res.error(), FMgr.getLastOffset(), - ASTNodeAttr::Type_Function); + return logLoadError(CodeByte.error(), FMgr.getLastOffset(), + ASTNodeAttr::Type_Rec); } - for (uint32_t I = 0; I < VecCnt; ++I) { +} + +// Load binary to construct FunctionType node. See "include/loader/loader.h". +Expect<void> Loader::loadType(AST::FunctionType &FuncType) { + // Read type of Func (0x60). Moved into the composite type. + auto LoadValType = [this](ValType &VT) -> Expect<void> { if (auto Res = loadValType(ASTNodeAttr::Type_Function)) { - FuncType.getParamTypes().push_back(*Res); + VT = *Res; } else { - // The AST node information is handled. + // The error code logging is handled. return Unexpect(Res); } + return {}; + }; + // Read vector of parameter types. + if (auto Res = + loadVec<AST::FunctionType>(FuncType.getParamTypes(), LoadValType); + !Res) { + return Unexpect(Res); } // Read vector of result types. - if (auto Res = FMgr.readU32()) { - VecCnt = *Res; - if (VecCnt / 2 > FMgr.getRemainSize()) { - return logLoadError(ErrCode::Value::IntegerTooLong, FMgr.getLastOffset(), - ASTNodeAttr::Type_Function); - } - FuncType.getReturnTypes().clear(); - FuncType.getReturnTypes().reserve(VecCnt); - } else { - return logLoadError(Res.error(), FMgr.getLastOffset(), - ASTNodeAttr::Type_Function); + if (auto Res = + loadVec<AST::FunctionType>(FuncType.getReturnTypes(), LoadValType); + !Res) { + return Unexpect(Res); } - if (unlikely(!Conf.hasProposal(Proposal::MultiValue)) && VecCnt > 1) { + + if (unlikely(!Conf.hasProposal(Proposal::MultiValue)) && + FuncType.getReturnTypes().size() > 1) { return logNeedProposal(ErrCode::Value::MalformedValType, Proposal::MultiValue, FMgr.getLastOffset(), ASTNodeAttr::Type_Function); } - for (uint32_t I = 0; I < VecCnt; ++I) { - if (auto Res = loadValType(ASTNodeAttr::Type_Function)) { - FuncType.getReturnTypes().push_back(*Res); - } else { - // The AST node information is handled. - return Unexpect(Res); - } - } return {}; } @@ -291,19 +441,36 @@ Expect<void> Loader::loadType(AST::GlobalType &GlobType) { } // Read mutability. + if (auto Res = loadMutability(ASTNodeAttr::Type_Global)) { + GlobType.setValMut(*Res); + } else { + // The AST node information is handled. + return Unexpect(Res); + } + return {}; +} + +// Load binary to construct Tag node. See "include/loader/loader.h". +Expect<void> Loader::loadType(AST::TagType &TgType) { if (auto Res = FMgr.readByte()) { - GlobType.setValMut(static_cast<ValMut>(*Res)); - switch (GlobType.getValMut()) { - case ValMut::Const: - case ValMut::Var: - break; - default: - return logLoadError(ErrCode::Value::InvalidMut, FMgr.getLastOffset(), - ASTNodeAttr::Type_Global); + // The preserved byte for future extension possibility for tag + // It supports only 0x00 currently, which is for exception handling. + if (unlikely(*Res != 0x00)) { + spdlog::error(ErrCode::Value::ExpectedZeroByte); + spdlog::error(ErrInfo::InfoLoading(FMgr.getLastOffset())); + return Unexpect(ErrCode::Value::ExpectedZeroByte); } } else { - return logLoadError(Res.error(), FMgr.getLastOffset(), - ASTNodeAttr::Type_Global); + spdlog::error(Res.error()); + spdlog::error(ErrInfo::InfoLoading(FMgr.getLastOffset())); + return Unexpect(Res); + } + if (auto Res = FMgr.readU32()) { + TgType.setTypeIdx(*Res); + } else { + spdlog::error(Res.error()); + spdlog::error(ErrInfo::InfoLoading(FMgr.getLastOffset())); + return Unexpect(Res); } return {}; } diff --git a/lib/loader/filemgr.cpp b/lib/loader/filemgr.cpp index 775d962f71e6..a6e2b95e9228 100644 --- a/lib/loader/filemgr.cpp +++ b/lib/loader/filemgr.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/filemgr.h" @@ -49,6 +49,11 @@ Expect<void> FileMgr::setCode(Span<const Byte> CodeData) { // Set code data. See "include/loader/filemgr.h". Expect<void> FileMgr::setCode(std::vector<Byte> CodeData) { reset(); + // Tell GCC 14 that DataHolder has no data. + // Fix the false positive warning, + // which is reported by GCC 14 with `maybe-uninitialized` + assuming(!DataHolder); + DataHolder.emplace(std::move(CodeData)); Data = DataHolder->data(); Size = DataHolder->size(); @@ -370,6 +375,16 @@ Expect<std::string> FileMgr::readName() { return Str; } +// Peek one byte. See "include/loader/filemgr.h". +Expect<Byte> FileMgr::peekByte() { + if (auto Res = readByte()) { + Pos--; + return Res; + } else { + return Unexpect(Res); + } +} + // Get the file header type. See "include/loader/filemgr.h". FileMgr::FileHeader FileMgr::getHeaderType() { if (Size >= 4) { diff --git a/lib/loader/ldmgr.cpp b/lib/loader/ldmgr.cpp deleted file mode 100644 index 85f817f33748..000000000000 --- a/lib/loader/ldmgr.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC - -#include "loader/ldmgr.h" - -#include "common/log.h" -#include <cstdint> - -namespace WasmEdge { - -// Set path to loadable manager. See "include/loader/ldmgr.h". -Expect<void> LDMgr::setPath(const std::filesystem::path &FilePath) { - Library = std::make_shared<Loader::SharedLibrary>(); - if (auto Res = Library->load(FilePath); unlikely(!Res)) { - return Unexpect(Res); - } - - const auto IntrinsicsTable = getSymbol<const void *>("intrinsics"); - if (IntrinsicsTable) { - if (unlikely(!Intrinsics)) { - spdlog::error(ErrCode::Value::IntrinsicsTableNotFound); - return Unexpect(ErrCode::Value::IntrinsicsTableNotFound); - } - *IntrinsicsTable = Intrinsics; - } - return {}; -} - -Expect<std::vector<Byte>> LDMgr::getWasm() { - const auto Size = getSymbol<uint32_t>("wasm.size"); - if (unlikely(!Size)) { - spdlog::error(ErrCode::Value::IllegalGrammar); - return Unexpect(ErrCode::Value::IllegalGrammar); - } - const auto Code = getSymbol<uint8_t>("wasm.code"); - if (unlikely(!Code)) { - spdlog::error(ErrCode::Value::IllegalGrammar); - return Unexpect(ErrCode::Value::IllegalGrammar); - } - - return std::vector<Byte>(Code.get(), Code.get() + *Size); -} - -Expect<uint32_t> LDMgr::getVersion() { - const auto Version = getSymbol<uint32_t>("version"); - if (unlikely(!Version)) { - spdlog::error(ErrCode::Value::IllegalGrammar); - return Unexpect(ErrCode::Value::IllegalGrammar); - } - return *Version; -} - -} // namespace WasmEdge diff --git a/lib/loader/loader.cpp b/lib/loader/loader.cpp index 15963dd10583..ebeb92bfcafe 100644 --- a/lib/loader/loader.cpp +++ b/lib/loader/loader.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/loader.h" @@ -82,11 +82,12 @@ Loader::parseWasmUnit(const std::filesystem::path &FilePath) { // AOT compiled shared-library-WASM cases. Use ldmgr to load the module. WASMType = InputType::SharedLibrary; FMgr.reset(); - if (auto Res = LMgr.setPath(FilePath); !Res) { + std::shared_ptr<SharedLibrary> Library = std::make_shared<SharedLibrary>(); + if (auto Res = Library->load(FilePath); !Res) { spdlog::error(ErrInfo::InfoFile(FilePath)); return Unexpect(Res); } - if (auto Res = LMgr.getVersion()) { + if (auto Res = Library->getVersion()) { if (*Res != AOT::kBinaryVersion) { spdlog::error(ErrInfo::InfoMismatch(AOT::kBinaryVersion, *Res)); spdlog::error(ErrInfo::InfoFile(FilePath)); @@ -98,7 +99,7 @@ Loader::parseWasmUnit(const std::filesystem::path &FilePath) { } std::unique_ptr<AST::Module> Mod; - if (auto Code = LMgr.getWasm()) { + if (auto Code = Library->getWasm()) { // Set the binary and load module. // Not to use parseModule() here to keep the `WASMType` value. if (auto Res = FMgr.setCode(*Code); !Res) { @@ -120,7 +121,7 @@ Loader::parseWasmUnit(const std::filesystem::path &FilePath) { if (!Conf.getRuntimeConfigure().isForceInterpreter()) { // If the configure is set to force interpreter mode, not to load the AOT // related data. - if (auto Res = loadCompiled(*Mod); unlikely(!Res)) { + if (auto Res = loadExecutable(*Mod, Library); unlikely(!Res)) { spdlog::error(ErrInfo::InfoFile(FilePath)); return Unexpect(Res); } @@ -168,6 +169,7 @@ Loader::parseWasmUnit(Span<const uint8_t> Code) { case FileMgr::FileHeader::DLL: case FileMgr::FileHeader::MachO_32: case FileMgr::FileHeader::MachO_64: + spdlog::error("Might an invalid wasm file"); spdlog::error(ErrCode::Value::MalformedMagic); spdlog::error( " The AOT compiled WASM shared library is not supported for loading " @@ -213,5 +215,29 @@ Expect<std::vector<Byte>> Loader::serializeModule(const AST::Module &Mod) { return Ser.serializeModule(Mod); } +// Helper function to set the function type for tag. +void Loader::setTagFunctionType(AST::TagSection &TagSec, + AST::ImportSection &ImportSec, + AST::TypeSection &TypeSec) { + auto &TypeVec = TypeSec.getContent(); + for (auto &TgType : TagSec.getContent()) { + auto TypeIdx = TgType.getTypeIdx(); + // Invalid type index would be checked during validation. + if (TypeIdx < TypeVec.size()) { + TgType.setDefType(&TypeVec[TypeIdx]); + } + } + for (auto &Desc : ImportSec.getContent()) { + if (Desc.getExternalType() == ExternalType::Tag) { + auto &TgType = Desc.getExternalTagType(); + auto TypeIdx = TgType.getTypeIdx(); + // Invalid type index would be checked during validation. + if (TypeIdx < TypeVec.size()) { + TgType.setDefType(&TypeVec[TypeIdx]); + } + } + } +} + } // namespace Loader } // namespace WasmEdge diff --git a/lib/loader/serialize/serial_description.cpp b/lib/loader/serialize/serial_description.cpp index e52358986c93..a4b68a3e20dc 100644 --- a/lib/loader/serialize/serial_description.cpp +++ b/lib/loader/serialize/serial_description.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" diff --git a/lib/loader/serialize/serial_expression.cpp b/lib/loader/serialize/serial_expression.cpp index ea3bb91f00ac..1c507f7d1b8c 100644 --- a/lib/loader/serialize/serial_expression.cpp +++ b/lib/loader/serialize/serial_expression.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" diff --git a/lib/loader/serialize/serial_instruction.cpp b/lib/loader/serialize/serial_instruction.cpp index 5be7b130bd8a..1d7d2fe74d37 100644 --- a/lib/loader/serialize/serial_instruction.cpp +++ b/lib/loader/serialize/serial_instruction.cpp @@ -1,20 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" namespace WasmEdge { namespace Loader { -namespace { -void serializeOpCode(OpCode Code, std::vector<uint8_t> &OutVec) { - if (static_cast<uint16_t>(Code) >= 0x100U) { - OutVec.push_back(static_cast<uint16_t>(Code) >> 8); - } - OutVec.push_back(static_cast<uint16_t>(Code) & 0xFFU); -} -} // namespace - // Serialize instruction. See "include/loader/serialize.h". Expect<void> Serializer::serializeInstruction(const AST::Instruction &Instr, @@ -40,9 +31,6 @@ Serializer::serializeInstruction(const AST::Instruction &Instr, return {}; }; - // Instruction: OpCode + immediate. - serializeOpCode(Instr.getOpCode(), OutVec); - // Check with proposals. if (auto Res = Conf.isInstrNeedProposal(Instr.getOpCode()); unlikely(Res.has_value())) { @@ -50,6 +38,45 @@ Serializer::serializeInstruction(const AST::Instruction &Instr, ASTNodeAttr::Instruction); } + // Serialize OpCode. + switch (Instr.getOpCode()) { +#define UseOpCode +#define Line(NAME, STRING, PREFIX) \ + case OpCode::NAME: \ + OutVec.push_back(static_cast<uint8_t>(PREFIX)); \ + break; +#define Line_FB(NAME, STRING, PREFIX, EXTEND) \ + case OpCode::NAME: \ + OutVec.push_back(static_cast<uint8_t>(PREFIX)); \ + serializeU32(EXTEND, OutVec); \ + break; +#define Line_FC(NAME, STRING, PREFIX, EXTEND) \ + case OpCode::NAME: \ + OutVec.push_back(static_cast<uint8_t>(PREFIX)); \ + serializeU32(EXTEND, OutVec); \ + break; +#define Line_FD(NAME, STRING, PREFIX, EXTEND) \ + case OpCode::NAME: \ + OutVec.push_back(static_cast<uint8_t>(PREFIX)); \ + serializeU32(EXTEND, OutVec); \ + break; +#define Line_FE(NAME, STRING, PREFIX, EXTEND) \ + case OpCode::NAME: \ + OutVec.push_back(static_cast<uint8_t>(PREFIX)); \ + serializeU32(EXTEND, OutVec); \ + break; +#include "common/enum.inc" +#undef Line +#undef Line_FB +#undef Line_FC +#undef Line_FD +#undef Line_FE +#undef UseOpCode + default: + assumingUnreachable(); + } + + // Serialize immediate. switch (Instr.getOpCode()) { // Control instructions. case OpCode::Unreachable: @@ -654,6 +681,28 @@ Serializer::serializeInstruction(const AST::Instruction &Instr, case OpCode::F64x2__nearest: return {}; + case OpCode::I8x16__relaxed_swizzle: + case OpCode::I32x4__relaxed_trunc_f32x4_s: + case OpCode::I32x4__relaxed_trunc_f32x4_u: + case OpCode::I32x4__relaxed_trunc_f64x2_s_zero: + case OpCode::I32x4__relaxed_trunc_f64x2_u_zero: + case OpCode::F32x4__relaxed_madd: + case OpCode::F32x4__relaxed_nmadd: + case OpCode::F64x2__relaxed_madd: + case OpCode::F64x2__relaxed_nmadd: + case OpCode::I8x16__relaxed_laneselect: + case OpCode::I16x8__relaxed_laneselect: + case OpCode::I32x4__relaxed_laneselect: + case OpCode::I64x2__relaxed_laneselect: + case OpCode::F32x4__relaxed_min: + case OpCode::F32x4__relaxed_max: + case OpCode::F64x2__relaxed_min: + case OpCode::F64x2__relaxed_max: + case OpCode::I16x8__relaxed_q15mulr_s: + case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s: + case OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s: + return {}; + // Atomic Memory Instructions. case OpCode::Atomic__fence: return serializeCheckZero(Instr.getTargetIndex()); @@ -728,8 +777,7 @@ Serializer::serializeInstruction(const AST::Instruction &Instr, return serializeMemImmediate(); default: - return logSerializeError(ErrCode::Value::IllegalOpCode, - ASTNodeAttr::Instruction); + assumingUnreachable(); } } diff --git a/lib/loader/serialize/serial_module.cpp b/lib/loader/serialize/serial_module.cpp index 1f61e3c2670c..7d608d2cf934 100644 --- a/lib/loader/serialize/serial_module.cpp +++ b/lib/loader/serialize/serial_module.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" diff --git a/lib/loader/serialize/serial_section.cpp b/lib/loader/serialize/serial_section.cpp index d018b76e1f83..f8309a3b8494 100644 --- a/lib/loader/serialize/serial_section.cpp +++ b/lib/loader/serialize/serial_section.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" @@ -29,12 +29,43 @@ Serializer::serializeSection(const AST::CustomSection &Sec, Expect<void> Serializer::serializeSection(const AST::TypeSection &Sec, std::vector<uint8_t> &OutVec) const noexcept { - // Type section: 0x01 + size:u32 + content:vec(functype). - return serializeSectionContent( - Sec, 0x01U, OutVec, - [=](const AST::FunctionType &R, std::vector<uint8_t> &V) { - return serializeType(R, V); - }); + // Type section: 0x01 + size:u32 + content:vec(rectype). + auto STypes = Sec.getContent(); + + // record the recursive type vector size. + if (STypes.size() > 0) { + // Section ID. + OutVec.push_back(0x01U); + auto OrgSize = OutVec.size(); + uint32_t RecCnt = 0; + // Content: vec(rectype). + for (uint32_t I = 0; I < STypes.size(); I++) { + auto RecInfo = STypes[I].getRecursiveInfo(); + if (!RecInfo.has_value()) { + RecCnt++; + } else if (RecInfo->Index == 0) { + // First element of recursive type. + if (!Conf.hasProposal(Proposal::GC)) { + return logNeedProposal(ErrCode::Value::MalformedValType, Proposal::GC, + ASTNodeAttr::Sec_Type); + } + OutVec.push_back(static_cast<uint8_t>(TypeCode::Rec)); + serializeU32(RecInfo->RecTypeSize, OutVec); + RecCnt++; + } + if (auto Res = serializeType(STypes[I], OutVec); unlikely(!Res)) { + spdlog::error(ASTNodeAttr::Sec_Type); + return Unexpect(Res); + } + } + // Backward insert the recursive type vector size. + serializeU32(RecCnt, OutVec, + std::next(OutVec.begin(), static_cast<ptrdiff_t>(OrgSize))); + // Backward insert the section size. + serializeU32(static_cast<uint32_t>(OutVec.size() - OrgSize), OutVec, + std::next(OutVec.begin(), static_cast<ptrdiff_t>(OrgSize))); + } + return {}; } // Serialize import section. See "include/loader/serialize.h". @@ -175,7 +206,7 @@ Serializer::serializeSection(const AST::DataCountSection &Sec, !Conf.hasProposal(Proposal::ReferenceTypes)) { return logNeedProposal(ErrCode::Value::MalformedSection, Proposal::BulkMemoryOperations, - ASTNodeAttr::Module); + ASTNodeAttr::Sec_DataCount); } // Section ID. OutVec.push_back(0x0CU); diff --git a/lib/loader/serialize/serial_segment.cpp b/lib/loader/serialize/serial_segment.cpp index 650585b3d45d..eb1d5dbfa6ae 100644 --- a/lib/loader/serialize/serial_segment.cpp +++ b/lib/loader/serialize/serial_segment.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" diff --git a/lib/loader/serialize/serial_type.cpp b/lib/loader/serialize/serial_type.cpp index f4a75ab98189..f8356bde19a2 100644 --- a/lib/loader/serialize/serial_type.cpp +++ b/lib/loader/serialize/serial_type.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" @@ -123,13 +123,58 @@ Serializer::serializeLimit(const AST::Limit &Lim, return {}; } +// Serialize sub type. See "include/loader/serialize.h". +Expect<void> +Serializer::serializeType(const AST::SubType &SType, + std::vector<uint8_t> &OutVec) const noexcept { + // Sub type: vec(typeidx) + if (SType.getSuperTypeIndices().size() > 0) { + if (!Conf.hasProposal(Proposal::GC)) { + return logNeedProposal(ErrCode::Value::MalformedValType, Proposal::GC, + ASTNodeAttr::Type_Rec); + } + if (SType.isFinal()) { + OutVec.push_back(static_cast<uint8_t>(TypeCode::SubFinal)); + } else { + OutVec.push_back(static_cast<uint8_t>(TypeCode::Sub)); + } + serializeU32(static_cast<uint32_t>(SType.getSuperTypeIndices().size()), + OutVec); + for (const auto &Idx : SType.getSuperTypeIndices()) { + serializeU32(Idx, OutVec); + } + } + // Composite type: array | struct | func + TypeCode CTypeCode = SType.getCompositeType().getContentTypeCode(); + OutVec.push_back(static_cast<uint8_t>(CTypeCode)); + switch (CTypeCode) { + case TypeCode::Func: + if (auto Res = + serializeType(SType.getCompositeType().getFuncType(), OutVec); + unlikely(!Res)) { + return Unexpect(Res); + } + break; + case TypeCode::Array: + case TypeCode::Struct: + if (!Conf.hasProposal(Proposal::GC)) { + return logNeedProposal(ErrCode::Value::MalformedValType, Proposal::GC, + ASTNodeAttr::Type_Rec); + } + // TODO: GC - Serializer: implementation. + [[fallthrough]]; + default: + return logSerializeError(ErrCode::Value::MalformedValType, + ASTNodeAttr::Type_Rec); + } + return {}; +} + // Serialize function type. See "include/loader/serialize.h". Expect<void> Serializer::serializeType(const AST::FunctionType &Type, std::vector<uint8_t> &OutVec) const noexcept { - // Function type: 0x60 + paramtypes:vec(valtype) + returntypes:vec(valtype). - // Prefix 0x60. - OutVec.push_back(0x60U); + // Function type: paramtypes:vec(valtype) + returntypes:vec(valtype). // Param types: vec(valtype). serializeU32(static_cast<uint32_t>(Type.getParamTypes().size()), OutVec); for (auto &VType : Type.getParamTypes()) { diff --git a/lib/loader/shared_library.cpp b/lib/loader/shared_library.cpp index a868a897a40a..6632babbed93 100644 --- a/lib/loader/shared_library.cpp +++ b/lib/loader/shared_library.cpp @@ -1,10 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/shared_library.h" - -#include "common/log.h" -#include "system/allocator.h" +#include "common/spdlog.h" #include <algorithm> #include <cerrno> @@ -21,27 +19,7 @@ #error Unsupported os! #endif -namespace { -inline constexpr uint64_t roundDownPageBoundary(const uint64_t Value) { -// ARM64 Mac has a special page size -#if WASMEDGE_OS_MACOS && defined(__aarch64__) - return Value & ~UINT64_C(16383); -#else - return Value & ~UINT64_C(4095); -#endif -} -inline constexpr uint64_t roundUpPageBoundary(const uint64_t Value) { -// ARM64 Mac has a special page size -#if WASMEDGE_OS_MACOS && defined(__aarch64__) - return roundDownPageBoundary(Value + UINT64_C(16383)); -#else - return roundDownPageBoundary(Value + UINT64_C(4095)); -#endif -} -} // namespace - -namespace WasmEdge { -namespace Loader { +namespace WasmEdge::Loader { // Open so file. See "include/loader/shared_library.h". Expect<void> SharedLibrary::load(const std::filesystem::path &Path) noexcept { @@ -76,89 +54,7 @@ Expect<void> SharedLibrary::load(const std::filesystem::path &Path) noexcept { return {}; } -Expect<void> SharedLibrary::load(const AST::AOTSection &AOTSec) noexcept { - BinarySize = 0; - for (const auto &Section : AOTSec.getSections()) { - const auto Offset = std::get<1>(Section); - const auto Size = std::get<2>(Section); - BinarySize = std::max(BinarySize, Offset + Size); - } - BinarySize = roundUpPageBoundary(BinarySize); - - Binary = Allocator::allocate_chunk(BinarySize); - if (unlikely(!Binary)) { - spdlog::error(ErrCode::Value::MemoryOutOfBounds); - return Unexpect(ErrCode::Value::MemoryOutOfBounds); - } - - std::vector<std::pair<uint8_t *, uint64_t>> ExecutableRanges; - for (const auto &Section : AOTSec.getSections()) { - const auto Offset = std::get<1>(Section); - const auto Size = std::get<2>(Section); - const auto &Content = std::get<3>(Section); - if (Size > BinarySize || Offset > BinarySize || - Offset + Size > BinarySize || Content.size() > Size) { - return Unexpect(ErrCode::Value::IntegerTooLarge); - } - std::copy(Content.begin(), Content.end(), Binary + Offset); - switch (std::get<0>(Section)) { - case 1: { // Text - const auto O = roundDownPageBoundary(Offset); - const auto S = roundUpPageBoundary(Size + (Offset - O)); - ExecutableRanges.emplace_back(Binary + O, S); - break; - } - case 2: // Data - break; - case 3: // BSS - break; -#if WASMEDGE_OS_WINDOWS - case 4: // PData - PDataAddress = reinterpret_cast<void *>(Binary + Offset); - PDataSize = - static_cast<uint32_t>(Size / sizeof(winapi::RUNTIME_FUNCTION_)); - break; -#endif - default: - return Unexpect(ErrCode::Value::IntegerTooLarge); - } - } - - for (const auto &[Pointer, Size] : ExecutableRanges) { - if (!Allocator::set_chunk_executable(Pointer, Size)) { - spdlog::error(ErrCode::Value::MemoryOutOfBounds); - spdlog::error(" set_chunk_executable failed:{}", std::strerror(errno)); - return Unexpect(ErrCode::Value::MemoryOutOfBounds); - } - } - - IntrinsicsAddress = AOTSec.getIntrinsicsAddress(); - TypesAddress = AOTSec.getTypesAddress(); - CodesAddress = AOTSec.getCodesAddress(); - -#if WASMEDGE_OS_WINDOWS - if (PDataSize != 0) { - winapi::RtlAddFunctionTable( - static_cast<winapi::PRUNTIME_FUNCTION_>(PDataAddress), PDataSize, - reinterpret_cast<winapi::ULONG_PTR_>(Binary)); - } -#endif - - return {}; -} - void SharedLibrary::unload() noexcept { - if (Binary) { -#if WASMEDGE_OS_WINDOWS - if (PDataSize != 0) { - winapi::RtlDeleteFunctionTable( - static_cast<winapi::PRUNTIME_FUNCTION_>(PDataAddress)); - } -#endif - Allocator::set_chunk_readable_writable(Binary, BinarySize); - Allocator::release_chunk(Binary, BinarySize); - Binary = nullptr; - } if (Handle) { #if WASMEDGE_OS_WINDOWS winapi::FreeLibrary(Handle); @@ -180,9 +76,4 @@ void *SharedLibrary::getSymbolAddr(const char *Name) const noexcept { #endif } -uintptr_t SharedLibrary::getOffset() const noexcept { - return reinterpret_cast<uintptr_t>(Binary); -} - -} // namespace Loader -} // namespace WasmEdge +} // namespace WasmEdge::Loader diff --git a/lib/plugin/CMakeLists.txt b/lib/plugin/CMakeLists.txt index 52c1fd2d6536..8d31fcc28869 100644 --- a/lib/plugin/CMakeLists.txt +++ b/lib/plugin/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +add_subdirectory(wasi_logging) wasmedge_add_library(wasmedgePlugin plugin.cpp @@ -13,6 +15,9 @@ target_include_directories(wasmedgePlugin target_link_libraries(wasmedgePlugin PUBLIC + # BUILTIN-PLUGIN: Temporary add the wasi-logging plugin here until the new + # plugin architecture ready in 0.15.0. + wasmedgePluginWasiLogging wasmedgeCommon wasmedgeLoaderFileMgr wasmedgePO diff --git a/lib/plugin/plugin.cpp b/lib/plugin/plugin.cpp index 0dd837280324..ce17cd50564d 100644 --- a/lib/plugin/plugin.cpp +++ b/lib/plugin/plugin.cpp @@ -1,10 +1,14 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "plugin/plugin.h" #include "common/errcode.h" #include "common/version.h" #include "wasmedge/wasmedge.h" + +// BUILTIN-PLUGIN: Headers for built-in plug-ins. +#include "plugin/wasi_logging/module.h" + #include <type_traits> #include <variant> @@ -14,6 +18,33 @@ #include <unistd.h> #elif WASMEDGE_OS_WINDOWS #include "system/winapi.h" + +static bool GetFunctionModuleFileName(void *FuncPtr, + std::filesystem::path &Path) { + WasmEdge::winapi::HMODULE_ Module = nullptr; + + if (!WasmEdge::winapi::GetModuleHandleExW( + WasmEdge::winapi::GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS_ | + WasmEdge::winapi::GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT_, + reinterpret_cast<WasmEdge::winapi::LPCWSTR_>(FuncPtr), &Module)) { + return false; + } + + std::vector<wchar_t> Buffer; + WasmEdge::winapi::DWORD_ CopiedSize; + do { + Buffer.resize(Buffer.size() + WasmEdge::winapi::MAX_PATH_); + CopiedSize = WasmEdge::winapi::GetModuleFileNameW( + Module, Buffer.data(), + static_cast<WasmEdge::winapi::DWORD_>(Buffer.size())); + if (CopiedSize == 0) { + return false; + } + } while (CopiedSize >= Buffer.size()); + + Path.assign(std::wstring_view(Buffer.data(), CopiedSize)); + return true; +} #endif namespace WasmEdge { @@ -36,32 +67,6 @@ template <> struct Parser<WasmEdge_String> { namespace Plugin { namespace { -static unsigned int NiftyCounter = 0; -static std::aligned_storage_t<sizeof(std::vector<Plugin>), - alignof(std::vector<Plugin>)> - PluginRegistryStorage; -static std::aligned_storage_t< - sizeof(std::unordered_map<std::string_view, std::size_t>), - alignof(std::unordered_map<std::string_view, std::size_t>)> - PluginNameLookupStorage; - -void IncreaseNiftyCounter() noexcept { - if (NiftyCounter++ == 0) { - new (&PluginRegistryStorage) std::vector<Plugin>(); - new (&PluginNameLookupStorage) - std::unordered_map<std::string_view, std::size_t>(); - } -} - -void DecreaseNiftyCounter() noexcept { - if (--NiftyCounter == 0) { - reinterpret_cast<std::vector<Plugin> &>(PluginRegistryStorage) - .~vector<Plugin>(); - reinterpret_cast<std::unordered_map<std::string_view, std::size_t> &>( - PluginNameLookupStorage) - .~unordered_map<std::string_view, std::size_t>(); - } -} class CAPIPluginRegister { public: @@ -69,8 +74,6 @@ class CAPIPluginRegister { CAPIPluginRegister &operator=(const CAPIPluginRegister &) = delete; CAPIPluginRegister(const WasmEdge_PluginDescriptor *Desc) noexcept { - IncreaseNiftyCounter(); - ModuleDescriptions.resize(Desc->ModuleCount); for (size_t I = 0; I < ModuleDescriptions.size(); ++I) { ModuleDescriptions[I].Name = Desc->ModuleDescriptions[I].Name; @@ -167,9 +170,9 @@ class CAPIPluginRegister { } } - Plugin::registerPlugin(&Descriptor); + Result = Plugin::registerPlugin(&Descriptor); } - ~CAPIPluginRegister() noexcept { DecreaseNiftyCounter(); } + bool result() const noexcept { return Result; } private: static Runtime::Instance::ModuleInstance * @@ -213,6 +216,8 @@ class CAPIPluginRegister { static std::unordered_map<const PluginModule::ModuleDescriptor *, const WasmEdge_ModuleDescriptor *> DescriptionLookup; + + bool Result = false; }; std::unordered_map<const PluginModule::ModuleDescriptor *, const WasmEdge_ModuleDescriptor *> @@ -222,11 +227,17 @@ std::vector<std::unique_ptr<CAPIPluginRegister>> CAPIPluginRegisters; } // namespace -std::vector<Plugin> &Plugin::PluginRegistry = - reinterpret_cast<std::vector<Plugin> &>(PluginRegistryStorage); -std::unordered_map<std::string_view, std::size_t> &Plugin::PluginNameLookup = - reinterpret_cast<std::unordered_map<std::string_view, std::size_t> &>( - PluginNameLookupStorage); +std::mutex WasmEdge::Plugin::Plugin::Mutex; +std::vector<Plugin> WasmEdge::Plugin::Plugin::PluginRegistry; +std::unordered_map<std::string_view, std::size_t> + WasmEdge::Plugin::Plugin::PluginNameLookup; + +void Plugin::loadFromDefaultPaths() noexcept { + registerBuiltInPlugins(); + for (const auto &Path : Plugin::Plugin::getDefaultPluginPaths()) { + Plugin::Plugin::load(Path); + } +} std::vector<std::filesystem::path> Plugin::getDefaultPluginPaths() noexcept { using namespace std::literals::string_view_literals; @@ -285,9 +296,15 @@ std::vector<std::filesystem::path> Plugin::getDefaultPluginPaths() noexcept { return std::vector<std::filesystem::path>(); } #elif WASMEDGE_OS_WINDOWS - // FIXME: Use the `dladdr`. // Global plugin directory. - Result.push_back(std::filesystem::u8path(kGlobalPluginDir)); + if (std::filesystem::path Path; GetFunctionModuleFileName( + reinterpret_cast<void *>(Plugin::getDefaultPluginPaths), Path)) { + Result.push_back(Path.parent_path()); + } else { + spdlog::error("Failed to get the path of the current module."sv); + return std::vector<std::filesystem::path>(); + } + // Local home plugin directory. std::filesystem::path Home; if (const auto HomeEnv = ::getenv("USERPROFILE")) { @@ -322,7 +339,6 @@ WASMEDGE_EXPORT bool Plugin::load(const std::filesystem::path &Path) noexcept { auto Status = std::filesystem::status(Path, Error); if (likely(!Error)) { if (std::filesystem::is_directory(Status)) { - bool Result = false; for (const auto &Entry : std::filesystem::recursive_directory_iterator( Path, std::filesystem::directory_options::skip_permission_denied, @@ -342,32 +358,22 @@ WASMEDGE_EXPORT bool Plugin::load(const std::filesystem::path &Path) noexcept { return false; } -bool Plugin::loadFile(const std::filesystem::path &Path) noexcept { - const auto Index = PluginRegistry.size(); - - auto Lib = std::make_shared<Loader::SharedLibrary>(); - if (auto Res = Lib->load(Path); unlikely(!Res)) { +bool Plugin::registerPlugin(const PluginDescriptor *Desc) noexcept { + if (Desc->APIVersion != CurrentAPIVersion) { + spdlog::debug( + "Plugin: API version {} of plugin {} is not match to current {}."sv, + Desc->APIVersion, Desc->Name, CurrentAPIVersion); return false; } - - if (PluginRegistry.size() != Index + 1) { - // Check C interface - if (auto GetDescriptor = Lib->get<decltype(WasmEdge_Plugin_GetDescriptor)>( - "WasmEdge_Plugin_GetDescriptor"); - unlikely(!GetDescriptor)) { - return false; - } else if (const auto *Descriptor = GetDescriptor(); - unlikely(!Descriptor)) { - return false; - } else { - CAPIPluginRegisters.push_back( - std::make_unique<CAPIPluginRegister>(Descriptor)); - } + if (PluginNameLookup.find(Desc->Name) != PluginNameLookup.end()) { + spdlog::debug("Plugin: {} has already loaded."sv, Desc->Name); + return false; } - auto &Plugin = PluginRegistry.back(); - Plugin.Path = Path; - Plugin.Lib = std::move(Lib); + const auto Index = PluginRegistry.size(); + PluginRegistry.emplace_back(Desc); + PluginNameLookup.emplace(Desc->Name, Index); + return true; } @@ -380,29 +386,58 @@ void Plugin::addPluginOptions(PO::ArgumentParser &Parser) noexcept { } WASMEDGE_EXPORT const Plugin *Plugin::find(std::string_view Name) noexcept { - if (NiftyCounter != 0) { - if (auto Iter = PluginNameLookup.find(Name); - Iter != PluginNameLookup.end()) { - return std::addressof(PluginRegistry[Iter->second]); - } + if (auto Iter = PluginNameLookup.find(Name); Iter != PluginNameLookup.end()) { + return std::addressof(PluginRegistry[Iter->second]); } return nullptr; } Span<const Plugin> Plugin::plugins() noexcept { return PluginRegistry; } -WASMEDGE_EXPORT void -Plugin::registerPlugin(const PluginDescriptor *Desc) noexcept { - assuming(NiftyCounter != 0); - if (Desc->APIVersion != CurrentAPIVersion) { - return; +bool Plugin::loadFile(const std::filesystem::path &Path) noexcept { + std::unique_lock Lock(Mutex); + bool Result = false; + auto Lib = std::make_shared<Loader::SharedLibrary>(); + if (auto Res = Lib->load(Path); unlikely(!Res)) { + return false; } - const auto Index = PluginRegistry.size(); - PluginRegistry.push_back(Plugin(Desc)); - PluginNameLookup.emplace(Desc->Name, Index); + if (auto GetDescriptor = + Lib->get<Plugin::PluginDescriptor const *()>("GetDescriptor")) { + Result = Plugin::registerPlugin(GetDescriptor()); + } - return; + if (!Result) { + // Check C interface + if (auto GetDescriptor = Lib->get<decltype(WasmEdge_Plugin_GetDescriptor)>( + "WasmEdge_Plugin_GetDescriptor"); + unlikely(!GetDescriptor)) { + return false; + } else if (const auto *Descriptor = GetDescriptor(); + unlikely(!Descriptor)) { + return false; + } else { + Result = + CAPIPluginRegisters + .emplace_back(std::make_unique<CAPIPluginRegister>(Descriptor)) + ->result(); + } + } + + if (!Result) { + return false; + } + + auto &Plugin = PluginRegistry.back(); + Plugin.Path = Path; + Plugin.Lib = std::move(Lib); + return true; +} + +void Plugin::registerBuiltInPlugins() noexcept { + std::unique_lock Lock(Mutex); + // BUILTIN-PLUGIN: Register wasi-logging here. May be refactored in 0.15.0. + registerPlugin(&Host::WasiLoggingModule::PluginDescriptor); } Plugin::Plugin(const PluginDescriptor *D) noexcept : Desc(D) { @@ -412,6 +447,13 @@ Plugin::Plugin(const PluginDescriptor *D) noexcept : Desc(D) { ModuleRegistry.push_back(PluginModule(&ModuleDesc)); ModuleNameLookup.emplace(ModuleDesc.Name, Index); } + for (const auto &ComponentDesc : + Span<const PluginComponent::ComponentDescriptor>( + D->ComponentDescriptions, D->ComponentCount)) { + const auto Index = ComponentRegistry.size(); + ComponentRegistry.push_back(PluginComponent(&ComponentDesc)); + ComponentNameLookup.emplace(ComponentDesc.Name, Index); + } } WASMEDGE_EXPORT const PluginModule * @@ -422,15 +464,13 @@ Plugin::findModule(std::string_view Name) const noexcept { return nullptr; } -WASMEDGE_EXPORT -PluginRegister::PluginRegister(const Plugin::PluginDescriptor *Desc) noexcept { - IncreaseNiftyCounter(); - Plugin::registerPlugin(Desc); -} - -WASMEDGE_EXPORT PluginRegister::~PluginRegister() noexcept { - DecreaseNiftyCounter(); +WASMEDGE_EXPORT const PluginComponent * +Plugin::findComponent(std::string_view Name) const noexcept { + if (auto Iter = ComponentNameLookup.find(Name); + Iter != ComponentNameLookup.end()) { + return std::addressof(ComponentRegistry[Iter->second]); + } + return nullptr; } - } // namespace Plugin } // namespace WasmEdge diff --git a/lib/plugin/wasi_logging/CMakeLists.txt b/lib/plugin/wasi_logging/CMakeLists.txt new file mode 100644 index 000000000000..9591fcfbc56f --- /dev/null +++ b/lib/plugin/wasi_logging/CMakeLists.txt @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +# BUILTIN-PLUGIN: Temporary move the wasi-logging plugin sources here until +# the new plugin architecture ready in 0.15.0. + +wasmedge_add_library(wasmedgePluginWasiLogging + func.cpp + module.cpp +) + +target_link_libraries(wasmedgePluginWasiLogging + PUBLIC + wasmedgeCommon +) diff --git a/lib/plugin/wasi_logging/func.cpp b/lib/plugin/wasi_logging/func.cpp new file mode 100644 index 000000000000..2a0ad5c141d5 --- /dev/null +++ b/lib/plugin/wasi_logging/func.cpp @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +// BUILTIN-PLUGIN: Temporary move the wasi-logging plugin sources here until +// the new plugin architecture ready in 0.15.0. + +#include "plugin/wasi_logging/func.h" + +#include <string_view> + +namespace WasmEdge { +namespace Host { +namespace WASILogging { + +using namespace std::literals; + +Expect<void> Log::body(const Runtime::CallingFrame &Frame, uint32_t Level, + uint32_t CxtPtr, uint32_t CxtLen, uint32_t MsgPtr, + uint32_t MsgLen) { + // Check memory instance from module. + auto *MemInst = Frame.getMemoryByIndex(0); + if (MemInst == nullptr) { + return Unexpect(ErrCode::Value::HostFuncError); + } + + // Get Buffer Pointer. + char *CxtBuf = MemInst->getPointer<char *>(CxtPtr); + char *MsgBuf = MemInst->getPointer<char *>(MsgPtr); + if (CxtBuf == nullptr || MsgBuf == nullptr) { + return Unexpect(ErrCode::Value::HostFuncError); + } + + // Get Context and Message string_view + std::string_view CxtSV(CxtBuf, CxtLen); + std::string_view MsgSV(MsgBuf, MsgLen); + + // Setup Logger for Stdout or Stderr + std::shared_ptr<spdlog::logger> Logger; + if (CxtSV == "stdout"sv || CxtSV == ""sv) { + Logger = Env.StdoutLogger; + } else if (CxtSV == "stderr"sv) { + Logger = Env.StderrLogger; + } else { + if (CxtSV != Env.getLogFileName()) { + try { + spdlog::drop(Env.getLogRegName()); + Env.FileLogger = + spdlog::basic_logger_mt(Env.getLogRegName(), std::string(CxtSV)); + Env.FileLogger->set_level(spdlog::level::trace); + Env.FileLogger->set_pattern(Env.DefFormat); + Env.setLogFileName(CxtSV); + } catch (const spdlog::spdlog_ex &Ex) { + spdlog::error("[WasiLogging] Cannot log into file: {}"sv, Ex.what()); + return Unexpect(ErrCode::Value::HostFuncError); + } + } + Logger = Env.FileLogger; + } + + // Print Message by Logging Level + switch (static_cast<LogLevel>(Level)) { + case LogLevel::Trace: + Logger->trace(MsgSV); + break; + case LogLevel::Debug: + Logger->debug(MsgSV); + break; + case LogLevel::Info: + Logger->info(MsgSV); + break; + case LogLevel::Warn: + Logger->warn(MsgSV); + break; + case LogLevel::Error: + Logger->error(MsgSV); + break; + case LogLevel::Critical: + Logger->critical(MsgSV); + break; + default: + spdlog::error("[WasiLogging] Unrecognized Logging Level: {}"sv, Level); + spdlog::error("[WasiLogging] Trace Level = {}"sv, + static_cast<uint32_t>(LogLevel::Trace)); + spdlog::error("[WasiLogging] Debug Level = {}"sv, + static_cast<uint32_t>(LogLevel::Debug)); + spdlog::error("[WasiLogging] Info Level = {}"sv, + static_cast<uint32_t>(LogLevel::Info)); + spdlog::error("[WasiLogging] Warn Level = {}"sv, + static_cast<uint32_t>(LogLevel::Warn)); + spdlog::error("[WasiLogging] Error Level = {}"sv, + static_cast<uint32_t>(LogLevel::Error)); + spdlog::error("[WasiLogging] Critical Level = {}"sv, + static_cast<uint32_t>(LogLevel::Critical)); + return Unexpect(ErrCode::Value::HostFuncError); + } + return {}; +} + +} // namespace WASILogging +} // namespace Host +} // namespace WasmEdge diff --git a/lib/plugin/wasi_logging/module.cpp b/lib/plugin/wasi_logging/module.cpp new file mode 100644 index 000000000000..20f91a4cf8a0 --- /dev/null +++ b/lib/plugin/wasi_logging/module.cpp @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +// BUILTIN-PLUGIN: Temporary move the wasi-logging plugin sources here until +// the new plugin architecture ready in 0.15.0. + +#include "plugin/wasi_logging/module.h" +#include "plugin/plugin.h" +#include "plugin/wasi_logging/func.h" + +#include <string_view> + +namespace WasmEdge { +namespace Host { + +namespace { +Runtime::Instance::ModuleInstance * +create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new WasiLoggingModule; +} +} // namespace + +using namespace std::literals; + +const std::string WASILogging::LogEnv::DefFormat = + "[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v"; +std::mutex WASILogging::LogEnv::Mutex; +std::unordered_set<uint64_t> WASILogging::LogEnv::RegisteredID; + +WasiLoggingModule::WasiLoggingModule() + : ModuleInstance("wasi:logging/logging"sv) { + addHostFunc("log"sv, std::make_unique<WASILogging::Log>(Env)); +} + +Plugin::PluginModule::ModuleDescriptor WasiLoggingModule::ModuleDescriptor[]{ + { + /* Name */ "wasi:logging/logging", + /* Description */ "", + /* Create */ create, + }, +}; + +Plugin::Plugin::PluginDescriptor WasiLoggingModule::PluginDescriptor{ + /* Name */ "wasi_logging", + /* Description */ "", + /* APIVersion */ Plugin::Plugin::CurrentAPIVersion, + /* Version */ {0, 1, 0, 0}, + /* ModuleCount */ 1, + /* ModuleDescriptions */ ModuleDescriptor, + /* ComponentCount */ 0, + /* ComponentDescriptions */ nullptr, + /* AddOptions */ nullptr, +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/lib/po/CMakeLists.txt b/lib/po/CMakeLists.txt index 68c72d2581de..1bd97ed2a61a 100644 --- a/lib/po/CMakeLists.txt +++ b/lib/po/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_library(wasmedgePO argument_parser.cpp diff --git a/lib/po/argument_parser.cpp b/lib/po/argument_parser.cpp index 3baafd51d5bc..d54a5a82f04c 100644 --- a/lib/po/argument_parser.cpp +++ b/lib/po/argument_parser.cpp @@ -1,9 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "po/argument_parser.h" #include "common/defines.h" -#include "common/log.h" +#include "common/spdlog.h" #include "system/winapi.h" #include <cstdio> diff --git a/lib/system/CMakeLists.txt b/lib/system/CMakeLists.txt index 074c995dc4ca..554d7117ec08 100644 --- a/lib/system/CMakeLists.txt +++ b/lib/system/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_library(wasmedgeSystem allocator.cpp diff --git a/lib/system/allocator.cpp b/lib/system/allocator.cpp index 4f6cf897b60a..b44b83517916 100644 --- a/lib/system/allocator.cpp +++ b/lib/system/allocator.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "system/allocator.h" diff --git a/lib/system/fault.cpp b/lib/system/fault.cpp index 2d0a39764e06..8d7aa485a143 100644 --- a/lib/system/fault.cpp +++ b/lib/system/fault.cpp @@ -1,11 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "system/fault.h" #include "common/config.h" #include "common/defines.h" -#include "common/log.h" +#include "common/spdlog.h" #include <atomic> #include <csetjmp> @@ -25,8 +25,7 @@ std::atomic_uint handlerCount = 0; thread_local Fault *localHandler = nullptr; #if defined(SA_SIGINFO) -[[noreturn]] void signalHandler(int Signal, siginfo_t *Siginfo [[maybe_unused]], - void *) noexcept { +void signalHandler(int Signal, siginfo_t *Siginfo, void *) { { // Unblock current signal sigset_t Set; @@ -47,8 +46,7 @@ thread_local Fault *localHandler = nullptr; } void enableHandler() noexcept { - [[maybe_unused]] - struct sigaction Action {}; + [[maybe_unused]] struct sigaction Action {}; Action.sa_sigaction = &signalHandler; Action.sa_flags = SA_SIGINFO; // sigaction(SIGFPE, &Action, nullptr); diff --git a/lib/system/mmap.cpp b/lib/system/mmap.cpp index b6a7b7476c6f..10008d170447 100644 --- a/lib/system/mmap.cpp +++ b/lib/system/mmap.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "system/mmap.h" @@ -72,12 +72,13 @@ struct Implement { Create2ExParams.hTemplateFile = nullptr; File = winapi::CreateFile2(Path.c_str(), winapi::GENERIC_READ_, - winapi::FILE_SHARE_READ_, winapi::OPEN_EXISTING_, - &Create2ExParams); + winapi::FILE_SHARE_VALID_FLAGS_, + winapi::OPEN_EXISTING_, &Create2ExParams); #else - File = winapi::CreateFileW( - Path.c_str(), winapi::GENERIC_READ_, winapi::FILE_SHARE_READ_, nullptr, - winapi::OPEN_EXISTING_, winapi::FILE_FLAG_SEQUENTIAL_SCAN_, nullptr); + File = winapi::CreateFileW(Path.c_str(), winapi::GENERIC_READ_, + winapi::FILE_SHARE_VALID_FLAGS_, nullptr, + winapi::OPEN_EXISTING_, + winapi::FILE_FLAG_SEQUENTIAL_SCAN_, nullptr); #endif if (File == winapi::INVALID_HANDLE_VALUE_) { File = nullptr; diff --git a/lib/system/path.cpp b/lib/system/path.cpp index 406a11af31a0..c7357bcc35bf 100644 --- a/lib/system/path.cpp +++ b/lib/system/path.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "system/path.h" diff --git a/lib/validator/CMakeLists.txt b/lib/validator/CMakeLists.txt index 695195a742e7..fc086d9333b7 100644 --- a/lib/validator/CMakeLists.txt +++ b/lib/validator/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_library(wasmedgeValidator formchecker.cpp diff --git a/lib/validator/formchecker.cpp b/lib/validator/formchecker.cpp index 1d09abc06e63..e60d2b5b82ac 100644 --- a/lib/validator/formchecker.cpp +++ b/lib/validator/formchecker.cpp @@ -1,10 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "validator/formchecker.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" #include <algorithm> #include <array> @@ -41,6 +41,7 @@ void FormChecker::reset(bool CleanGlobal) { Datas.clear(); Elems.clear(); Refs.clear(); + Tags.clear(); NumImportFuncs = 0; NumImportGlobals = 0; } @@ -68,18 +69,7 @@ Expect<void> FormChecker::validate(const ValType &VT) const noexcept { return {}; } -void FormChecker::addType(const AST::FunctionType &Func) { - std::vector<ValType> Param, Ret; - Param.reserve(Func.getParamTypes().size()); - Ret.reserve(Func.getReturnTypes().size()); - for (auto Val : Func.getParamTypes()) { - Param.push_back(Val); - } - for (auto Val : Func.getReturnTypes()) { - Ret.push_back(Val); - } - Types.emplace_back(std::move(Param), std::move(Ret)); -} +void FormChecker::addType(const AST::SubType &Type) { Types.push_back(&Type); } void FormChecker::addFunc(const uint32_t TypeIdx, const bool IsImport) { if (Types.size() > TypeIdx) { @@ -122,6 +112,8 @@ void FormChecker::addLocal(const ValType &V, bool Initialized) { } } +void FormChecker::addTag(const uint32_t TypeIdx) { Tags.push_back(TypeIdx); } + ValType FormChecker::VTypeToAST(const VType &V) { if (!V) { return TypeCode::I32; @@ -129,60 +121,6 @@ ValType FormChecker::VTypeToAST(const VType &V) { return *V; } -bool FormChecker::matchType(const ValType &Exp, - const ValType &Got) const noexcept { - if (!Exp.isRefType() && !Got.isRefType() && Exp.getCode() == Got.getCode()) { - // Match for the non-reference type case. - return true; - } - if (Exp.isRefType() && Got.isRefType()) { - // Nullable matching. - if (!Exp.isNullableRefType() && Got.isNullableRefType()) { - return false; - } - - // Match the heap type. - if (Exp.getHeapTypeCode() == Got.getHeapTypeCode() && - Exp.getHeapTypeCode() != TypeCode::TypeIndex) { - // Abs heap types are the same. - return true; - } - if (Exp.getHeapTypeCode() == TypeCode::FuncRef && - Got.getHeapTypeCode() == TypeCode::TypeIndex) { - // Match type index to any funcref. - return true; - } - if (Exp.getHeapTypeCode() == TypeCode::TypeIndex && - Got.getHeapTypeCode() == TypeCode::TypeIndex) { - // Match got type index to expected type index. - if (matchTypes(Types[Exp.getTypeIndex()].first, - Types[Got.getTypeIndex()].first) && - matchTypes(Types[Exp.getTypeIndex()].second, - Types[Got.getTypeIndex()].second)) { - // Note: In future versions of WebAssembly, subtyping on function types - // may be relaxed to support co- and contra-variance. - // Due to passing the validation of type section, this will not cause - // infinite recursion. - return true; - } - } - } - return false; -} - -bool FormChecker::matchTypes(Span<const ValType> Exp, - Span<const ValType> Got) const noexcept { - if (Exp.size() != Got.size()) { - return false; - } - for (uint32_t I = 0; I < Exp.size(); I++) { - if (!matchType(Exp[I], Got[I])) { - return false; - } - } - return true; -} - Expect<void> FormChecker::checkExpr(AST::InstrView Instrs) { if (Instrs.size() > 0) { // Push ctrl frame ([] -> [Returns]) @@ -203,13 +141,31 @@ Expect<void> FormChecker::checkInstrs(AST::InstrView Instrs) { } return {}; } + Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { // Note: The instructions and their immediates have passed proposal // configuration checking in loader phase. + // Helper lambda for checking the defined type. + auto checkDefinedType = + [this](uint32_t TIdx, TypeCode TC) -> Expect<const AST::CompositeType *> { + if (TIdx >= Types.size()) { + return logOutOfRange(ErrCode::Value::InvalidFuncTypeIdx, + ErrInfo::IndexCategory::FunctionType, TIdx, + static_cast<uint32_t>(Types.size())); + } + const auto &CType = Types[TIdx]->getCompositeType(); + if (CType.getContentTypeCode() == TC) { + return &CType; + } else { + spdlog::error(ErrCode::Value::TypeCheckFailed); + return Unexpect(ErrCode::Value::TypeCheckFailed); + } + }; + // Helper lambda for checking and resolve the block type. - auto checkBlockType = [this](std::vector<ValType> &Buffer, - const BlockType &BType) + auto checkBlockType = [this, checkDefinedType](std::vector<ValType> &Buffer, + const BlockType &BType) -> Expect<std::pair<Span<const ValType>, Span<const ValType>>> { using ReturnType = std::pair<Span<const ValType>, Span<const ValType>>; if (BType.isEmpty()) { @@ -223,14 +179,13 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { Buffer[0] = BType.getValType(); return ReturnType{{}, Buffer}; } else { - // Type index case. t2* = type[index].returns - const uint32_t TypeIdx = BType.getTypeIndex(); - if (TypeIdx >= Types.size()) { - return logOutOfRange(ErrCode::Value::InvalidFuncTypeIdx, - ErrInfo::IndexCategory::FunctionType, TypeIdx, - static_cast<uint32_t>(Types.size())); + // Type index case. t2* = functype.returns. + if (auto Res = checkDefinedType(BType.getTypeIndex(), TypeCode::Func)) { + const auto &FType = (*Res)->getFuncType(); + return ReturnType{FType.getParamTypes(), FType.getReturnTypes()}; + } else { + return Unexpect(Res); } - return ReturnType{Types[TypeIdx].first, Types[TypeIdx].second}; } }; @@ -298,16 +253,9 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { // Helper lambda for checking value types matching. auto checkTypesMatching = [this](Span<const ValType> Exp, Span<const ValType> Got) -> Expect<void> { - if (!matchTypes(Exp, Got)) { - std::vector<ValType> ExpV, GotV; - ExpV.reserve(Exp.size()); - for (auto &I : Exp) { - ExpV.push_back(I); - } - GotV.reserve(Got.size()); - for (auto &I : Got) { - GotV.push_back(I); - } + if (!AST::TypeMatcher::matchTypes(Types, Exp, Got)) { + std::vector<ValType> ExpV(Exp.begin(), Exp.end()), + GotV(Got.begin(), Got.end()); spdlog::error(ErrCode::Value::TypeCheckFailed); spdlog::error(ErrInfo::InfoMismatch(ExpV, GotV)); return Unexpect(ErrCode::Value::TypeCheckFailed); @@ -315,6 +263,55 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { return {}; }; + // Helper lambda for recording jump data. + auto recordJump = [this, &Instr](AST::Instruction::JumpDescriptor &Jump, + uint32_t Arity, uint32_t D) -> void { + const uint32_t Remain = + static_cast<uint32_t>(ValStack.size() - CtrlStack[D].Height); + Jump.StackEraseBegin = Remain + Arity; + Jump.StackEraseEnd = Arity; + Jump.PCOffset = static_cast<int32_t>(CtrlStack[D].Jump - &Instr); + }; + + // Helper lambda for unpacking a value type. + auto unpackType = [](const ValType &T) -> ValType { + if (T.isPackType()) { + return ValType(TypeCode::I32); + } + return T; + }; + + // Helper lambda for downcasting into the top heap type. + auto toTopHeapType = [this](const ValType &T) -> ValType { + assuming(T.isRefType()); + if (T.isAbsHeapType()) { + switch (T.getHeapTypeCode()) { + case TypeCode::NullFuncRef: + case TypeCode::FuncRef: + return TypeCode::FuncRef; + case TypeCode::NullExternRef: + case TypeCode::ExternRef: + return TypeCode::ExternRef; + case TypeCode::NullRef: + case TypeCode::AnyRef: + case TypeCode::EqRef: + case TypeCode::I31Ref: + case TypeCode::StructRef: + case TypeCode::ArrayRef: + return TypeCode::AnyRef; + default: + assumingUnreachable(); + } + } else { + const auto &CompType = Types[T.getTypeIndex()]->getCompositeType(); + if (CompType.isFunc()) { + return TypeCode::FuncRef; + } else { + return TypeCode::AnyRef; + } + } + }; + switch (Instr.getOpCode()) { // Control instructions. case OpCode::Unreachable: @@ -322,13 +319,21 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { case OpCode::Nop: return {}; - case OpCode::If: case OpCode::Block: - case OpCode::Loop: { + case OpCode::Loop: + case OpCode::If: + // LEGACY-EH: remove the `Try` case after deprecating legacy EH. + case OpCode::Try: + case OpCode::Try_table: { // Get blocktype [t1*] -> [t2*] and check valtype first. std::vector<ValType> Buffer(1); Span<const ValType> T1, T2; - if (auto Res = checkBlockType(Buffer, Instr.getBlockType())) { + // LEGACY-EH: remove the `Try` case after deprecating legacy EH. + const auto &BType = (Instr.getOpCode() == OpCode::Try || + Instr.getOpCode() == OpCode::Try_table) + ? Instr.getTryCatch().ResType + : Instr.getBlockType(); + if (auto Res = checkBlockType(Buffer, BType)) { std::tie(T1, T2) = std::move(*Res); } else { return Unexpect(Res); @@ -343,6 +348,52 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { if (auto Res = popTypes(T1); !Res) { return Unexpect(Res); } + // For the try_table instruction, validate the handlers. + if (Instr.getOpCode() == OpCode::Try_table) { + const auto &TryDesc = Instr.getTryCatch(); + const_cast<AST::Instruction::TryDescriptor &>(TryDesc).BlockParamNum = + static_cast<uint32_t>(T1.size()); + // Validate catch clause. + for (const auto &C : TryDesc.Catch) { + if (!C.IsAll) { + // Check tag index. + if (unlikely(C.TagIndex >= Tags.size())) { + return logOutOfRange(ErrCode::Value::InvalidTagIdx, + ErrInfo::IndexCategory::Tag, C.TagIndex, + static_cast<uint32_t>(Tags.size())); + } + // Result type of tag index are checked in tag section. + } + if (auto D = checkCtrlStackDepth(C.LabelIndex)) { + pushCtrl({}, getLabelTypes(CtrlStack[*D]), &Instr + TryDesc.JumpEnd, + Instr.getOpCode()); + std::vector<ValType> NTypes; + if (!C.IsAll) { + // The type is checked as a function type. + NTypes = Types[Tags[C.TagIndex]] + ->getCompositeType() + .getFuncType() + .getParamTypes(); + } + if (C.IsRef) { + NTypes.emplace_back(ValType(TypeCode::ExnRef)); + } + pushTypes(NTypes); + if (auto Res = popCtrl(); !Res) { + return Unexpect(Res); + } + recordJump(const_cast<AST::Instruction::JumpDescriptor &>(C.Jump), + static_cast<uint32_t>(NTypes.size()), *D); + } else { + return Unexpect(D); + } + } + } else if (Instr.getOpCode() == OpCode::Try) { + // LEGACY-EH: remove the `Try` case after deprecating legacy EH. + const auto &TryDesc = Instr.getTryCatch(); + const_cast<AST::Instruction::TryDescriptor &>(TryDesc).BlockParamNum = + static_cast<uint32_t>(T1.size()); + } // Push ctrl frame ([t1*], [t2*]) const AST::Instruction *From = Instr.getOpCode() == OpCode::Loop ? &Instr @@ -360,15 +411,74 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { case OpCode::Else: if (auto Res = popCtrl()) { - pushCtrl((*Res).StartTypes, (*Res).EndTypes, Res->Jump, - Instr.getOpCode()); + pushCtrl(Res->StartTypes, Res->EndTypes, Res->Jump, Instr.getOpCode()); } else { return Unexpect(Res); } return {}; + + // LEGACY-EH: remove the `Catch` after deprecating legacy EH. + case OpCode::Catch: { + const auto &CatchDesc = Instr.getCatchLegacy(); + // Check tag index. + if (unlikely(CatchDesc.TagIndex >= Tags.size())) { + return logOutOfRange(ErrCode::Value::InvalidTagIdx, + ErrInfo::IndexCategory::Tag, CatchDesc.TagIndex, + static_cast<uint32_t>(Tags.size())); + } + const auto &NTypes = Types[Tags[CatchDesc.TagIndex]] + ->getCompositeType() + .getFuncType() + .getParamTypes(); + const auto &TryInstr = *(&Instr - CatchDesc.CatchPCOffset); + const auto &Catch = TryInstr.getTryCatch().Catch[CatchDesc.CatchIndex]; + if (auto Res = popCtrl()) { + // The continue block PC offset is the next of this instruction. + auto &Jump = const_cast<AST::Instruction::JumpDescriptor &>(Catch.Jump); + Jump.StackEraseBegin = + static_cast<uint32_t>(ValStack.size() - Res->Height) + + static_cast<uint32_t>(NTypes.size()); + Jump.StackEraseEnd = static_cast<uint32_t>(NTypes.size()); + Jump.PCOffset = static_cast<int32_t>(CatchDesc.CatchPCOffset + 1); + pushCtrl(NTypes, Res->EndTypes, Res->Jump, Instr.getOpCode()); + } else { + return Unexpect(Res); + } + return {}; + } + + case OpCode::Throw: + if (unlikely(Instr.getTargetIndex() >= Tags.size())) { + return logOutOfRange(ErrCode::Value::InvalidTagIdx, + ErrInfo::IndexCategory::Tag, Instr.getTargetIndex(), + static_cast<uint32_t>(Tags.size())); + } + if (auto CompType = + checkDefinedType(Tags[Instr.getTargetIndex()], TypeCode::Func)) { + std::vector<ValType> Input = (*CompType)->getFuncType().getParamTypes(); + if (auto Res = popTypes(Input); !Res) { + return Unexpect(Res); + } + return unreachable(); + } else { + return Unexpect(CompType); + } + + // LEGACY-EH: remove the `Rethrow` after deprecating legacy EH. + case OpCode::Rethrow: + spdlog::error(ErrCode::Value::TypeCheckFailed); + spdlog::error(" Deprecated `rethrow` instruction."); + return Unexpect(ErrCode::Value::TypeCheckFailed); + + case OpCode::Throw_ref: + if (auto Res = popType(TypeCode::ExnRef); !Res) { + return Unexpect(Res); + } + return unreachable(); + case OpCode::End: if (auto Res = popCtrl()) { - pushTypes((*Res).EndTypes); + pushTypes(Res->EndTypes); } else { return Unexpect(Res); } @@ -383,13 +493,8 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { if (auto Res = popTypes(NTypes); !Res) { return Unexpect(Res); } - const uint32_t Remain = - static_cast<uint32_t>(ValStack.size() - CtrlStack[*D].Height); - const uint32_t Arity = static_cast<uint32_t>(NTypes.size()); - auto &Jump = const_cast<AST::Instruction &>(Instr).getJump(); - Jump.StackEraseBegin = Remain + Arity; - Jump.StackEraseEnd = Arity; - Jump.PCOffset = static_cast<int32_t>(CtrlStack[*D].Jump - &Instr); + recordJump(const_cast<AST::Instruction &>(Instr).getJump(), + static_cast<uint32_t>(NTypes.size()), *D); return unreachable(); } case OpCode::Br_if: @@ -404,13 +509,8 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { if (auto Res = popTypes(NTypes); !Res) { return Unexpect(Res); } - const uint32_t Remain = - static_cast<uint32_t>(ValStack.size() - CtrlStack[*D].Height); - const uint32_t Arity = static_cast<uint32_t>(NTypes.size()); - auto &Jump = const_cast<AST::Instruction &>(Instr).getJump(); - Jump.StackEraseBegin = Remain + Arity; - Jump.StackEraseEnd = Arity; - Jump.PCOffset = static_cast<int32_t>(CtrlStack[*D].Jump - &Instr); + recordJump(const_cast<AST::Instruction &>(Instr).getJump(), + static_cast<uint32_t>(NTypes.size()), *D); pushTypes(NTypes); return {}; } @@ -450,13 +550,8 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { return Unexpect(Res); } } - const uint32_t Remain = - static_cast<uint32_t>(ValStack.size() - CtrlStack[*N].Height); - const uint32_t Arity = static_cast<uint32_t>(NTypes.size()); - LabelTable[LabelIdx].StackEraseBegin = Remain + Arity; - LabelTable[LabelIdx].StackEraseEnd = Arity; - LabelTable[LabelIdx].PCOffset = - static_cast<int32_t>(CtrlStack[*N].Jump - &Instr); + recordJump(LabelTable[LabelIdx], static_cast<uint32_t>(NTypes.size()), + *N); pushTypes(TypeBuf); } else { return Unexpect(N); @@ -466,13 +561,8 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { if (auto Res = popTypes(NTypes); !Res) { return Unexpect(Res); } - const uint32_t Remain = - static_cast<uint32_t>(ValStack.size() - CtrlStack[*M].Height); - const uint32_t Arity = static_cast<uint32_t>(NTypes.size()); - LabelTable[LabelTableSize].StackEraseBegin = Remain + Arity; - LabelTable[LabelTableSize].StackEraseEnd = Arity; - LabelTable[LabelTableSize].PCOffset = - static_cast<int32_t>(CtrlStack[*M].Jump - &Instr); + recordJump(LabelTable[LabelTableSize], + static_cast<uint32_t>(NTypes.size()), *M); return unreachable(); } else { return Unexpect(M); @@ -481,30 +571,24 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { case OpCode::Br_on_null: // D is the last D element of control stack. - if (auto D = checkCtrlStackDepth(Instr.getTargetIndex())) { + if (auto D = checkCtrlStackDepth(Instr.getJump().TargetIndex)) { const auto NTypes = getLabelTypes(CtrlStack[*D]); if (auto ResT = popType()) { - if (*ResT == unreachableVType()) { - // will not reach here. Validation succeeds. - return {}; - } - if (!(*ResT)->isRefType()) { + if ((*ResT).has_value() && !(*ResT)->isRefType()) { spdlog::error(ErrCode::Value::InvalidBrRefType); return Unexpect(ErrCode::ErrCode::Value::InvalidBrRefType); } if (auto Res = popTypes(NTypes); !Res) { return Unexpect(Res); } - const uint32_t Remain = - static_cast<uint32_t>(ValStack.size() - CtrlStack[*D].Height); - const uint32_t Arity = static_cast<uint32_t>(NTypes.size()); - auto &Jump = const_cast<AST::Instruction &>(Instr).getJump(); - Jump.StackEraseBegin = Remain + Arity; - Jump.StackEraseEnd = Arity; - Jump.PCOffset = static_cast<int32_t>(CtrlStack[*D].Jump - &Instr); + recordJump(const_cast<AST::Instruction &>(Instr).getJump(), + static_cast<uint32_t>(NTypes.size()), *D); pushTypes(NTypes); - pushType(ValType(TypeCode::Ref, (*ResT)->getHeapTypeCode(), - (*ResT)->getTypeIndex())); + if ((*ResT).has_value()) { + pushType((*ResT)->toNonNullableRef()); + } else { + pushType(unreachableVType()); + } return {}; } else { return Unexpect(ResT); @@ -512,38 +596,30 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { } else { return Unexpect(D); } + case OpCode::Br_on_non_null: - if (auto D = checkCtrlStackDepth(Instr.getTargetIndex())) { + if (auto D = checkCtrlStackDepth(Instr.getJump().TargetIndex)) { + // Get the result type of the label. (Should be [t* rt].) auto LabelTypes = getLabelTypes(CtrlStack[*D]); std::vector<ValType> NTypes(LabelTypes.begin(), LabelTypes.end()); - if (NTypes.empty()) { - spdlog::error(ErrCode::Value::InvalidBrRefType); - return Unexpect(ErrCode::Value::InvalidBrRefType); - } - ValType RType = NTypes.back(); - NTypes.pop_back(); - if (!RType.isRefType() || RType.isNullableRefType()) { + if (unlikely(NTypes.empty())) { spdlog::error(ErrCode::Value::InvalidBrRefType); return Unexpect(ErrCode::Value::InvalidBrRefType); } - if (auto Res = popType(ValType(TypeCode::RefNull, RType.getHeapTypeCode(), - RType.getTypeIndex())); - !Res) { + // Pop types [t* (ref.null rt)]. + ValType &RT = NTypes.back(); + if (!RT.isRefType()) { spdlog::error(ErrCode::Value::InvalidBrRefType); return Unexpect(ErrCode::Value::InvalidBrRefType); } + RT.toNullableRef(); if (auto Res = popTypes(NTypes); !Res) { - spdlog::error(ErrCode::Value::InvalidBrRefType); - return Unexpect(ErrCode::Value::InvalidBrRefType); + return Unexpect(Res); } - const uint32_t Remain = - static_cast<uint32_t>(ValStack.size() - CtrlStack[*D].Height); - const uint32_t Arity = static_cast<uint32_t>(NTypes.size() + 1); - // We plus 1 here because we did `pop_back` on `NTypes` - auto &Jump = const_cast<AST::Instruction &>(Instr).getJump(); - Jump.StackEraseBegin = Remain + Arity; - Jump.StackEraseEnd = Arity; - Jump.PCOffset = static_cast<int32_t>(CtrlStack[*D].Jump - &Instr); + recordJump(const_cast<AST::Instruction &>(Instr).getJump(), + static_cast<uint32_t>(NTypes.size()), *D); + // Push types [t*]. + NTypes.pop_back(); pushTypes(NTypes); return {}; } else { @@ -558,40 +634,43 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { case OpCode::Call: { auto N = Instr.getTargetIndex(); - if (N >= Funcs.size()) { + if (unlikely(N >= Funcs.size())) { return logOutOfRange(ErrCode::Value::InvalidFuncIdx, ErrInfo::IndexCategory::Function, N, static_cast<uint32_t>(Funcs.size())); } - return StackTrans(Types[Funcs[N]].first, Types[Funcs[N]].second); + // Due to validation when adding functions, Type[Funcs[N]] must be a + // function type. + auto &FuncType = Types[Funcs[N]]->getCompositeType().getFuncType(); + return StackTrans(FuncType.getParamTypes(), FuncType.getReturnTypes()); } case OpCode::Call_indirect: { auto N = Instr.getTargetIndex(); auto T = Instr.getSourceIndex(); // Check source table index. - if (T >= Tables.size()) { + if (unlikely(T >= Tables.size())) { return logOutOfRange(ErrCode::Value::InvalidTableIdx, ErrInfo::IndexCategory::Table, T, static_cast<uint32_t>(Tables.size())); } - if (!Tables[T].isFuncRefType()) { + if (unlikely(!Tables[T].isFuncRefType())) { spdlog::error(ErrCode::Value::InvalidTableIdx); return Unexpect(ErrCode::Value::InvalidTableIdx); } // Check target function type index. - if (N >= Types.size()) { - return logOutOfRange(ErrCode::Value::InvalidFuncTypeIdx, - ErrInfo::IndexCategory::FunctionType, N, - static_cast<uint32_t>(Types.size())); - } - if (auto Res = popType(TypeCode::I32); !Res) { - return Unexpect(Res); + if (auto CompType = checkDefinedType(N, TypeCode::Func)) { + if (auto Res = popType(TypeCode::I32); !Res) { + return Unexpect(Res); + } + const auto &FType = (*CompType)->getFuncType(); + return StackTrans(FType.getParamTypes(), FType.getReturnTypes()); + } else { + return Unexpect(CompType); } - return StackTrans(Types[N].first, Types[N].second); } case OpCode::Return_call: { auto N = Instr.getTargetIndex(); - if (Funcs.size() <= N) { + if (unlikely(N >= Funcs.size())) { // Call function index out of range spdlog::error(ErrCode::Value::InvalidFuncIdx); spdlog::error( @@ -599,12 +678,13 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { static_cast<uint32_t>(Funcs.size()))); return Unexpect(ErrCode::Value::InvalidFuncIdx); } - if (!matchTypes(Returns, Types[Funcs[N]].second)) { - spdlog::error(ErrCode::Value::TypeCheckFailed); - spdlog::error(ErrInfo::InfoMismatch(Returns, Types[Funcs[N]].second)); - return Unexpect(ErrCode::Value::TypeCheckFailed); + // Due to validation when adding functions, Type[Funcs[N]] must be a + // function type. + auto &FType = Types[Funcs[N]]->getCompositeType().getFuncType(); + if (auto Res = checkTypesMatching(Returns, FType.getReturnTypes()); !Res) { + return Unexpect(Res); } - if (auto Res = popTypes(Types[Funcs[N]].first); !Res) { + if (auto Res = popTypes(FType.getParamTypes()); !Res) { return Unexpect(Res); } return unreachable(); @@ -613,72 +693,89 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { auto N = Instr.getTargetIndex(); auto T = Instr.getSourceIndex(); // Check source table index. - if (Tables.size() <= T) { - spdlog::error(ErrCode::Value::InvalidTableIdx); - spdlog::error( - ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::Table, T, - static_cast<uint32_t>(Tables.size()))); - return Unexpect(ErrCode::Value::InvalidTableIdx); + if (unlikely(T >= Tables.size())) { + return logOutOfRange(ErrCode::Value::InvalidTableIdx, + ErrInfo::IndexCategory::Table, T, + static_cast<uint32_t>(Tables.size())); } - if (!Tables[T].isFuncRefType()) { + if (unlikely(!Tables[T].isFuncRefType())) { spdlog::error(ErrCode::Value::InvalidTableIdx); return Unexpect(ErrCode::Value::InvalidTableIdx); } // Check target function type index. - if (Types.size() <= N) { - spdlog::error(ErrCode::Value::InvalidFuncTypeIdx); - spdlog::error( - ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::FunctionType, N, - static_cast<uint32_t>(Types.size()))); - return Unexpect(ErrCode::Value::InvalidFuncTypeIdx); - } - if (!matchTypes(Returns, Types[N].second)) { - spdlog::error(ErrCode::Value::TypeCheckFailed); - spdlog::error(ErrInfo::InfoMismatch(Returns, Types[N].second)); - return Unexpect(ErrCode::Value::TypeCheckFailed); - } - if (auto Res = popType(TypeCode::I32); !Res) { - return Unexpect(Res); - } - if (auto Res = popTypes(Types[N].first); !Res) { - return Unexpect(Res); + if (auto CompType = checkDefinedType(N, TypeCode::Func)) { + const auto &FType = (*CompType)->getFuncType(); + if (auto Res = checkTypesMatching(Returns, FType.getReturnTypes()); + !Res) { + return Unexpect(Res); + } + if (auto Res = popType(TypeCode::I32); !Res) { + return Unexpect(Res); + } + if (auto Res = popTypes(FType.getParamTypes()); !Res) { + return Unexpect(Res); + } + return unreachable(); + } else { + return Unexpect(CompType); } - return unreachable(); } - case OpCode::Call_ref: { - auto TypeIdx = Instr.getTargetIndex(); - if (TypeIdx >= static_cast<uint32_t>(Types.size())) { - return logOutOfRange(ErrCode::Value::InvalidFuncTypeIdx, - ErrInfo::IndexCategory::FunctionType, TypeIdx, - static_cast<uint32_t>(Types.size())); + case OpCode::Call_ref: + if (auto Res = checkDefinedType(Instr.getTargetIndex(), TypeCode::Func)) { + const auto &FType = (*Res)->getFuncType(); + std::vector<ValType> Input = FType.getParamTypes(); + Input.push_back(ValType(TypeCode::RefNull, Instr.getTargetIndex())); + return StackTrans(Input, FType.getReturnTypes()); + } else { + return Unexpect(Res); } - std::vector<ValType> Input = Types[TypeIdx].first; - Input.push_back(ValType(TypeCode::RefNull, TypeIdx)); - return StackTrans(Input, Types[TypeIdx].second); - } case OpCode::Return_call_ref: { - auto TypeIdx = Instr.getTargetIndex(); - if (TypeIdx >= Types.size()) { - // Call function index out of range - spdlog::error(ErrCode::Value::InvalidFuncIdx); - spdlog::error(ErrInfo::InfoForbidIndex( - ErrInfo::IndexCategory::FunctionType, TypeIdx, - static_cast<uint32_t>(Types.size()))); - return Unexpect(ErrCode::Value::InvalidFuncIdx); - } - if (!matchTypes(Returns, Types[TypeIdx].second)) { - spdlog::error(ErrCode::Value::TypeCheckFailed); - spdlog::error(ErrInfo::InfoMismatch(Returns, Types[TypeIdx].second)); - return Unexpect(ErrCode::Value::TypeCheckFailed); + if (auto CompType = + checkDefinedType(Instr.getTargetIndex(), TypeCode::Func)) { + const auto &FType = (*CompType)->getFuncType(); + if (auto Res = checkTypesMatching(Returns, FType.getReturnTypes()); + !Res) { + return Unexpect(Res); + } + if (auto Res = + popType(ValType(TypeCode::RefNull, Instr.getTargetIndex())); + !Res) { + return Unexpect(Res); + } + if (auto Res = popTypes(FType.getParamTypes()); !Res) { + return Unexpect(Res); + } + return unreachable(); + } else { + return Unexpect(CompType); } - std::vector<ValType> Input = Types[TypeIdx].first; - Input.push_back(ValType(TypeCode::RefNull, TypeIdx)); - if (auto Res = popTypes(Input); !Res) { + } + + // LEGACY-EH: remove the `Catch_all` after deprecating legacy EH. + case OpCode::Catch_all: { + const auto &CatchDesc = Instr.getCatchLegacy(); + const auto &TryInstr = *(&Instr - CatchDesc.CatchPCOffset); + const auto &Catch = TryInstr.getTryCatch().Catch[CatchDesc.CatchIndex]; + if (auto Res = popCtrl()) { + // The continue block PC offset is the next of this instruction. + auto &Jump = const_cast<AST::Instruction::JumpDescriptor &>(Catch.Jump); + Jump.StackEraseBegin = + static_cast<uint32_t>(ValStack.size() - Res->Height); + Jump.StackEraseEnd = 0; + Jump.PCOffset = static_cast<int32_t>(CatchDesc.CatchPCOffset + 1); + pushCtrl({}, Res->EndTypes, Res->Jump, Instr.getOpCode()); + } else { return Unexpect(Res); } - return unreachable(); + return {}; } + // LEGACY-EH: remove the `Delegate` after deprecating legacy EH. + case OpCode::Delegate: + spdlog::error(ErrCode::Value::TypeCheckFailed); + spdlog::error(" Deprecated `delegate` instruction."); + return Unexpect(ErrCode::Value::TypeCheckFailed); + // Reference Instructions. case OpCode::Ref__null: if (auto Res = validate(Instr.getValType())) { @@ -688,7 +785,7 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { } case OpCode::Ref__is_null: if (auto Res = popType()) { - if (!isRefType(*Res)) { + if ((*Res).has_value() && !(*Res)->isRefType()) { spdlog::error(ErrCode::Value::TypeCheckFailed); spdlog::error( ErrInfo::InfoMismatch(TypeCode::FuncRef, VTypeToAST(*Res))); @@ -710,6 +807,11 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { assuming(TypeIdx < Types.size()); return StackTrans({}, {ValType(TypeCode::Ref, TypeIdx)}); } + case OpCode::Ref__eq: { + return StackTrans({ValType(TypeCode::RefNull, TypeCode::EqRef), + ValType(TypeCode::RefNull, TypeCode::EqRef)}, + {ValType(TypeCode::I32)}); + } case OpCode::Ref__as_non_null: { if (auto Res = popType()) { if (*Res == unreachableVType()) { @@ -722,12 +824,354 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { ValType(TypeCode::RefNull, TypeCode::FuncRef), VTypeToAST(*Res))); return Unexpect(ErrCode::Value::TypeCheckFailed); } - return StackTrans({}, {ValType(TypeCode::Ref, (*Res)->getHeapTypeCode(), - (*Res)->getTypeIndex())}); + return StackTrans({}, {(*Res)->toNonNullableRef()}); + } else { + return Unexpect(Res); + } + } + + case OpCode::Struct__new: + case OpCode::Struct__new_default: { + if (auto Res = checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct)) { + std::vector<ValType> Fields; + if (Instr.getOpCode() == OpCode::Struct__new) { + Fields.reserve((*Res)->getFieldTypes().size()); + } + for (auto &FType : (*Res)->getFieldTypes()) { + if (Instr.getOpCode() == OpCode::Struct__new) { + Fields.emplace_back(unpackType(FType.getStorageType())); + } else if (!FType.getStorageType().isDefaultable()) { + spdlog::error(ErrCode::Value::TypeCheckFailed); + spdlog::error(" Value type should be defaultable."); + return Unexpect(ErrCode::Value::TypeCheckFailed); + } + } + return StackTrans(Fields, + {ValType(TypeCode::Ref, Instr.getTargetIndex())}); + } else { + return Unexpect(Res); + } + } + case OpCode::Struct__get: + case OpCode::Struct__get_s: + case OpCode::Struct__get_u: { + if (auto Res = checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct)) { + if (Instr.getSourceIndex() >= (*Res)->getFieldTypes().size()) { + return logOutOfRange( + ErrCode::Value::InvalidFieldIdx, ErrInfo::IndexCategory::Field, + Instr.getSourceIndex(), + static_cast<uint32_t>((*Res)->getFieldTypes().size())); + } + const auto &FType = (*Res)->getFieldTypes()[Instr.getSourceIndex()]; + if (unlikely(Instr.getOpCode() == OpCode::Struct__get && + FType.getStorageType().isPackType())) { + // For a packed type, the `_s` or `_u` in instruction is required. + spdlog::error(ErrCode::Value::InvalidPackedField); + return Unexpect(ErrCode::Value::InvalidPackedField); + } else if (unlikely(Instr.getOpCode() != OpCode::Struct__get && + !FType.getStorageType().isPackType())) { + // The `_s` or `_u` in instruction only accepts packed field. + spdlog::error(ErrCode::Value::InvalidUnpackedField); + return Unexpect(ErrCode::Value::InvalidUnpackedField); + } + return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex())}, + {unpackType(FType.getStorageType())}); + } else { + return Unexpect(Res); + } + } + case OpCode::Struct__set: { + if (auto Res = checkDefinedType(Instr.getTargetIndex(), TypeCode::Struct)) { + if (Instr.getSourceIndex() >= (*Res)->getFieldTypes().size()) { + return logOutOfRange( + ErrCode::Value::InvalidFieldIdx, ErrInfo::IndexCategory::Field, + Instr.getSourceIndex(), + static_cast<uint32_t>((*Res)->getFieldTypes().size())); + } + const auto &FType = (*Res)->getFieldTypes()[Instr.getSourceIndex()]; + if (FType.getValMut() != ValMut::Var) { + spdlog::error(ErrCode::Value::ImmutableField); + return Unexpect(ErrCode::Value::ImmutableField); + } + return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()), + unpackType(FType.getStorageType())}, + {}); + } else { + return Unexpect(Res); + } + } + case OpCode::Array__new: + case OpCode::Array__new_default: + case OpCode::Array__new_fixed: { + if (auto Res = checkDefinedType(Instr.getTargetIndex(), TypeCode::Array)) { + const auto &SType = (*Res)->getFieldTypes()[0].getStorageType(); + if (Instr.getOpCode() == OpCode::Array__new) { + return StackTrans({unpackType(SType), ValType(TypeCode::I32)}, + {ValType(TypeCode::Ref, Instr.getTargetIndex())}); + } else if (Instr.getOpCode() == OpCode::Array__new_default) { + if (!SType.isDefaultable()) { + spdlog::error(ErrCode::Value::TypeCheckFailed); + spdlog::error(" Value type should be defaultable."); + return Unexpect(ErrCode::Value::TypeCheckFailed); + } + return StackTrans({ValType(TypeCode::I32)}, + {ValType(TypeCode::Ref, Instr.getTargetIndex())}); + } else { + std::vector<ValType> Fields(Instr.getSourceIndex(), unpackType(SType)); + return StackTrans(Fields, + {ValType(TypeCode::Ref, Instr.getTargetIndex())}); + } + } else { + return Unexpect(Res); + } + } + case OpCode::Array__new_data: + case OpCode::Array__init_data: { + if (auto Res = checkDefinedType(Instr.getTargetIndex(), TypeCode::Array)) { + const auto &FType = (*Res)->getFieldTypes()[0]; + if (Instr.getOpCode() == OpCode::Array__init_data && + FType.getValMut() != ValMut::Var) { + spdlog::error(ErrCode::Value::ImmutableArray); + return Unexpect(ErrCode::Value::ImmutableArray); + } + if (!unpackType(FType.getStorageType()).isNumType()) { + spdlog::error(ErrCode::Value::ArrayTypesNumtypeRequired); + return Unexpect(ErrCode::Value::ArrayTypesNumtypeRequired); + } + if (Instr.getSourceIndex() >= Datas.size()) { + return logOutOfRange( + ErrCode::Value::InvalidDataIdx, ErrInfo::IndexCategory::Data, + Instr.getSourceIndex(), static_cast<uint32_t>(Datas.size())); + } + if (Instr.getOpCode() == OpCode::Array__new_data) { + return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)}, + {ValType(TypeCode::Ref, Instr.getTargetIndex())}); + } else { + return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()), + ValType(TypeCode::I32), ValType(TypeCode::I32), + ValType(TypeCode::I32)}, + {}); + } + } else { + return Unexpect(Res); + } + } + case OpCode::Array__new_elem: + case OpCode::Array__init_elem: { + if (auto Res = checkDefinedType(Instr.getTargetIndex(), TypeCode::Array)) { + const auto &FType = (*Res)->getFieldTypes()[0]; + if (Instr.getOpCode() == OpCode::Array__init_elem && + FType.getValMut() != ValMut::Var) { + spdlog::error(ErrCode::Value::ImmutableArray); + return Unexpect(ErrCode::Value::ImmutableArray); + } + if (!FType.getStorageType().isRefType()) { + spdlog::error(ErrCode::Value::TypeCheckFailed); + return Unexpect(ErrCode::Value::TypeCheckFailed); + } + if (Instr.getSourceIndex() >= Elems.size()) { + return logOutOfRange( + ErrCode::Value::InvalidElemIdx, ErrInfo::IndexCategory::Element, + Instr.getSourceIndex(), static_cast<uint32_t>(Elems.size())); + } + if (!AST::TypeMatcher::matchType(Types, FType.getStorageType(), + Elems[Instr.getSourceIndex()])) { + spdlog::error(ErrCode::Value::TypeCheckFailed); + spdlog::error(ErrInfo::InfoMismatch(FType.getStorageType(), + Elems[Instr.getSourceIndex()])); + return Unexpect(ErrCode::Value::TypeCheckFailed); + } + if (Instr.getOpCode() == OpCode::Array__new_elem) { + return StackTrans({ValType(TypeCode::I32), ValType(TypeCode::I32)}, + {ValType(TypeCode::Ref, Instr.getTargetIndex())}); + } else { + return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()), + ValType(TypeCode::I32), ValType(TypeCode::I32), + ValType(TypeCode::I32)}, + {}); + } + } else { + return Unexpect(Res); + } + } + case OpCode::Array__get: + case OpCode::Array__get_s: + case OpCode::Array__get_u: { + if (auto Res = checkDefinedType(Instr.getTargetIndex(), TypeCode::Array)) { + const auto &FType = (*Res)->getFieldTypes()[0]; + if (unlikely(Instr.getOpCode() == OpCode::Array__get && + FType.getStorageType().isPackType())) { + // For a packed type, the `_s` or `_u` in instruction is required. + spdlog::error(ErrCode::Value::InvalidPackedArray); + return Unexpect(ErrCode::Value::InvalidPackedArray); + } else if (unlikely(Instr.getOpCode() != OpCode::Array__get && + !FType.getStorageType().isPackType())) { + // The `_s` or `_u` in instruction only accepts packed array. + spdlog::error(ErrCode::Value::InvalidUnpackedArray); + return Unexpect(ErrCode::Value::InvalidUnpackedArray); + } + return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()), + ValType(TypeCode::I32)}, + {unpackType(FType.getStorageType())}); + } else { + return Unexpect(Res); + } + } + case OpCode::Array__set: + case OpCode::Array__fill: { + if (auto Res = checkDefinedType(Instr.getTargetIndex(), TypeCode::Array)) { + const auto &FType = (*Res)->getFieldTypes()[0]; + if (FType.getValMut() != ValMut::Var) { + spdlog::error(ErrCode::Value::ImmutableArray); + return Unexpect(ErrCode::Value::ImmutableArray); + } + std::vector<ValType> Fields = { + ValType(TypeCode::RefNull, Instr.getTargetIndex()), + ValType(TypeCode::I32), unpackType(FType.getStorageType())}; + if (Instr.getOpCode() == OpCode::Array__fill) { + Fields.emplace_back(ValType(TypeCode::I32)); + } + return StackTrans(Fields, {}); + } else { + return Unexpect(Res); + } + } + case OpCode::Array__len: + return StackTrans({ValType(TypeCode::ArrayRef)}, {ValType(TypeCode::I32)}); + case OpCode::Array__copy: { + if (auto Dst = checkDefinedType(Instr.getTargetIndex(), TypeCode::Array)) { + const auto &DstFType = (*Dst)->getFieldTypes()[0]; + if (DstFType.getValMut() != ValMut::Var) { + spdlog::error(ErrCode::Value::ImmutableArray); + return Unexpect(ErrCode::Value::ImmutableArray); + } + if (auto Src = + checkDefinedType(Instr.getSourceIndex(), TypeCode::Array)) { + const auto &SrcFType = (*Src)->getFieldTypes()[0]; + if (!AST::TypeMatcher::matchType(Types, DstFType.getStorageType(), + SrcFType.getStorageType())) { + spdlog::error(ErrCode::Value::ArrayTypesMismatch); + spdlog::error(ErrInfo::InfoMismatch(DstFType.getStorageType(), + SrcFType.getStorageType())); + return Unexpect(ErrCode::Value::ArrayTypesMismatch); + } + return StackTrans({ValType(TypeCode::RefNull, Instr.getTargetIndex()), + ValType(TypeCode::I32), + ValType(TypeCode::RefNull, Instr.getSourceIndex()), + ValType(TypeCode::I32), ValType(TypeCode::I32)}, + {}); + } else { + return Unexpect(Src); + } + } else { + return Unexpect(Dst); + } + } + + case OpCode::Ref__test: + case OpCode::Ref__test_null: + case OpCode::Ref__cast: + case OpCode::Ref__cast_null: { + if (auto Res = validate(Instr.getValType()); !Res) { + return Unexpect(Res); + } + if (auto Res = popType()) { + if (!(*Res).has_value() || !(*Res)->isRefType()) { + // For getting bottom valtype here, matching must fail. + spdlog::error(ErrCode::Value::TypeCheckFailed); + spdlog::error( + ErrInfo::InfoMismatch(Instr.getValType(), VTypeToAST(*Res))); + return Unexpect(ErrCode::Value::TypeCheckFailed); + } + if (!AST::TypeMatcher::matchType(Types, toTopHeapType(**Res), + Instr.getValType())) { + spdlog::error(ErrCode::Value::TypeCheckFailed); + spdlog::error(ErrInfo::InfoMismatch(**Res, Instr.getValType())); + return Unexpect(ErrCode::Value::TypeCheckFailed); + } + if (Instr.getOpCode() == OpCode::Ref__test || + Instr.getOpCode() == OpCode::Ref__test_null) { + return StackTrans({}, {ValType(TypeCode::I32)}); + } else { + return StackTrans({}, {Instr.getValType()}); + } } else { return Unexpect(Res); } } + case OpCode::Br_on_cast: + case OpCode::Br_on_cast_fail: { + // The reference types should be valid. + auto &RT1 = Instr.getBrCast().RType1; + auto &RT2 = Instr.getBrCast().RType2; + if (auto Res = validate(RT1); !Res) { + return Unexpect(Res); + } + if (auto Res = validate(RT2); !Res) { + return Unexpect(Res); + } + // The reference type RT2 should match RT1. + if (unlikely(!AST::TypeMatcher::matchType(Types, RT1, RT2))) { + spdlog::error(ErrCode::Value::TypeCheckFailed); + spdlog::error(ErrInfo::InfoMismatch(RT1, RT2)); + return Unexpect(ErrCode::Value::TypeCheckFailed); + } + if (auto D = checkCtrlStackDepth(Instr.getBrCast().Jump.TargetIndex)) { + // Get the result type of the label. (Should be [t* rt'].) + auto LabelTypes = getLabelTypes(CtrlStack[*D]); + std::vector<ValType> NTypes(LabelTypes.begin(), LabelTypes.end()); + if (unlikely(NTypes.empty())) { + spdlog::error(ErrCode::Value::InvalidBrRefType); + return Unexpect(ErrCode::Value::InvalidBrRefType); + } + // Get the type difference between rt1 \ rt2. (rt1' = rt1 \ rt2) + ValType RT1P = RT2.isNullableRefType() ? RT1.getNonNullableRef() : RT1; + // For br_on_cast, rt2 must match rt'. + // For Br_on_cast_fail, rt1' must match rt'. + ValType &RTP = NTypes.back(); + const ValType &RTRHS = + Instr.getOpCode() == OpCode::Br_on_cast ? RT2 : RT1P; + if (unlikely(!AST::TypeMatcher::matchType(Types, RTP, RTRHS))) { + spdlog::error(ErrCode::Value::TypeCheckFailed); + spdlog::error(ErrInfo::InfoMismatch(RTP, RTRHS)); + return Unexpect(ErrCode::Value::TypeCheckFailed); + } + // Pop types [t* rt1]. + RTP = RT1; + if (auto Res = popTypes(NTypes); !Res) { + return Unexpect(Res); + } + recordJump(const_cast<AST::Instruction &>(Instr).getBrCast().Jump, + static_cast<uint32_t>(NTypes.size()), *D); + // For br_on_cast, push types [t* rt1']. + // For Br_on_cast_fail, push types [t* rt2]. + RTP = Instr.getOpCode() == OpCode::Br_on_cast ? RT1P : RT2; + pushTypes(NTypes); + return {}; + } else { + return Unexpect(D); + } + } + case OpCode::Any__convert_extern: + if (auto Res = popType(TypeCode::ExternRef)) { + return StackTrans({}, {ValType((*Res)->getCode(), TypeCode::AnyRef)}); + } else { + return Unexpect(Res); + } + case OpCode::Extern__convert_any: + if (auto Res = popType(TypeCode::AnyRef)) { + return StackTrans({}, {ValType((*Res)->getCode(), TypeCode::ExternRef)}); + } else { + return Unexpect(Res); + } + case OpCode::Ref__i31: + return StackTrans({ValType(TypeCode::I32)}, + {ValType(TypeCode::Ref, TypeCode::I31Ref)}); + case OpCode::I31__get_s: + case OpCode::I31__get_u: + return StackTrans({ValType(TypeCode::RefNull, TypeCode::I31Ref)}, + {ValType(TypeCode::I32)}); + // Parametric Instructions. case OpCode::Drop: return StackPopAny(); @@ -749,12 +1193,12 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { return Unexpect(Res); } // T1 and T2 should be number type. - if (!isNumType(T1)) { + if (T1.has_value() && !T1->isNumType()) { spdlog::error(ErrCode::Value::TypeCheckFailed); spdlog::error(ErrInfo::InfoMismatch(TypeCode::I32, VTypeToAST(T1))); return Unexpect(ErrCode::Value::TypeCheckFailed); } - if (!isNumType(T2)) { + if (T2.has_value() && !T2->isNumType()) { spdlog::error(ErrCode::Value::TypeCheckFailed); spdlog::error(ErrInfo::InfoMismatch(VTypeToAST(T1), VTypeToAST(T2))); return Unexpect(ErrCode::Value::TypeCheckFailed); @@ -883,8 +1327,8 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { Instr.getSourceIndex(), static_cast<uint32_t>(Elems.size())); } // Check is the reference types matched. - if (!matchType(Tables[Instr.getTargetIndex()], - Elems[Instr.getSourceIndex()])) { + if (!AST::TypeMatcher::matchType(Types, Tables[Instr.getTargetIndex()], + Elems[Instr.getSourceIndex()])) { spdlog::error(ErrCode::Value::TypeCheckFailed); spdlog::error(ErrInfo::InfoMismatch(Tables[Instr.getTargetIndex()], Elems[Instr.getSourceIndex()])); @@ -901,8 +1345,8 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { Instr.getSourceIndex(), static_cast<uint32_t>(Tables.size())); } // Check is the reference types matched. - if (!matchType(Tables[Instr.getTargetIndex()], - Tables[Instr.getSourceIndex()])) { + if (!AST::TypeMatcher::matchType(Types, Tables[Instr.getTargetIndex()], + Tables[Instr.getSourceIndex()])) { spdlog::error(ErrCode::Value::TypeCheckFailed); spdlog::error(ErrInfo::InfoMismatch(Tables[Instr.getTargetIndex()], Tables[Instr.getSourceIndex()])); @@ -1552,6 +1996,38 @@ Expect<void> FormChecker::checkInstr(const AST::Instruction &Instr) { return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::I32)}, {ValType(TypeCode::V128)}); + case OpCode::I8x16__relaxed_swizzle: + return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)}, + {ValType(TypeCode::V128)}); + case OpCode::I32x4__relaxed_trunc_f32x4_s: + case OpCode::I32x4__relaxed_trunc_f32x4_u: + case OpCode::I32x4__relaxed_trunc_f64x2_s_zero: + case OpCode::I32x4__relaxed_trunc_f64x2_u_zero: + return StackTrans({ValType(TypeCode::V128)}, {ValType(TypeCode::V128)}); + case OpCode::F32x4__relaxed_madd: + case OpCode::F32x4__relaxed_nmadd: + case OpCode::F64x2__relaxed_madd: + case OpCode::F64x2__relaxed_nmadd: + case OpCode::I8x16__relaxed_laneselect: + case OpCode::I16x8__relaxed_laneselect: + case OpCode::I32x4__relaxed_laneselect: + case OpCode::I64x2__relaxed_laneselect: + return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128), + ValType(TypeCode::V128)}, + {ValType(TypeCode::V128)}); + case OpCode::F32x4__relaxed_min: + case OpCode::F32x4__relaxed_max: + case OpCode::F64x2__relaxed_min: + case OpCode::F64x2__relaxed_max: + case OpCode::I16x8__relaxed_q15mulr_s: + case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s: + return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128)}, + {ValType(TypeCode::V128)}); + case OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s: + return StackTrans({ValType(TypeCode::V128), ValType(TypeCode::V128), + ValType(TypeCode::V128)}, + {ValType(TypeCode::V128)}); + case OpCode::Atomic__fence: return {}; @@ -1868,7 +2344,7 @@ Expect<VType> FormChecker::popType(ValType E) { return E; } - if (!matchType(E, **Res)) { + if (!AST::TypeMatcher::matchType(Types, E, **Res)) { // Expect value on value stack is not matched spdlog::error(ErrCode::Value::TypeCheckFailed); spdlog::error(ErrInfo::InfoMismatch(VTypeToAST(E), VTypeToAST(*Res))); diff --git a/lib/validator/validator.cpp b/lib/validator/validator.cpp index 3d8c6fe5cdcd..24f20c488336 100644 --- a/lib/validator/validator.cpp +++ b/lib/validator/validator.cpp @@ -1,11 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "validator/validator.h" #include "common/errinfo.h" #include <cstdint> +#include <numeric> #include <string> #include <unordered_set> #include <vector> @@ -14,14 +15,20 @@ namespace WasmEdge { namespace Validator { Expect<void> Validator::validate(const AST::Component::Component &Comp) { + using namespace AST::Component; + spdlog::warn("component validation is not done yet."); - for (auto &Mod : Comp.getCoreModuleSection().getContent()) { - validate(Mod); - } - for (const std::shared_ptr<AST::Component::Component> &C : - Comp.getComponentSection().getContent()) { - validate(*C); + for (auto &Sec : Comp.getSections()) { + if (std::holds_alternative<AST::CoreModuleSection>(Sec)) { + auto &Mod = std::get<AST::CoreModuleSection>(Sec).getContent(); + validate(Mod); + } else if (std::holds_alternative<ComponentSection>(Sec)) { + auto &C = std::get<ComponentSection>(Sec).getContent(); + validate(C); + } else { + // TODO: validate others section + } } return {}; @@ -74,6 +81,13 @@ Expect<void> Validator::validate(const AST::Module &Mod) { return Unexpect(Res); } + // Validate tag section and register tags into FormChecker. + if (auto Res = validate(Mod.getTagSection()); !Res) { + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Tag)); + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); + return Unexpect(Res); + } + // Validate export section. if (auto Res = validate(Mod.getExportSection()); !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Export)); @@ -131,6 +145,64 @@ Expect<void> Validator::validate(const AST::Module &Mod) { return {}; } +// Validate Sub type. See "include/validator/validator.h". +Expect<void> Validator::validate(const AST::SubType &Type) { + const auto &TypeVec = Checker.getTypes(); + const auto &CompType = Type.getCompositeType(); + + // Check the validation of the composite type. + if (CompType.isFunc()) { + const auto &FType = CompType.getFuncType(); + for (auto &PType : FType.getParamTypes()) { + if (auto Res = Checker.validate(PType); !Res) { + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function)); + return Unexpect(Res); + } + } + for (auto &RType : FType.getReturnTypes()) { + if (auto Res = Checker.validate(RType); !Res) { + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Function)); + return Unexpect(Res); + } + } + } else { + const auto &FTypes = CompType.getFieldTypes(); + for (auto &FieldType : FTypes) { + if (auto Res = Checker.validate(FieldType.getStorageType()); !Res) { + return Unexpect(Res); + } + } + } + + // In current version, the length of type index vector will be <= 1. + if (Type.getSuperTypeIndices().size() > 1) { + spdlog::error(ErrCode::Value::InvalidSubType); + spdlog::error(" Accepts 1 super type currently."); + return Unexpect(ErrCode::Value::InvalidSubType); + } + for (auto Index : Type.getSuperTypeIndices()) { + if (Index >= TypeVec.size()) { + spdlog::error(ErrCode::Value::InvalidSubType); + spdlog::error( + ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::DefinedType, Index, + static_cast<uint32_t>(TypeVec.size()))); + return Unexpect(ErrCode::Value::InvalidSubType); + } + if (TypeVec[Index]->isFinal()) { + spdlog::error(ErrCode::Value::InvalidSubType); + spdlog::error(" Super type should not be final."); + return Unexpect(ErrCode::Value::InvalidSubType); + } + auto &SuperType = TypeVec[Index]->getCompositeType(); + if (!AST::TypeMatcher::matchType(Checker.getTypes(), SuperType, CompType)) { + spdlog::error(ErrCode::Value::InvalidSubType); + spdlog::error(" Super type not matched."); + return Unexpect(ErrCode::Value::InvalidSubType); + } + } + return {}; +} + // Validate Limit type. See "include/validator/validator.h". Expect<void> Validator::validate(const AST::Limit &Lim) { if (Lim.hasMax() && Lim.getMin() > Lim.getMax()) { @@ -257,7 +329,7 @@ Expect<void> Validator::validate(const AST::ElementSegment &ElemSeg) { static_cast<uint32_t>(TableVec.size()))); return Unexpect(ErrCode::Value::InvalidTableIdx); } - // TODO: Use Checker.matchType() to match types instead. + // TODO: Use AST::TypeMatcher::matchType() to match types instead. // For the element segments, the RefType may not record the strict type // index, and should check the init exprs for the real type index to do type // matching. But for the table type, the type index is recorded into the @@ -285,12 +357,16 @@ Expect<void> Validator::validate(const AST::ElementSegment &ElemSeg) { // Validate Code segment. See "include/validator/validator.h". Expect<void> Validator::validate(const AST::CodeSegment &CodeSeg, const uint32_t TypeIdx) { + // Due to the validation of the function section, the type of index bust be a + // function type. + const auto &FuncType = + Checker.getTypes()[TypeIdx]->getCompositeType().getFuncType(); // Reset stack in FormChecker. Checker.reset(); // Add parameters into this frame. - for (auto Val : Checker.getTypes()[TypeIdx].first) { - // Local passed as function parameters should be initialized - Checker.addLocal(Val, true); + for (auto &Type : FuncType.getParamTypes()) { + // Local passed as function parameters should be initialized. + Checker.addLocal(Type, true); } // Add locals into this frame. for (auto Val : CodeSeg.getLocals()) { @@ -304,7 +380,7 @@ Expect<void> Validator::validate(const AST::CodeSegment &CodeSeg, } // Validate function body expression. if (auto Res = Checker.validate(CodeSeg.getExpr().getInstrs(), - Checker.getTypes()[TypeIdx].second); + FuncType.getReturnTypes()); !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression)); return Unexpect(Res); @@ -342,7 +418,7 @@ Expect<void> Validator::validate(const AST::ImportDesc &ImpDesc) { // loader phase. case ExternalType::Function: { const auto TId = ImpDesc.getExternalFuncTypeIdx(); - // Function type index must exist in context. + // Function type index must exist in context and be valid. if (TId >= Checker.getTypes().size()) { spdlog::error(ErrCode::Value::InvalidFuncTypeIdx); spdlog::error(ErrInfo::InfoForbidIndex( @@ -350,6 +426,11 @@ Expect<void> Validator::validate(const AST::ImportDesc &ImpDesc) { static_cast<uint32_t>(Checker.getTypes().size()))); return Unexpect(ErrCode::Value::InvalidFuncTypeIdx); } + if (!Checker.getTypes()[TId]->getCompositeType().isFunc()) { + spdlog::error(ErrCode::Value::InvalidFuncTypeIdx); + spdlog::error(" Defined type index {} is not a function type.", TId); + return Unexpect(ErrCode::Value::InvalidFuncTypeIdx); + } Checker.addRef(static_cast<uint32_t>(Checker.getFunctions().size())); Checker.addFunc(TId, true); return {}; @@ -374,6 +455,20 @@ Expect<void> Validator::validate(const AST::ImportDesc &ImpDesc) { Checker.addMemory(MemType); return {}; } + case ExternalType::Tag: { + const auto &T = ImpDesc.getExternalTagType(); + // Tag type index must exist in context. + auto TagTypeIdx = T.getTypeIdx(); + if (TagTypeIdx >= Checker.getTypes().size()) { + spdlog::error(ErrCode::Value::InvalidTagIdx); + spdlog::error(ErrInfo::InfoForbidIndex( + ErrInfo::IndexCategory::TagType, TagTypeIdx, + static_cast<uint32_t>(Checker.getTypes().size()))); + return Unexpect(ErrCode::Value::InvalidTagIdx); + } + Checker.addTag(TagTypeIdx); + return {}; + } case ExternalType::Global: { const auto &GlobType = ImpDesc.getExternalGlobalType(); // Global type must be valid. @@ -421,6 +516,15 @@ Expect<void> Validator::validate(const AST::ExportDesc &ExpDesc) { return Unexpect(ErrCode::Value::InvalidMemoryIdx); } return {}; + case ExternalType::Tag: + if (Id >= Checker.getTags().size()) { + spdlog::error(ErrCode::Value::InvalidTagIdx); + spdlog::error(ErrInfo::InfoForbidIndex( + ErrInfo::IndexCategory::Tag, Id, + static_cast<uint32_t>(Checker.getTags().size()))); + return Unexpect(ErrCode::Value::InvalidTagIdx); + } + return {}; case ExternalType::Global: if (Id >= Checker.getGlobals().size()) { spdlog::error(ErrCode::Value::InvalidGlobalIdx); @@ -437,18 +541,41 @@ Expect<void> Validator::validate(const AST::ExportDesc &ExpDesc) { } Expect<void> Validator::validate(const AST::TypeSection &TypeSec) { - for (const auto &Type : TypeSec.getContent()) { - for (auto &PType : Type.getParamTypes()) { - if (auto Res = Checker.validate(PType); !Res) { - return Unexpect(Res); + const auto STypeList = TypeSec.getContent(); + uint32_t Idx = 0; + while (Idx < STypeList.size()) { + const auto &SType = STypeList[Idx]; + if (SType.getRecursiveInfo().has_value()) { + // Recursive type case. Add types first for referring recursively. + uint32_t RecSize = SType.getRecursiveInfo()->RecTypeSize; + for (uint32_t I = Idx; I < Idx + RecSize; I++) { + Checker.addType(STypeList[I]); } - } - for (auto &RType : Type.getReturnTypes()) { - if (auto Res = Checker.validate(RType); !Res) { - return Unexpect(Res); + for (uint32_t I = Idx; I < Idx + RecSize; I++) { + if (auto Res = validate(STypeList[I]); !Res) { + spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Type_Rec)); + return Unexpect(Res); + } } + Idx += RecSize; + } else { + // SubType case. + if (Conf.hasProposal(Proposal::GC)) { + // For the GC proposal, the subtype is seemed as a self-recursive type. + // Add types first for referring recursively. + Checker.addType(SType); + if (auto Res = validate(*Checker.getTypes().back()); !Res) { + return Unexpect(Res); + } + } else { + // Validating first. + if (auto Res = validate(SType); !Res) { + return Unexpect(Res); + } + Checker.addType(SType); + } + Idx++; } - Checker.addType(Type); } return {}; } @@ -478,6 +605,11 @@ Expect<void> Validator::validate(const AST::FunctionSection &FuncSec) { static_cast<uint32_t>(TypeVec.size()))); return Unexpect(ErrCode::Value::InvalidFuncTypeIdx); } + if (!TypeVec[TId]->getCompositeType().isFunc()) { + spdlog::error(ErrCode::Value::InvalidFuncTypeIdx); + spdlog::error(" Defined type index {} is not a function type.", TId); + return Unexpect(ErrCode::Value::InvalidFuncTypeIdx); + } Checker.addFunc(TId); } return {}; @@ -584,18 +716,18 @@ Expect<void> Validator::validate(const AST::StartSection &StartSec) { return Unexpect(ErrCode::Value::InvalidFuncIdx); } auto TId = Checker.getFunctions()[FId]; - auto &Type = Checker.getTypes()[TId]; - if (Type.first.size() != 0 || Type.second.size() != 0) { + assuming(TId < Checker.getTypes().size()); + if (!Checker.getTypes()[TId]->getCompositeType().isFunc()) { + spdlog::error(ErrCode::Value::InvalidStartFunc); + spdlog::error(" Defined type index {} is not a function type.", TId); + return Unexpect(ErrCode::Value::InvalidStartFunc); + } + auto &Type = Checker.getTypes()[TId]->getCompositeType().getFuncType(); + if (Type.getParamTypes().size() != 0 || Type.getReturnTypes().size() != 0) { // Start function signature should be {}->{} - std::vector<ValType> Params, Returns; - for (auto &V : Type.first) { - Params.push_back(Checker.VTypeToAST(V)); - } - for (auto &V : Type.second) { - Returns.push_back(Checker.VTypeToAST(V)); - } spdlog::error(ErrCode::Value::InvalidStartFunc); - spdlog::error(ErrInfo::InfoMismatch({}, {}, Params, Returns)); + spdlog::error(ErrInfo::InfoMismatch({}, {}, Type.getParamTypes(), + Type.getReturnTypes())); return Unexpect(ErrCode::Value::InvalidStartFunc); } } @@ -621,6 +753,37 @@ Expect<void> Validator::validate(const AST::ExportSection &ExportSec) { return {}; } +// Validate Tag section. See "include/validator/validator.h". +Expect<void> Validator::validate(const AST::TagSection &TagSec) { + const auto &TagVec = TagSec.getContent(); + const auto &TypeVec = Checker.getTypes(); + + // Check if type id of tag is valid in context. + for (auto &TagType : TagVec) { + auto TagTypeIdx = TagType.getTypeIdx(); + if (TagTypeIdx >= TypeVec.size()) { + spdlog::error(ErrCode::Value::InvalidTagIdx); + spdlog::error( + ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::TagType, TagTypeIdx, + static_cast<uint32_t>(TypeVec.size()))); + return Unexpect(ErrCode::Value::InvalidTagIdx); + } + auto &CompType = TypeVec[TagTypeIdx]->getCompositeType(); + if (!CompType.isFunc()) { + spdlog::error(ErrCode::Value::InvalidTagIdx); + spdlog::error(" Defined type index {} is not a function type.", + TagTypeIdx); + return Unexpect(ErrCode::Value::InvalidTagIdx); + } + if (!CompType.getFuncType().getReturnTypes().empty()) { + spdlog::error(ErrCode::Value::InvalidTagResultType); + return Unexpect(ErrCode::Value::InvalidTagResultType); + } + Checker.addTag(TagTypeIdx); + } + return {}; +} + // Validate constant expression. See "include/validator/validator.h". Expect<void> Validator::validateConstExpr(AST::InstrView Instrs, Span<const ValType> Returns) { @@ -630,11 +793,14 @@ Expect<void> Validator::validateConstExpr(AST::InstrView Instrs, case OpCode::Global__get: { // For initialization case, global indices must be imported globals. auto GlobIdx = Instr.getTargetIndex(); - if (GlobIdx >= Checker.getNumImportGlobals()) { + uint32_t ValidGlobalSize = Checker.getNumImportGlobals(); + if (Conf.hasProposal(Proposal::GC)) { + ValidGlobalSize = static_cast<uint32_t>(Checker.getGlobals().size()); + } + if (GlobIdx >= ValidGlobalSize) { spdlog::error(ErrCode::Value::InvalidGlobalIdx); - spdlog::error(ErrInfo::InfoForbidIndex( - ErrInfo::IndexCategory::Global, GlobIdx, - static_cast<uint32_t>(Checker.getNumImportGlobals()))); + spdlog::error(ErrInfo::InfoForbidIndex(ErrInfo::IndexCategory::Global, + GlobIdx, ValidGlobalSize)); spdlog::error( ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); return Unexpect(ErrCode::Value::InvalidGlobalIdx); @@ -670,6 +836,14 @@ Expect<void> Validator::validateConstExpr(AST::InstrView Instrs, case OpCode::Ref__null: case OpCode::V128__const: case OpCode::End: + case OpCode::Struct__new: + case OpCode::Struct__new_default: + case OpCode::Array__new: + case OpCode::Array__new_default: + case OpCode::Array__new_fixed: + case OpCode::Any__convert_extern: + case OpCode::Extern__convert_any: + case OpCode::Ref__i31: break; // For the Extended-const proposal, these instructions are accepted. diff --git a/lib/vm/CMakeLists.txt b/lib/vm/CMakeLists.txt index 0158e0bdfaf6..fc55ecd0b2d0 100644 --- a/lib/vm/CMakeLists.txt +++ b/lib/vm/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_library(wasmedgeVM vm.cpp @@ -15,3 +15,14 @@ target_link_libraries(wasmedgeVM wasmedgeExecutor wasmedgeHostModuleWasi ) + +if(WASMEDGE_USE_LLVM) + target_compile_definitions(wasmedgeVM + PUBLIC + -DWASMEDGE_USE_LLVM + ) + target_link_libraries(wasmedgeVM + PUBLIC + wasmedgeLLVM + ) +endif() diff --git a/lib/vm/vm.cpp b/lib/vm/vm.cpp index 398e4be97d27..ee54dacf8426 100644 --- a/lib/vm/vm.cpp +++ b/lib/vm/vm.cpp @@ -1,24 +1,48 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "vm/vm.h" +#include "ast/module.h" #include "host/wasi/wasimodule.h" #include "plugin/plugin.h" +#include "llvm/compiler.h" +#include "llvm/jit.h" #include "host/mock/wasi_crypto_module.h" #include "host/mock/wasi_logging_module.h" #include "host/mock/wasi_nn_module.h" #include "host/mock/wasmedge_image_module.h" #include "host/mock/wasmedge_process_module.h" +#include "host/mock/wasmedge_stablediffusion_module.h" #include "host/mock/wasmedge_tensorflow_module.h" #include "host/mock/wasmedge_tensorflowlite_module.h" +#include "validator/validator.h" +#include <memory> #include <variant> namespace WasmEdge { namespace VM { namespace { + +template <typename T> struct VisitUnit { + using MT = std::function<T(std::unique_ptr<AST::Module> &)>; + using CT = std::function<T(std::unique_ptr<AST::Component::Component> &)>; + + VisitUnit(MT F, CT G) : VisitMod{F}, VisitComp{G} {} + T operator()(std::unique_ptr<AST::Module> &Mod) const { + return VisitMod(Mod); + } + T operator()(std::unique_ptr<AST::Component::Component> &Comp) const { + return VisitComp(Comp); + } + +private: + MT VisitMod; + CT VisitComp; +}; + template <typename T> std::unique_ptr<Runtime::Instance::ModuleInstance> createPluginModule(std::string_view PName, std::string_view MName) { @@ -102,6 +126,9 @@ void VM::unsafeLoadPlugInHosts() { "wasmedge_tensorflowlite"sv, "wasmedge_tensorflowlite"sv)); PlugInModInsts.push_back(createPluginModule<Host::WasmEdgeImageModuleMock>( "wasmedge_image"sv, "wasmedge_image"sv)); + PlugInModInsts.push_back( + createPluginModule<Host::WasmEdgeStableDiffusionModuleMock>( + "wasmedge_stablediffusion"sv, "wasmedge_stablediffusion"sv)); // Load the other non-official plugins. for (const auto &Plugin : Plugin::Plugin::plugins()) { @@ -115,12 +142,16 @@ void VM::unsafeLoadPlugInHosts() { Plugin.name() == "wasmedge_process"sv || Plugin.name() == "wasmedge_tensorflow"sv || Plugin.name() == "wasmedge_tensorflowlite"sv || - Plugin.name() == "wasmedge_image"sv) { + Plugin.name() == "wasmedge_image"sv || + Plugin.name() == "wasmedge_stablediffusion"sv) { continue; } for (const auto &Module : Plugin.modules()) { PlugInModInsts.push_back(Module.create()); } + for (const auto &Component : Plugin.components()) { + PlugInCompInsts.push_back(Component.create()); + } } } @@ -136,6 +167,9 @@ void VM::unsafeRegisterPlugInHosts() { for (auto &It : PlugInModInsts) { ExecutorEngine.registerModule(StoreRef, *(It.get())); } + for (auto &It : PlugInCompInsts) { + ExecutorEngine.registerComponent(StoreRef, *(It.get())); + } } Expect<void> VM::unsafeRegisterModule(std::string_view Name, @@ -209,14 +243,19 @@ VM::unsafeRunWasmFile(const std::filesystem::path &Path, std::string_view Func, } // Load wasm unit. if (auto Res = LoaderEngine.parseWasmUnit(Path)) { - if (std::holds_alternative<std::unique_ptr<AST::Module>>(*Res)) { - auto M = std::move(std::get<std::unique_ptr<AST::Module>>(*Res)); - return unsafeRunWasmFile(*M, Func, Params, ParamTypes); - } else { - return unsafeRunWasmFile( - (*std::get<std::unique_ptr<AST::Component::Component>>(*Res)), Func, - Params, ParamTypes); - } + return std::visit( + VisitUnit<Expect<std::vector<std::pair<ValVariant, ValType>>>>( + [&](auto &M) + -> Expect<std::vector<std::pair<ValVariant, ValType>>> { + Mod = std::move(M); + return unsafeRunWasmFile(*Mod, Func, Params, ParamTypes); + }, + [&](auto &C) + -> Expect<std::vector<std::pair<ValVariant, ValType>>> { + Comp = std::move(C); + return unsafeRunWasmFile(*Comp, Func, Params, ParamTypes); + }), + *Res); } else { return Unexpect(Res); } @@ -233,15 +272,19 @@ VM::unsafeRunWasmFile(Span<const Byte> Code, std::string_view Func, } // Load wasm unit. if (auto Res = LoaderEngine.parseWasmUnit(Code)) { - if (std::holds_alternative<std::unique_ptr<AST::Module>>(*Res)) { - std::unique_ptr<AST::Module> M = - std::move(std::get<std::unique_ptr<AST::Module>>(*Res)); - return unsafeRunWasmFile(*M, Func, Params, ParamTypes); - } else { - std::unique_ptr<AST::Component::Component> C = - std::move(std::get<std::unique_ptr<AST::Component::Component>>(*Res)); - return unsafeRunWasmFile(*C, Func, Params, ParamTypes); - } + return std::visit( + VisitUnit<Expect<std::vector<std::pair<ValVariant, ValType>>>>( + [&](auto &M) + -> Expect<std::vector<std::pair<ValVariant, ValType>>> { + Mod = std::move(M); + return unsafeRunWasmFile(*Mod, Func, Params, ParamTypes); + }, + [&](auto &C) + -> Expect<std::vector<std::pair<ValVariant, ValType>>> { + Comp = std::move(C); + return unsafeRunWasmFile(*Comp, Func, Params, ParamTypes); + }), + *Res); } else { return Unexpect(Res); } @@ -284,10 +327,29 @@ VM::unsafeRunWasmFile(const AST::Module &Module, std::string_view Func, if (ActiveModInst) { // Execute function and return values with the module instance. return unsafeExecute(ActiveModInst.get(), Func, Params, ParamTypes); + } + spdlog::error(ErrCode::Value::WrongInstanceAddress); + spdlog::error(ErrInfo::InfoExecuting("", Func)); + return Unexpect(ErrCode::Value::WrongInstanceAddress); +} + +Expect<std::vector<std::pair<ValVariant, ValType>>> +VM::unsafeExecute(const Runtime::Instance::ComponentInstance *CompInst, + std::string_view Func, Span<const ValVariant> Params, + Span<const ValType> ParamTypes) { + // Find exported function by name. + Runtime::Instance::FunctionInstance *FuncInst = + CompInst->findFuncExports(Func); + + // Execute function. + if (auto Res = ExecutorEngine.invoke(FuncInst, Params, ParamTypes); + unlikely(!Res)) { + if (Res.error() != ErrCode::Value::Terminated) { + spdlog::error(ErrInfo::InfoExecuting(CompInst->getComponentName(), Func)); + } + return Unexpect(Res); } else { - spdlog::error(ErrCode::Value::WrongInstanceAddress); - spdlog::error(ErrInfo::InfoExecuting("", Func)); - return Unexpect(ErrCode::Value::WrongInstanceAddress); + return Res; } } @@ -338,37 +400,27 @@ VM::asyncRunWasmFile(const AST::Module &Module, std::string_view Func, Expect<void> VM::unsafeLoadWasm(const std::filesystem::path &Path) { // If not load successfully, the previous status will be reserved. - if (auto Res = LoaderEngine.parseWasmUnit(Path)) { - if (std::holds_alternative<std::unique_ptr<AST::Module>>(*Res)) { - Mod = std::move(std::get<std::unique_ptr<AST::Module>>(*Res)); - } else if (std::holds_alternative< - std::unique_ptr<AST::Component::Component>>(*Res)) { - spdlog::error("component execution is not done yet."); - } else { - return Unexpect(Res); - } - Stage = VMStage::Loaded; - } else { + auto Res = LoaderEngine.parseWasmUnit(Path); + if (!Res) { return Unexpect(Res); } + std::visit(VisitUnit<void>([&](auto &M) -> void { Mod = std::move(M); }, + [&](auto &C) -> void { Comp = std::move(C); }), + *Res); + Stage = VMStage::Loaded; return {}; } Expect<void> VM::unsafeLoadWasm(Span<const Byte> Code) { // If not load successfully, the previous status will be reserved. - if (auto Res = LoaderEngine.parseWasmUnit(Code)) { - if (std::holds_alternative<std::unique_ptr<AST::Module>>(*Res)) { - Mod = std::move(std::get<std::unique_ptr<AST::Module>>(*Res)); - } else if (std::holds_alternative< - std::unique_ptr<AST::Component::Component>>(*Res)) { - spdlog::error("component execution is not done yet."); - } else { - return Unexpect(Res); - } - Stage = VMStage::Loaded; - } else { + auto Res = LoaderEngine.parseWasmUnit(Code); + if (!Res) { return Unexpect(Res); } + std::visit(VisitUnit<void>([&](auto &M) -> void { Mod = std::move(M); }, + [&](auto &C) -> void { Comp = std::move(C); }), + *Res); + Stage = VMStage::Loaded; return {}; } @@ -378,18 +430,42 @@ Expect<void> VM::unsafeLoadWasm(const AST::Module &Module) { return {}; } +struct Validate { + // borrow validator to pass control to it + Validate(Validator::Validator &Engine) : ValidatorEngine(Engine) {} + Expect<void> operator()(const std::unique_ptr<AST::Module> &Mod) const { + return ValidatorEngine.validate(*Mod.get()); + } + Expect<void> + operator()(const std::unique_ptr<AST::Component::Component> &Comp) const { + return ValidatorEngine.validate(*Comp.get()); + } + +private: + Validator::Validator &ValidatorEngine; +}; + Expect<void> VM::unsafeValidate() { if (Stage < VMStage::Loaded) { // When module is not loaded, not validate. spdlog::error(ErrCode::Value::WrongVMWorkflow); return Unexpect(ErrCode::Value::WrongVMWorkflow); } - if (auto Res = ValidatorEngine.validate(*Mod.get())) { - Stage = VMStage::Validated; - return {}; + + if (Mod) { + if (auto Res = ValidatorEngine.validate(*Mod.get()); !Res) { + return Unexpect(Res); + } + } else if (Comp) { + if (auto Res = ValidatorEngine.validate(*Comp.get()); !Res) { + return Unexpect(Res); + } } else { - return Unexpect(Res); + spdlog::error(ErrCode::Value::WrongVMWorkflow); + return Unexpect(ErrCode::Value::WrongVMWorkflow); } + Stage = VMStage::Validated; + return {}; } Expect<void> VM::unsafeInstantiate() { @@ -398,12 +474,47 @@ Expect<void> VM::unsafeInstantiate() { spdlog::error(ErrCode::Value::WrongVMWorkflow); return Unexpect(ErrCode::Value::WrongVMWorkflow); } - if (auto Res = ExecutorEngine.instantiateModule(StoreRef, *Mod.get())) { - Stage = VMStage::Instantiated; - ActiveModInst = std::move(*Res); - return {}; + + if (Mod) { + if (Conf.getRuntimeConfigure().isEnableJIT() && !Mod->getSymbol()) { +#ifdef WASMEDGE_USE_LLVM + LLVM::Compiler Compiler(Conf); + LLVM::JIT JIT(Conf); + if (auto Res = Compiler.compile(*Mod); !Res) { + const auto Err = static_cast<uint32_t>(Res.error()); + spdlog::error( + "Compilation failed. Error code: {}, use interpreter mode instead."sv, + Err); + } else if (auto Res2 = JIT.load(std::move(*Res)); !Res2) { + const auto Err = static_cast<uint32_t>(Res2.error()); + spdlog::warn( + "JIT failed. Error code: {}, use interpreter mode instead."sv, Err); + } else { + LoaderEngine.loadExecutable(*Mod, std::move(*Res2)); + } +#else + spdlog::error("LLVM disabled, JIT is unsupported!"); +#endif + } + + if (auto Res = ExecutorEngine.instantiateModule(StoreRef, *Mod)) { + Stage = VMStage::Instantiated; + ActiveModInst = std::move(*Res); + return {}; + } else { + return Unexpect(Res); + } + } else if (Comp) { + if (auto Res = ExecutorEngine.instantiateComponent(StoreRef, *Comp)) { + Stage = VMStage::Instantiated; + ActiveCompInst = std::move(*Res); + return {}; + } else { + return Unexpect(Res); + } } else { - return Unexpect(Res); + spdlog::error(ErrCode::Value::WrongVMWorkflow); + return Unexpect(ErrCode::Value::WrongVMWorkflow); } } @@ -413,11 +524,13 @@ VM::unsafeExecute(std::string_view Func, Span<const ValVariant> Params, if (ActiveModInst) { // Execute function and return values with the module instance. return unsafeExecute(ActiveModInst.get(), Func, Params, ParamTypes); - } else { - spdlog::error(ErrCode::Value::WrongInstanceAddress); - spdlog::error(ErrInfo::InfoExecuting("", Func)); - return Unexpect(ErrCode::Value::WrongInstanceAddress); } + if (ActiveCompInst) { + return unsafeExecute(ActiveCompInst.get(), Func, Params, ParamTypes); + } + spdlog::error(ErrCode::Value::WrongInstanceAddress); + spdlog::error(ErrInfo::InfoExecuting("", Func)); + return Unexpect(ErrCode::Value::WrongInstanceAddress); } Expect<std::vector<std::pair<ValVariant, ValType>>> @@ -483,8 +596,18 @@ VM::asyncExecute(std::string_view ModName, std::string_view Func, } void VM::unsafeCleanup() { - Mod.reset(); - ActiveModInst.reset(); + if (Mod) { + Mod.reset(); + } + if (Comp) { + Comp.reset(); + } + if (ActiveModInst) { + ActiveModInst.reset(); + } + if (ActiveCompInst) { + ActiveCompInst.reset(); + } StoreRef.reset(); RegModInsts.clear(); Stat.clear(); @@ -507,6 +630,8 @@ VM::unsafeGetFunctionList() const { Map.emplace_back(Func.first, FuncType); } }); + } else if (ActiveCompInst) { + return ActiveCompInst->getFuncExports(); } return Map; } diff --git a/lib/wasi_nn_rpc/wasi_ephemeral_nn.proto b/lib/wasi_nn_rpc/wasi_ephemeral_nn.proto index 3ed030e455dc..0d7365e31d26 100644 --- a/lib/wasi_nn_rpc/wasi_ephemeral_nn.proto +++ b/lib/wasi_nn_rpc/wasi_ephemeral_nn.proto @@ -44,9 +44,19 @@ message LoadByNameResult { uint32 graph_handle = 1; } +message LoadByNameWithConfigRequest { + string name = 1; + string config = 2; +} + +message LoadByNameWithConfigResult { + uint32 graph_handle = 1; +} + service Graph { // No support for Load yet rpc LoadByName(LoadByNameRequest) returns (LoadByNameResult) {}; + rpc LoadByNameWithConfig(LoadByNameWithConfigRequest) returns (LoadByNameWithConfigResult) {}; } message SetInputRequest { @@ -68,10 +78,17 @@ message GetOutputResult { bytes data = 1; // defined as a tensor in wit } +message FiniSingleRequest{ + uint32 resource_handle = 1; +} + service GraphExecutionContextResource { rpc SetInput(SetInputRequest) returns (google.protobuf.Empty) {}; rpc Compute(ComputeRequest) returns (google.protobuf.Empty) {}; + rpc ComputeSingle(ComputeRequest) returns (google.protobuf.Empty) {}; rpc GetOutput(GetOutputRequest) returns (GetOutputResult) {}; + rpc GetOutputSingle(GetOutputRequest) returns (GetOutputResult) {}; + rpc FiniSingle(FiniSingleRequest) returns (google.protobuf.Empty) {}; } // ref: diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index abe3e8e6c78e..8f57a5fa749b 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -1,14 +1,51 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC +# WASI plug-in: WASI-Crypto proposal. +if(WASMEDGE_PLUGIN_WASI_CRYPTO) + add_subdirectory(wasi_crypto) +endif() + +# WASI plug-in: WASI-Http proposal. +if(WASMEDGE_PLUGIN_WASI_HTTP) + add_subdirectory(wasi_http) +endif() + +# WASI plug-in: WASI-Logging proposal. +if(WASMEDGE_PLUGIN_WASI_LOGGING) + # BUILTIN-PLUGIN: Add the wasi-logging plugin here after the new plugin + # architecture ready in 0.15.0. +endif() + +# WASI plug-in: WASI-NN proposal with backends. if(WASMEDGE_PLUGIN_WASI_NN_BACKEND) add_subdirectory(wasi_nn) endif() +if(WASMEDGE_PLUGIN_WASI_NN_BURNRS_MODEL) + add_subdirectory(wasi_nn_burnrs) +endif() -if(WASMEDGE_PLUGIN_WASI_CRYPTO) - add_subdirectory(wasi_crypto) +# WASI plug-in: WASI-Poll proposal. +if(WASMEDGE_PLUGIN_WASI_POLL) + add_subdirectory(wasi_poll) +endif() + +# WasmEdge plug-in: wasm-bpf. +if(WASMEDGE_PLUGIN_WASM_BPF) + # Only Linux systems support wasm_bpf now. + if(CMAKE_SYSTEM_NAME MATCHES "Linux") + add_subdirectory(wasm_bpf) + else() + message(WARNING "Only Linux platforms support wasm_bpf plug-in now.") + endif() +endif() + +# WasmEdge plug-in: ffmpeg. +if(WASMEDGE_PLUGIN_FFMPEG) + add_subdirectory(wasmedge_ffmpeg) endif() +# WasmEdge plug-in: Image. if(WASMEDGE_PLUGIN_IMAGE) # Only Linux and MacOS support wasmedge_image now. if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") @@ -18,24 +55,27 @@ if(WASMEDGE_PLUGIN_IMAGE) endif() endif() -if(WASMEDGE_PLUGIN_TENSORFLOW) - # Only Linux and MacOS support wasmedge_tensorflow now. - if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") - add_subdirectory(wasmedge_tensorflow) - else() - message(WARNING "Only Linux and Darwin platforms support WasmEdge_Tensorflow plug-in now.") - endif() +# WasmEdge plug-in: LLMC. +if(WASMEDGE_PLUGIN_LLMC) + add_subdirectory(wasmedge_llmc) endif() -if(WASMEDGE_PLUGIN_TENSORFLOWLITE) - # Only Linux and MacOS support wasmedge_tensorflowlite now. +# WasmEdge plug-in: OCR. +if(WASMEDGE_PLUGIN_OCR) + add_subdirectory(wasmedge_ocr) +endif() + +# WasmEdge plug-in: OpenCV-mini. +if(WASMEDGE_PLUGIN_OPENCVMINI) + # Only Linux and MacOS support wasmedge_opencvmini now. if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") - add_subdirectory(wasmedge_tensorflowlite) + add_subdirectory(wasmedge_opencvmini) else() - message(WARNING "Only Linux and Darwin platforms support WasmEdge_TensorflowLite plug-in now.") + message(WARNING "Only Linux and Darwin platforms support WasmEdge_OpenCVMini plug-in now.") endif() endif() +# WasmEdge plug-in: Process. if(WASMEDGE_PLUGIN_PROCESS) # Only Linux systems support wasmedge_process now. if(CMAKE_SYSTEM_NAME MATCHES "Linux") @@ -45,32 +85,37 @@ if(WASMEDGE_PLUGIN_PROCESS) endif() endif() -if(WASMEDGE_PLUGIN_WASM_BPF) - # Only Linux systems support wasm_bpf now. - if(CMAKE_SYSTEM_NAME MATCHES "Linux") - add_subdirectory(wasm_bpf) +# WasmEdge plug-in: Stable-diffusion. +if(WASMEDGE_PLUGIN_STABLEDIFFUSION) + # Only Linux and MacOS support wasmedge_stablediffusion now. + if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") + add_subdirectory(wasmedge_stablediffusion) else() - message(WARNING "Only Linux platforms support wasm_bpf plug-in now.") + message(WARNING "Only Linux and Darwin platforms support WasmEdge_StableDiffusion plug-in now.") endif() endif() -if(WASMEDGE_PLUGIN_OPENCVMINI) - # Only Linux and MacOS support wasmedge_opencvmini now. +# WasmEdge plug-in: TensorFlow. +if(WASMEDGE_PLUGIN_TENSORFLOW) + # Only Linux and MacOS support wasmedge_tensorflow now. if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") - add_subdirectory(wasmedge_opencvmini) + add_subdirectory(wasmedge_tensorflow) else() - message(WARNING "Only Linux and Darwin platforms support WasmEdge_OpenCVMini plug-in now.") + message(WARNING "Only Linux and Darwin platforms support WasmEdge_Tensorflow plug-in now.") endif() endif() -if(WASMEDGE_PLUGIN_WASI_LOGGING) - add_subdirectory(wasi_logging) -endif() - -if(WASMEDGE_PLUGIN_RUSTLS) - add_subdirectory(wasmedge_rustls) +# WasmEdge plug-in: TensorFlow-Lite. +if(WASMEDGE_PLUGIN_TENSORFLOWLITE) + # Only Linux and MacOS support wasmedge_tensorflowlite now. + if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") + add_subdirectory(wasmedge_tensorflowlite) + else() + message(WARNING "Only Linux and Darwin platforms support WasmEdge_TensorflowLite plug-in now.") + endif() endif() +# WasmEdge plug-in: zlib. if(WASMEDGE_PLUGIN_ZLIB) add_subdirectory(wasmedge_zlib) endif() diff --git a/plugins/wasi_crypto/CMakeLists.txt b/plugins/wasi_crypto/CMakeLists.txt index 70ae211e219a..cc8c8dbe5807 100644 --- a/plugins/wasi_crypto/CMakeLists.txt +++ b/plugins/wasi_crypto/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC set(OPENSSL_USE_STATIC_LIBS ON) find_package(OpenSSL REQUIRED) @@ -79,4 +79,7 @@ else() ) endif() -install(TARGETS wasmedgePluginWasiCrypto DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge) +install( + TARGETS wasmedgePluginWasiCrypto + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) diff --git a/plugins/wasi_crypto/asymmetric_common/ctx.cpp b/plugins/wasi_crypto/asymmetric_common/ctx.cpp index 551bd5ccd008..4e94a3fd6a8a 100644 --- a/plugins/wasi_crypto/asymmetric_common/ctx.cpp +++ b/plugins/wasi_crypto/asymmetric_common/ctx.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "ctx.h" diff --git a/plugins/wasi_crypto/asymmetric_common/ecdsa.h b/plugins/wasi_crypto/asymmetric_common/ecdsa.h index 5e170cf083b2..ee351b8a2889 100644 --- a/plugins/wasi_crypto/asymmetric_common/ecdsa.h +++ b/plugins/wasi_crypto/asymmetric_common/ecdsa.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/asymmetric_common/ecdsa.h - Ecdsa alg-===// // diff --git a/plugins/wasi_crypto/asymmetric_common/func.cpp b/plugins/wasi_crypto/asymmetric_common/func.cpp index 6f70f521c4e3..698f72a6c68c 100644 --- a/plugins/wasi_crypto/asymmetric_common/func.cpp +++ b/plugins/wasi_crypto/asymmetric_common/func.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "asymmetric_common/func.h" diff --git a/plugins/wasi_crypto/asymmetric_common/func.h b/plugins/wasi_crypto/asymmetric_common/func.h index 1157751bf16d..3c5411a55a03 100644 --- a/plugins/wasi_crypto/asymmetric_common/func.h +++ b/plugins/wasi_crypto/asymmetric_common/func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/asymmetric_common/func.h -------------===// // diff --git a/plugins/wasi_crypto/asymmetric_common/keypair.cpp b/plugins/wasi_crypto/asymmetric_common/keypair.cpp index ec543c1014cd..e3881524f00f 100644 --- a/plugins/wasi_crypto/asymmetric_common/keypair.cpp +++ b/plugins/wasi_crypto/asymmetric_common/keypair.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "asymmetric_common/keypair.h" diff --git a/plugins/wasi_crypto/asymmetric_common/keypair.h b/plugins/wasi_crypto/asymmetric_common/keypair.h index 65a32172d80a..0016b6121745 100644 --- a/plugins/wasi_crypto/asymmetric_common/keypair.h +++ b/plugins/wasi_crypto/asymmetric_common/keypair.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/asymmetric_common/keypair.h ----------===// // diff --git a/plugins/wasi_crypto/asymmetric_common/module.cpp b/plugins/wasi_crypto/asymmetric_common/module.cpp index 816f22323f37..ed3b34488d9d 100644 --- a/plugins/wasi_crypto/asymmetric_common/module.cpp +++ b/plugins/wasi_crypto/asymmetric_common/module.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "asymmetric_common/module.h" #include "asymmetric_common/func.h" diff --git a/plugins/wasi_crypto/asymmetric_common/module.h b/plugins/wasi_crypto/asymmetric_common/module.h index 4e5281afdadf..9aa39cf4ca8b 100644 --- a/plugins/wasi_crypto/asymmetric_common/module.h +++ b/plugins/wasi_crypto/asymmetric_common/module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/asymmetric_common/module.h - Asym ----===// // diff --git a/plugins/wasi_crypto/asymmetric_common/publickey.cpp b/plugins/wasi_crypto/asymmetric_common/publickey.cpp index 5e9f1baef8f4..2ee7d84a4257 100644 --- a/plugins/wasi_crypto/asymmetric_common/publickey.cpp +++ b/plugins/wasi_crypto/asymmetric_common/publickey.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "asymmetric_common/publickey.h" diff --git a/plugins/wasi_crypto/asymmetric_common/publickey.h b/plugins/wasi_crypto/asymmetric_common/publickey.h index 1e4915cb86c5..5e50efddb07d 100644 --- a/plugins/wasi_crypto/asymmetric_common/publickey.h +++ b/plugins/wasi_crypto/asymmetric_common/publickey.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/asymmetric_common/publickey.h --------===// // diff --git a/plugins/wasi_crypto/asymmetric_common/registered.h b/plugins/wasi_crypto/asymmetric_common/registered.h index 989130ac6f47..f74cb0a04fba 100644 --- a/plugins/wasi_crypto/asymmetric_common/registered.h +++ b/plugins/wasi_crypto/asymmetric_common/registered.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/asymmetric/registered.h - Registered -===// // diff --git a/plugins/wasi_crypto/asymmetric_common/secretkey.cpp b/plugins/wasi_crypto/asymmetric_common/secretkey.cpp index f76b2180190b..55f518e7f620 100644 --- a/plugins/wasi_crypto/asymmetric_common/secretkey.cpp +++ b/plugins/wasi_crypto/asymmetric_common/secretkey.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "asymmetric_common/secretkey.h" diff --git a/plugins/wasi_crypto/asymmetric_common/secretkey.h b/plugins/wasi_crypto/asymmetric_common/secretkey.h index 25115a8b5449..b9f3ec59c1d7 100644 --- a/plugins/wasi_crypto/asymmetric_common/secretkey.h +++ b/plugins/wasi_crypto/asymmetric_common/secretkey.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/asymmetric_common/secretkey.h --------===// // diff --git a/plugins/wasi_crypto/common/array_output.cpp b/plugins/wasi_crypto/common/array_output.cpp index 79ec82e7bc9e..8f25327e96a4 100644 --- a/plugins/wasi_crypto/common/array_output.cpp +++ b/plugins/wasi_crypto/common/array_output.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/array_output.h" diff --git a/plugins/wasi_crypto/common/array_output.h b/plugins/wasi_crypto/common/array_output.h index 51238281e330..f5fef5c89afb 100644 --- a/plugins/wasi_crypto/common/array_output.h +++ b/plugins/wasi_crypto/common/array_output.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/common/array_output.h - ArrayOutput --===// // diff --git a/plugins/wasi_crypto/common/ctx.cpp b/plugins/wasi_crypto/common/ctx.cpp index 03996922ebf6..7c8e76b157c1 100644 --- a/plugins/wasi_crypto/common/ctx.cpp +++ b/plugins/wasi_crypto/common/ctx.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "ctx.h" #include "common/array_output.h" diff --git a/plugins/wasi_crypto/common/func.cpp b/plugins/wasi_crypto/common/func.cpp index e8dcc9814cda..37bfb29faa59 100644 --- a/plugins/wasi_crypto/common/func.cpp +++ b/plugins/wasi_crypto/common/func.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/func.h" diff --git a/plugins/wasi_crypto/common/func.h b/plugins/wasi_crypto/common/func.h index d29a9f3e3f9c..e546672dedb0 100644 --- a/plugins/wasi_crypto/common/func.h +++ b/plugins/wasi_crypto/common/func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/common/func.h - Common func ----------===// // diff --git a/plugins/wasi_crypto/common/module.cpp b/plugins/wasi_crypto/common/module.cpp index bbb0107b8484..9cdfd46dd3ed 100644 --- a/plugins/wasi_crypto/common/module.cpp +++ b/plugins/wasi_crypto/common/module.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/module.h" #include "common/func.h" diff --git a/plugins/wasi_crypto/common/module.h b/plugins/wasi_crypto/common/module.h index cfa05726cf81..75a1bc111e97 100644 --- a/plugins/wasi_crypto/common/module.h +++ b/plugins/wasi_crypto/common/module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/common/module.h - Common Module ------===// // diff --git a/plugins/wasi_crypto/common/options.cpp b/plugins/wasi_crypto/common/options.cpp index f93f2fe069de..e95aefa2ef5e 100644 --- a/plugins/wasi_crypto/common/options.cpp +++ b/plugins/wasi_crypto/common/options.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/options.h" diff --git a/plugins/wasi_crypto/common/options.h b/plugins/wasi_crypto/common/options.h index de22b64dd06b..e07578c1442b 100644 --- a/plugins/wasi_crypto/common/options.h +++ b/plugins/wasi_crypto/common/options.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/common/options.h - Options definition ===// // diff --git a/plugins/wasi_crypto/ctx.cpp b/plugins/wasi_crypto/ctx.cpp index 7ff586f68d9d..7c7d68118541 100644 --- a/plugins/wasi_crypto/ctx.cpp +++ b/plugins/wasi_crypto/ctx.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "ctx.h" #include "asymmetric_common/module.h" @@ -72,9 +72,10 @@ Plugin::Plugin::PluginDescriptor Descriptor{ .AddOptions = nullptr, }; +EXPORT_GET_DESCRIPTOR(Descriptor) + } // namespace -Plugin::PluginRegister WasiCrypto::Context::Register(&Descriptor); std::shared_mutex WasiCrypto::Context::Mutex; std::weak_ptr<WasiCrypto::Context> WasiCrypto::Context::Instance; diff --git a/plugins/wasi_crypto/ctx.h b/plugins/wasi_crypto/ctx.h index f5eda8a74c64..caa5bdf4ee68 100644 --- a/plugins/wasi_crypto/ctx.h +++ b/plugins/wasi_crypto/ctx.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/ctx.h - Context class definition -----===// // @@ -358,7 +358,6 @@ class Context { static std::shared_mutex Mutex; static std::weak_ptr<Context> Instance; - static Plugin::PluginRegister Register; }; } // namespace WasiCrypto diff --git a/plugins/wasi_crypto/kx/ctx.cpp b/plugins/wasi_crypto/kx/ctx.cpp index f5bb349b33f2..86f7646a1a73 100644 --- a/plugins/wasi_crypto/kx/ctx.cpp +++ b/plugins/wasi_crypto/kx/ctx.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "ctx.h" #include "kx/kx.h" diff --git a/plugins/wasi_crypto/kx/dh/ecdsa.cpp b/plugins/wasi_crypto/kx/dh/ecdsa.cpp index ef4536a69683..a228cfe8c81d 100644 --- a/plugins/wasi_crypto/kx/dh/ecdsa.cpp +++ b/plugins/wasi_crypto/kx/dh/ecdsa.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "kx/dh/ecdsa.h" diff --git a/plugins/wasi_crypto/kx/dh/ecdsa.h b/plugins/wasi_crypto/kx/dh/ecdsa.h index d15cbb3c7301..f41cd63bc778 100644 --- a/plugins/wasi_crypto/kx/dh/ecdsa.h +++ b/plugins/wasi_crypto/kx/dh/ecdsa.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/kx/dh/ecdsa.h - Ecdsa alg implement --===// // diff --git a/plugins/wasi_crypto/kx/dh/x25519.cpp b/plugins/wasi_crypto/kx/dh/x25519.cpp index a2460217b494..53d87a7295a6 100644 --- a/plugins/wasi_crypto/kx/dh/x25519.cpp +++ b/plugins/wasi_crypto/kx/dh/x25519.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "kx/dh/x25519.h" diff --git a/plugins/wasi_crypto/kx/dh/x25519.h b/plugins/wasi_crypto/kx/dh/x25519.h index f598b0264868..806d6dd7a246 100644 --- a/plugins/wasi_crypto/kx/dh/x25519.h +++ b/plugins/wasi_crypto/kx/dh/x25519.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/kx/dh/x25519.h - X25519 alg implement ===// // diff --git a/plugins/wasi_crypto/kx/func.cpp b/plugins/wasi_crypto/kx/func.cpp index 0cdd305d733d..4649c278b855 100644 --- a/plugins/wasi_crypto/kx/func.cpp +++ b/plugins/wasi_crypto/kx/func.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "kx/func.h" diff --git a/plugins/wasi_crypto/kx/func.h b/plugins/wasi_crypto/kx/func.h index c0f83789deb6..3f1040c06832 100644 --- a/plugins/wasi_crypto/kx/func.h +++ b/plugins/wasi_crypto/kx/func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/kx/func.h - Key Exchange funcs -------===// // diff --git a/plugins/wasi_crypto/kx/kx.cpp b/plugins/wasi_crypto/kx/kx.cpp index cd785fc530e3..79d98e9a5d86 100644 --- a/plugins/wasi_crypto/kx/kx.cpp +++ b/plugins/wasi_crypto/kx/kx.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "kx/kx.h" diff --git a/plugins/wasi_crypto/kx/kx.h b/plugins/wasi_crypto/kx/kx.h index eba5a4c39b41..5004ebe93035 100644 --- a/plugins/wasi_crypto/kx/kx.h +++ b/plugins/wasi_crypto/kx/kx.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/kx/kx.h - Key Exchange related -------===// // diff --git a/plugins/wasi_crypto/kx/module.cpp b/plugins/wasi_crypto/kx/module.cpp index 38f35cf6378c..12dff8779b21 100644 --- a/plugins/wasi_crypto/kx/module.cpp +++ b/plugins/wasi_crypto/kx/module.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "kx/module.h" #include "kx/func.h" diff --git a/plugins/wasi_crypto/kx/module.h b/plugins/wasi_crypto/kx/module.h index 85992f0a5054..aa3ea512fab2 100644 --- a/plugins/wasi_crypto/kx/module.h +++ b/plugins/wasi_crypto/kx/module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/kx/module.h - Kx Module --------------===// // diff --git a/plugins/wasi_crypto/kx/options.cpp b/plugins/wasi_crypto/kx/options.cpp index da383199e7e9..c2612e2436c9 100644 --- a/plugins/wasi_crypto/kx/options.cpp +++ b/plugins/wasi_crypto/kx/options.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "kx/options.h" diff --git a/plugins/wasi_crypto/kx/options.h b/plugins/wasi_crypto/kx/options.h index 4074579cb7c9..83fb85d330a3 100644 --- a/plugins/wasi_crypto/kx/options.h +++ b/plugins/wasi_crypto/kx/options.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/kx/options.h - Key exchange Options --===// // diff --git a/plugins/wasi_crypto/kx/registered.h b/plugins/wasi_crypto/kx/registered.h index 655fc3929a40..6020f3b95501 100644 --- a/plugins/wasi_crypto/kx/registered.h +++ b/plugins/wasi_crypto/kx/registered.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/kx/registered.h - Registered ---------===// // diff --git a/plugins/wasi_crypto/signatures/ctx.cpp b/plugins/wasi_crypto/signatures/ctx.cpp index 17070d449d5c..ea85c965b566 100644 --- a/plugins/wasi_crypto/signatures/ctx.cpp +++ b/plugins/wasi_crypto/signatures/ctx.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "ctx.h" #include "signatures/signatures.h" diff --git a/plugins/wasi_crypto/signatures/ecdsa.cpp b/plugins/wasi_crypto/signatures/ecdsa.cpp index f295910c0c84..e7b2162e6486 100644 --- a/plugins/wasi_crypto/signatures/ecdsa.cpp +++ b/plugins/wasi_crypto/signatures/ecdsa.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "signatures/ecdsa.h" diff --git a/plugins/wasi_crypto/signatures/ecdsa.h b/plugins/wasi_crypto/signatures/ecdsa.h index 4c8e373efb56..41c0d27c5993 100644 --- a/plugins/wasi_crypto/signatures/ecdsa.h +++ b/plugins/wasi_crypto/signatures/ecdsa.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/signatures/ecdsa.h - Ecdsa alg -------===// // diff --git a/plugins/wasi_crypto/signatures/eddsa.cpp b/plugins/wasi_crypto/signatures/eddsa.cpp index 820204b816e0..d1a44f24df71 100644 --- a/plugins/wasi_crypto/signatures/eddsa.cpp +++ b/plugins/wasi_crypto/signatures/eddsa.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "signatures/eddsa.h" diff --git a/plugins/wasi_crypto/signatures/eddsa.h b/plugins/wasi_crypto/signatures/eddsa.h index 70a1753896da..996744084bd3 100644 --- a/plugins/wasi_crypto/signatures/eddsa.h +++ b/plugins/wasi_crypto/signatures/eddsa.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/signatures/eddsa.h - Eddsa alg -------===// // diff --git a/plugins/wasi_crypto/signatures/func.cpp b/plugins/wasi_crypto/signatures/func.cpp index 8a5b6510dc3e..18e6905c643d 100644 --- a/plugins/wasi_crypto/signatures/func.cpp +++ b/plugins/wasi_crypto/signatures/func.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "signatures/func.h" diff --git a/plugins/wasi_crypto/signatures/func.h b/plugins/wasi_crypto/signatures/func.h index 56683080f9b1..f1b8b8a7ce42 100644 --- a/plugins/wasi_crypto/signatures/func.h +++ b/plugins/wasi_crypto/signatures/func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/signatures/func.h - Signatures func --===// // diff --git a/plugins/wasi_crypto/signatures/module.cpp b/plugins/wasi_crypto/signatures/module.cpp index 44a3fef7bcde..36d08b2ae6fd 100644 --- a/plugins/wasi_crypto/signatures/module.cpp +++ b/plugins/wasi_crypto/signatures/module.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "module.h" #include "asymmetric_common/func.h" diff --git a/plugins/wasi_crypto/signatures/module.h b/plugins/wasi_crypto/signatures/module.h index 71e8540ffb8e..1296fff4d816 100644 --- a/plugins/wasi_crypto/signatures/module.h +++ b/plugins/wasi_crypto/signatures/module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/signatures/module.h - Module ---------===// // diff --git a/plugins/wasi_crypto/signatures/options.cpp b/plugins/wasi_crypto/signatures/options.cpp index 761ca439e2bd..d4de6cf394c7 100644 --- a/plugins/wasi_crypto/signatures/options.cpp +++ b/plugins/wasi_crypto/signatures/options.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "signatures/options.h" diff --git a/plugins/wasi_crypto/signatures/options.h b/plugins/wasi_crypto/signatures/options.h index a229dc9b5513..895c5d9f599b 100644 --- a/plugins/wasi_crypto/signatures/options.h +++ b/plugins/wasi_crypto/signatures/options.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/signatures/options.h - Options -------===// // diff --git a/plugins/wasi_crypto/signatures/registered.h b/plugins/wasi_crypto/signatures/registered.h index 5d436ea35213..06dcd0d0d222 100644 --- a/plugins/wasi_crypto/signatures/registered.h +++ b/plugins/wasi_crypto/signatures/registered.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/signatures/registered.h - Registered //-----===// diff --git a/plugins/wasi_crypto/signatures/rsa.cpp b/plugins/wasi_crypto/signatures/rsa.cpp index 6e7fc8f02978..245fe9ed96eb 100644 --- a/plugins/wasi_crypto/signatures/rsa.cpp +++ b/plugins/wasi_crypto/signatures/rsa.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "signatures/rsa.h" diff --git a/plugins/wasi_crypto/signatures/rsa.h b/plugins/wasi_crypto/signatures/rsa.h index 85c9b312f6be..878324ae0885 100644 --- a/plugins/wasi_crypto/signatures/rsa.h +++ b/plugins/wasi_crypto/signatures/rsa.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/signatures/rsa.h - Rsa alg implement -===// // diff --git a/plugins/wasi_crypto/signatures/signatures.cpp b/plugins/wasi_crypto/signatures/signatures.cpp index 29fae93a4cea..ae3b003ed8a1 100644 --- a/plugins/wasi_crypto/signatures/signatures.cpp +++ b/plugins/wasi_crypto/signatures/signatures.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "signatures/signatures.h" diff --git a/plugins/wasi_crypto/signatures/signatures.h b/plugins/wasi_crypto/signatures/signatures.h index 6e548c0f1b04..d2bd2bbb6d3c 100644 --- a/plugins/wasi_crypto/signatures/signatures.h +++ b/plugins/wasi_crypto/signatures/signatures.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/signatures/signatures.h - Signatures -===// // diff --git a/plugins/wasi_crypto/signatures/signstate.cpp b/plugins/wasi_crypto/signatures/signstate.cpp index bf12ddbc8c43..a8c45707bf81 100644 --- a/plugins/wasi_crypto/signatures/signstate.cpp +++ b/plugins/wasi_crypto/signatures/signstate.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "signatures/signstate.h" diff --git a/plugins/wasi_crypto/signatures/signstate.h b/plugins/wasi_crypto/signatures/signstate.h index 02fcd7a56c5e..5ed5f61da1b8 100644 --- a/plugins/wasi_crypto/signatures/signstate.h +++ b/plugins/wasi_crypto/signatures/signstate.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/signatures/signstate.h - SignState ---===// // diff --git a/plugins/wasi_crypto/signatures/verificationstate.cpp b/plugins/wasi_crypto/signatures/verificationstate.cpp index 547bbdb83c31..3f4593efeb19 100644 --- a/plugins/wasi_crypto/signatures/verificationstate.cpp +++ b/plugins/wasi_crypto/signatures/verificationstate.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "signatures/verificationstate.h" diff --git a/plugins/wasi_crypto/signatures/verificationstate.h b/plugins/wasi_crypto/signatures/verificationstate.h index 3e326daac118..81e612f11ad1 100644 --- a/plugins/wasi_crypto/signatures/verificationstate.h +++ b/plugins/wasi_crypto/signatures/verificationstate.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/signatures/verificationstate.h -------===// // diff --git a/plugins/wasi_crypto/symmetric/aeads.cpp b/plugins/wasi_crypto/symmetric/aeads.cpp index 08ba7658e555..15f7d1275400 100644 --- a/plugins/wasi_crypto/symmetric/aeads.cpp +++ b/plugins/wasi_crypto/symmetric/aeads.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "symmetric/aeads.h" #include "utils/error.h" diff --git a/plugins/wasi_crypto/symmetric/aeads.h b/plugins/wasi_crypto/symmetric/aeads.h index 96d6b245c56d..4e580485ea13 100644 --- a/plugins/wasi_crypto/symmetric/aeads.h +++ b/plugins/wasi_crypto/symmetric/aeads.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/symmetric/aeads.h - Aeads related ----===// // diff --git a/plugins/wasi_crypto/symmetric/ctx.cpp b/plugins/wasi_crypto/symmetric/ctx.cpp index 4afa2351582f..542634173b63 100644 --- a/plugins/wasi_crypto/symmetric/ctx.cpp +++ b/plugins/wasi_crypto/symmetric/ctx.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "ctx.h" #include "symmetric/key.h" diff --git a/plugins/wasi_crypto/symmetric/func.cpp b/plugins/wasi_crypto/symmetric/func.cpp index 47abba79baa6..24ceb43ae2bd 100644 --- a/plugins/wasi_crypto/symmetric/func.cpp +++ b/plugins/wasi_crypto/symmetric/func.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "symmetric/func.h" diff --git a/plugins/wasi_crypto/symmetric/func.h b/plugins/wasi_crypto/symmetric/func.h index a122784f78b5..eded49a3ea16 100644 --- a/plugins/wasi_crypto/symmetric/func.h +++ b/plugins/wasi_crypto/symmetric/func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/symmetric/func.h - Symmetric funcs ---===// // diff --git a/plugins/wasi_crypto/symmetric/hash.cpp b/plugins/wasi_crypto/symmetric/hash.cpp index ea2129b5058a..2e80f856d8f6 100644 --- a/plugins/wasi_crypto/symmetric/hash.cpp +++ b/plugins/wasi_crypto/symmetric/hash.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "symmetric/hash.h" #include "utils/evp_wrapper.h" diff --git a/plugins/wasi_crypto/symmetric/hash.h b/plugins/wasi_crypto/symmetric/hash.h index 66934da54da4..59257a42e569 100644 --- a/plugins/wasi_crypto/symmetric/hash.h +++ b/plugins/wasi_crypto/symmetric/hash.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/symmetric/hash.h - Hash related ------===// // diff --git a/plugins/wasi_crypto/symmetric/kdf.h b/plugins/wasi_crypto/symmetric/kdf.h index 73c8897cf2c0..4834f385d208 100644 --- a/plugins/wasi_crypto/symmetric/kdf.h +++ b/plugins/wasi_crypto/symmetric/kdf.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/symmetric/kdf.h - Kdf related --------===// // diff --git a/plugins/wasi_crypto/symmetric/key.cpp b/plugins/wasi_crypto/symmetric/key.cpp index 33797042e537..970d1ace137e 100644 --- a/plugins/wasi_crypto/symmetric/key.cpp +++ b/plugins/wasi_crypto/symmetric/key.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "symmetric/key.h" #include "utils/error.h" diff --git a/plugins/wasi_crypto/symmetric/key.h b/plugins/wasi_crypto/symmetric/key.h index bf2d8745e23f..d7e4aa6d4706 100644 --- a/plugins/wasi_crypto/symmetric/key.h +++ b/plugins/wasi_crypto/symmetric/key.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/symmetric/key.h - Symmetric Key class ===// // diff --git a/plugins/wasi_crypto/symmetric/mac.cpp b/plugins/wasi_crypto/symmetric/mac.cpp index 53c7e2eef9e2..2b0bab771b9e 100644 --- a/plugins/wasi_crypto/symmetric/mac.cpp +++ b/plugins/wasi_crypto/symmetric/mac.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "symmetric/mac.h" #include "utils/secret_vec.h" diff --git a/plugins/wasi_crypto/symmetric/mac.h b/plugins/wasi_crypto/symmetric/mac.h index f1247b95da3f..57fa5d435fd8 100644 --- a/plugins/wasi_crypto/symmetric/mac.h +++ b/plugins/wasi_crypto/symmetric/mac.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/symmetric/mac.h - Mac related --------===// // diff --git a/plugins/wasi_crypto/symmetric/module.cpp b/plugins/wasi_crypto/symmetric/module.cpp index 402c4b196e76..01540cf88658 100644 --- a/plugins/wasi_crypto/symmetric/module.cpp +++ b/plugins/wasi_crypto/symmetric/module.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "symmetric/module.h" #include "symmetric/func.h" diff --git a/plugins/wasi_crypto/symmetric/module.h b/plugins/wasi_crypto/symmetric/module.h index af4f23d49c22..1405235971f5 100644 --- a/plugins/wasi_crypto/symmetric/module.h +++ b/plugins/wasi_crypto/symmetric/module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/symmetric/module.h - Module ----------===// // diff --git a/plugins/wasi_crypto/symmetric/options.cpp b/plugins/wasi_crypto/symmetric/options.cpp index 22309e57bbd0..ae2b3c5f602d 100644 --- a/plugins/wasi_crypto/symmetric/options.cpp +++ b/plugins/wasi_crypto/symmetric/options.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "symmetric/options.h" @@ -18,7 +18,7 @@ constexpr std::array<std::string_view, 3> ValidNames{"context"sv, "salt"sv, std::string toLower(std::string_view Name) noexcept { std::string Ret{Name}; std::transform(Ret.begin(), Ret.end(), Ret.begin(), - [](char C) { return std::tolower(C); }); + [](char C) { return static_cast<char>(std::tolower(C)); }); return Ret; } diff --git a/plugins/wasi_crypto/symmetric/options.h b/plugins/wasi_crypto/symmetric/options.h index 9d0a6ec3010a..7e7d1bd1b9a6 100644 --- a/plugins/wasi_crypto/symmetric/options.h +++ b/plugins/wasi_crypto/symmetric/options.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/symmetric/options.h - Options --------===// // diff --git a/plugins/wasi_crypto/symmetric/registered.h b/plugins/wasi_crypto/symmetric/registered.h index 0785fc6cf3c2..2bf5a622bc1b 100644 --- a/plugins/wasi_crypto/symmetric/registered.h +++ b/plugins/wasi_crypto/symmetric/registered.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/symmetric/registered.h - Registered --===// // diff --git a/plugins/wasi_crypto/symmetric/state.cpp b/plugins/wasi_crypto/symmetric/state.cpp index 77852f587e19..c759d219b038 100644 --- a/plugins/wasi_crypto/symmetric/state.cpp +++ b/plugins/wasi_crypto/symmetric/state.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "symmetric/state.h" #include "utils/error.h" diff --git a/plugins/wasi_crypto/symmetric/state.h b/plugins/wasi_crypto/symmetric/state.h index d567cf2eb748..9759753e582d 100644 --- a/plugins/wasi_crypto/symmetric/state.h +++ b/plugins/wasi_crypto/symmetric/state.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/symmetric/state.h - Symmetric State --===// // diff --git a/plugins/wasi_crypto/symmetric/tag.cpp b/plugins/wasi_crypto/symmetric/tag.cpp index 2fee4fb99a95..3998aee283be 100644 --- a/plugins/wasi_crypto/symmetric/tag.cpp +++ b/plugins/wasi_crypto/symmetric/tag.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "symmetric/tag.h" diff --git a/plugins/wasi_crypto/symmetric/tag.h b/plugins/wasi_crypto/symmetric/tag.h index 5d2f3fad271b..9daa458ba71e 100644 --- a/plugins/wasi_crypto/symmetric/tag.h +++ b/plugins/wasi_crypto/symmetric/tag.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/symmetric/tag.h - Symmetric Tag class ===// // diff --git a/plugins/wasi_crypto/utils/error.h b/plugins/wasi_crypto/utils/error.h index ba1bc1fcadc1..24018755cd78 100644 --- a/plugins/wasi_crypto/utils/error.h +++ b/plugins/wasi_crypto/utils/error.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/utils/error.h - Error definition -----===// // diff --git a/plugins/wasi_crypto/utils/evp_wrapper.cpp b/plugins/wasi_crypto/utils/evp_wrapper.cpp index e5badb146ed9..a28f96650eab 100644 --- a/plugins/wasi_crypto/utils/evp_wrapper.cpp +++ b/plugins/wasi_crypto/utils/evp_wrapper.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "utils/evp_wrapper.h" #include "utils/error.h" diff --git a/plugins/wasi_crypto/utils/evp_wrapper.h b/plugins/wasi_crypto/utils/evp_wrapper.h index 67b4ecfbfd2d..893fb0e518cb 100644 --- a/plugins/wasi_crypto/utils/evp_wrapper.h +++ b/plugins/wasi_crypto/utils/evp_wrapper.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/utils/evp_wrapper.h - Evp Wrapper ----===// // @@ -17,8 +17,8 @@ #include "utils/error.h" #include "utils/secret_vec.h" -#include "common/log.h" #include "common/span.h" +#include "common/spdlog.h" #include <openssl/bio.h> #include <openssl/bn.h> diff --git a/plugins/wasi_crypto/utils/handles_manager.h b/plugins/wasi_crypto/utils/handles_manager.h index ba01f157989a..8eb456030da1 100644 --- a/plugins/wasi_crypto/utils/handles_manager.h +++ b/plugins/wasi_crypto/utils/handles_manager.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/utils/handles_manager.h --------------===// // @@ -48,7 +48,8 @@ template <typename HandleType, typename ManagerType> class BaseHandlesManager { BaseHandlesManager &operator=(BaseHandlesManager &&) noexcept = delete; /// @param TypeID A unique number - BaseHandlesManager(uint8_t TypeID) noexcept : LastHandle{TypeID, 0} {} + explicit BaseHandlesManager(uint8_t TypeID) noexcept + : LastHandle{TypeID, 0} {} WasiCryptoExpect<void> close(HandleType Handle) noexcept { std::unique_lock<std::shared_mutex> Lock{Mutex}; @@ -140,6 +141,8 @@ class RcHandlesManager ManagerType>::HandleWrapper; public: + using detail::BaseHandlesManager<HandleType, ManagerType>::BaseHandlesManager; + /// Get the return copy. WasiCryptoExpect<ManagerType> get(HandleType Handle) noexcept { std::shared_lock<std::shared_mutex> Lock{this->Mutex}; @@ -184,6 +187,8 @@ class RefHandlesManager ManagerType>::HandleWrapper; public: + using detail::BaseHandlesManager<HandleType, ManagerType>::BaseHandlesManager; + /// Get the return reference. WasiCryptoExpect<std::reference_wrapper<ManagerType>> get(HandleType Handle) noexcept { diff --git a/plugins/wasi_crypto/utils/hostfunction.cpp b/plugins/wasi_crypto/utils/hostfunction.cpp index b07c2be221b6..81c078a9cf28 100644 --- a/plugins/wasi_crypto/utils/hostfunction.cpp +++ b/plugins/wasi_crypto/utils/hostfunction.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "utils/hostfunction.h" diff --git a/plugins/wasi_crypto/utils/hostfunction.h b/plugins/wasi_crypto/utils/hostfunction.h index bbe58859609f..460130ebdd58 100644 --- a/plugins/wasi_crypto/utils/hostfunction.h +++ b/plugins/wasi_crypto/utils/hostfunction.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/hostfunc.h - HostFunction class ------===// // diff --git a/plugins/wasi_crypto/utils/optional.h b/plugins/wasi_crypto/utils/optional.h index ea8e93f6f390..85d06ad6dfb6 100644 --- a/plugins/wasi_crypto/utils/optional.h +++ b/plugins/wasi_crypto/utils/optional.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/utils/handles_manager.h - OptionalRef ===// // diff --git a/plugins/wasi_crypto/utils/secret_vec.h b/plugins/wasi_crypto/utils/secret_vec.h index a66bed9fb7fa..9e2d2f1b2083 100644 --- a/plugins/wasi_crypto/utils/secret_vec.h +++ b/plugins/wasi_crypto/utils/secret_vec.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/plugins/wasi_crypto/utils/secret_vec.h - Secret Vec def --===// // diff --git a/plugins/wasi_http/CMakeLists.txt b/plugins/wasi_http/CMakeLists.txt new file mode 100644 index 000000000000..3c7321fd4b74 --- /dev/null +++ b/plugins/wasi_http/CMakeLists.txt @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +include(FetchContent) +FetchContent_Declare(cpr GIT_REPOSITORY https://github.com/libcpr/cpr.git + GIT_TAG 3b15fa82ea74739b574d705fea44959b58142eb8) +FetchContent_MakeAvailable(cpr) + +wasmedge_add_library(wasmedgePluginWasiHttp + SHARED + env.cpp + func.cpp + module.cpp +) + +target_compile_options(wasmedgePluginWasiHttp + PUBLIC + -DWASMEDGE_PLUGIN +) + +target_include_directories(wasmedgePluginWasiHttp + PUBLIC + $<TARGET_PROPERTY:wasmedgePlugin,INCLUDE_DIRECTORIES> + ${CMAKE_CURRENT_SOURCE_DIR} + ${PROJECT_SOURCE_DIR}/thirdparty +) + +target_link_libraries(wasmedgePluginWasiHttp + PUBLIC + cpr::cpr +) + +if(WASMEDGE_LINK_PLUGINS_STATIC) + target_link_libraries(wasmedgePluginWasiHttp + PRIVATE + wasmedgeCAPI + ) +else() + target_link_libraries(wasmedgePluginWasiHttp + PRIVATE + wasmedge_shared + ) +endif() + +install( + TARGETS wasmedgePluginWasiHttp + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) diff --git a/plugins/wasi_http/README.md b/plugins/wasi_http/README.md new file mode 100644 index 000000000000..0074d4b80889 --- /dev/null +++ b/plugins/wasi_http/README.md @@ -0,0 +1,3 @@ +# wasi_http + +This is corresponding to [wasi-http preview2](https://github.com/WebAssembly/wasi-http), but a very beginning implementation, for now it's created to test component model. diff --git a/plugins/wasi_http/base.h b/plugins/wasi_http/base.h new file mode 100644 index 000000000000..0c5fdbd2cf4f --- /dev/null +++ b/plugins/wasi_http/base.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "env.h" + +#include "common/errcode.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { + +template <typename T> class WasiHttp : public Runtime::HostFunction<T> { +public: + WasiHttp(WasiHttpEnvironment &HostEnv) + : Runtime::HostFunction<T>(0), Env(HostEnv) {} + +protected: + WasiHttpEnvironment &Env; +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_http/env.cpp b/plugins/wasi_http/env.cpp new file mode 100644 index 000000000000..b0743d14bac8 --- /dev/null +++ b/plugins/wasi_http/env.cpp @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "env.h" +#include "module.h" + +namespace WasmEdge { +namespace Host { + +WasiHttpEnvironment::WasiHttpEnvironment() noexcept {} + +namespace { + +Runtime::Instance::ComponentInstance * +create(const Plugin::PluginComponent::ComponentDescriptor *) noexcept { + return new WasiHttpModule(); +} + +Plugin::Plugin::PluginDescriptor Descriptor{ + .Name = "wasi_http", + .Description = "", + .APIVersion = Plugin::Plugin::CurrentAPIVersion, + .Version = {0, 1, 0, 0}, + .ModuleCount = 0, + .ModuleDescriptions = {}, + .ComponentCount = 1, + .ComponentDescriptions = + (Plugin::PluginComponent::ComponentDescriptor[]){ + { + .Name = "wasi:http/test", + .Description = "", + .Create = create, + }, + }, + .AddOptions = nullptr, +}; + +EXPORT_GET_DESCRIPTOR(Descriptor) + +} // namespace +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_http/env.h b/plugins/wasi_http/env.h new file mode 100644 index 000000000000..2df43a2ba047 --- /dev/null +++ b/plugins/wasi_http/env.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC +#pragma once + +#include "plugin/plugin.h" + +#include <cstdint> +#include <vector> + +namespace WasmEdge { +namespace Host { + +class WasiHttpEnvironment { +public: + WasiHttpEnvironment() noexcept; +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_http/func.cpp b/plugins/wasi_http/func.cpp new file mode 100644 index 000000000000..f00b2121a3eb --- /dev/null +++ b/plugins/wasi_http/func.cpp @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "func.h" +#include "common/defines.h" +#include "common/errcode.h" + +#include <cpr/cpr.h> +#include <cstdint> +#include <string> +#include <vector> + +namespace WasmEdge { +namespace Host { + +Expect<void> WasiHttpPrint::body(const Runtime::CallingFrame &, + StrVariant Str) { + spdlog::info("[WASI-HTTP] print: {}", Str.getString()); + return {}; +} + +Expect<StrVariant> WasiHttpGet::body(const Runtime::CallingFrame &, + StrVariant URI) { + const auto &S = URI.getString(); + spdlog::info("[WASI-HTTP] URI: {}", S); + cpr::Response Res = cpr::Get( + cpr::Url{S}, cpr::Authentication{"user", "pass", cpr::AuthMode::BASIC}); + spdlog::info("[WASI-HTTP] status: {}", Res.status_code); + + return StrVariant(std::move(Res.text)); +} + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_http/func.h b/plugins/wasi_http/func.h new file mode 100644 index 000000000000..79ce1c835406 --- /dev/null +++ b/plugins/wasi_http/func.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { + +class WasiHttpPrint : public WasiHttp<WasiHttpPrint> { +public: + WasiHttpPrint(WasiHttpEnvironment &HostEnv) : WasiHttp(HostEnv) {} + Expect<void> body(const Runtime::CallingFrame &Frame, StrVariant Str); +}; + +class WasiHttpGet : public WasiHttp<WasiHttpGet> { +public: + WasiHttpGet(WasiHttpEnvironment &HostEnv) : WasiHttp(HostEnv) {} + Expect<StrVariant> body(const Runtime::CallingFrame &Frame, StrVariant URI); +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_http/module.cpp b/plugins/wasi_http/module.cpp new file mode 100644 index 000000000000..49fc4fb66593 --- /dev/null +++ b/plugins/wasi_http/module.cpp @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "module.h" +#include "func.h" + +#include <memory> + +namespace WasmEdge { +namespace Host { + +WasiHttpModule::WasiHttpModule() : ComponentInstance("wasi:http/test") { + addHostFunc("http-get", std::make_unique<WasiHttpGet>(Env)); + addHostFunc("print", std::make_unique<WasiHttpPrint>(Env)); +} + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_http/module.h b/plugins/wasi_http/module.h new file mode 100644 index 000000000000..93bb8776bed8 --- /dev/null +++ b/plugins/wasi_http/module.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "env.h" + +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { + +class WasiHttpModule : public Runtime::Instance::ComponentInstance { +public: + WasiHttpModule(); + + WasiHttpEnvironment &getEnv() { return Env; } + +private: + WasiHttpEnvironment Env; +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_logging/CMakeLists.txt b/plugins/wasi_logging/CMakeLists.txt deleted file mode 100644 index 0d0b64692adf..000000000000 --- a/plugins/wasi_logging/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -wasmedge_add_library(wasmedgePluginWasiLogging - SHARED - env.cpp - func.cpp - module.cpp -) - -target_compile_options(wasmedgePluginWasiLogging - PUBLIC - -DWASMEDGE_PLUGIN -) - -target_include_directories(wasmedgePluginWasiLogging - PUBLIC - $<TARGET_PROPERTY:wasmedgePlugin,INCLUDE_DIRECTORIES> - ${CMAKE_CURRENT_SOURCE_DIR} -) - -if(WASMEDGE_LINK_PLUGINS_STATIC) - target_link_libraries(wasmedgePluginWasiLogging - PRIVATE - wasmedgeCAPI - ) -else() - target_link_libraries(wasmedgePluginWasiLogging - PRIVATE - wasmedge_shared - ) -endif() - -install(TARGETS wasmedgePluginWasiLogging DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge) diff --git a/plugins/wasi_logging/env.cpp b/plugins/wasi_logging/env.cpp deleted file mode 100644 index 0f55170fff8b..000000000000 --- a/plugins/wasi_logging/env.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "wasi_logging/env.h" -#include "wasi_logging/module.h" - -namespace WasmEdge { -namespace Host { - -namespace { - -Runtime::Instance::ModuleInstance * -create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { - return new WasiLoggingModule; -} - -Plugin::Plugin::PluginDescriptor Descriptor{ - .Name = "wasi_logging", - .Description = "", - .APIVersion = Plugin::Plugin::CurrentAPIVersion, - .Version = {0, 1, 0, 0}, - .ModuleCount = 1, - .ModuleDescriptions = - (Plugin::PluginModule::ModuleDescriptor[]){ - { - .Name = "wasi:logging/logging", - .Description = "", - .Create = create, - }, - }, - .AddOptions = nullptr, -}; - -} // namespace - -Plugin::PluginRegister WasiLoggingEnvironment::Register(&Descriptor); - -} // namespace Host -} // namespace WasmEdge \ No newline at end of file diff --git a/plugins/wasi_logging/func.cpp b/plugins/wasi_logging/func.cpp deleted file mode 100644 index 5f0a2c0106b4..000000000000 --- a/plugins/wasi_logging/func.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "wasi_logging/func.h" -#include "wasi_logging/enum.h" -#include <string_view> - -namespace WasmEdge { -namespace Host { - -using namespace std::literals; - -Expect<void> WasiLoggingLog::body(const Runtime::CallingFrame &Frame, - uint32_t Level, uint32_t CxtPtr, - uint32_t CxtLen, uint32_t MsgPtr, - uint32_t MsgLen) { - // Check memory instance from module. - auto *MemInst = Frame.getMemoryByIndex(0); - if (MemInst == nullptr) { - return Unexpect(ErrCode::Value::HostFuncError); - } - - // Get Buffer Pointer - char *CxtBuf = MemInst->getPointer<char *>(CxtPtr); - char *MsgBuf = MemInst->getPointer<char *>(MsgPtr); - if (CxtBuf == nullptr || MsgBuf == nullptr) { - return Unexpect(ErrCode::Value::HostFuncError); - } - - // Copy Context String and Message String - std::string CxtStr, MsgStr; - std::copy_n(CxtBuf, CxtLen, std::back_inserter(CxtStr)); - std::copy_n(MsgBuf, MsgLen, std::back_inserter(MsgStr)); - - // Setup Logger for Stdout or Stderr - CxtStr == "stderr"sv ? Env.isCxtStrStderr = true : Env.isCxtStrStderr = false; - auto logger = Env.isCxtStrStderr ? Env.StderrLogger : Env.StdoutLogger; - - // Construct Spdlog Message - std::string SpdlogMsg; - if (!CxtStr.empty()) { - SpdlogMsg = CxtStr + ": " + MsgStr; - } else { - SpdlogMsg = MsgStr; - } - - // Print Message by Logging Level - switch (Level) { - case WASILOGGING::WasiLoggingLevel::Trace: - logger->trace(SpdlogMsg); - break; - case WASILOGGING::WasiLoggingLevel::Debug: - logger->debug(SpdlogMsg); - break; - case WASILOGGING::WasiLoggingLevel::Info: - logger->info(SpdlogMsg); - break; - case WASILOGGING::WasiLoggingLevel::Warn: - logger->warn(SpdlogMsg); - break; - case WASILOGGING::WasiLoggingLevel::Error: - logger->error(SpdlogMsg); - break; - case WASILOGGING::WasiLoggingLevel::Critical: - logger->critical(SpdlogMsg); - break; - default: - spdlog::error("[WasiLogging] Unrecognized Logging Level: {}"sv, Level); - spdlog::error("[WasiLogging] Trace Level = {}"sv, - static_cast<uint32_t>(WASILOGGING::WasiLoggingLevel::Trace)); - spdlog::error("[WasiLogging] Debug Level = {}"sv, - static_cast<uint32_t>(WASILOGGING::WasiLoggingLevel::Debug)); - spdlog::error("[WasiLogging] Info Level = {}"sv, - static_cast<uint32_t>(WASILOGGING::WasiLoggingLevel::Info)); - spdlog::error("[WasiLogging] Warn Level = {}"sv, - static_cast<uint32_t>(WASILOGGING::WasiLoggingLevel::Warn)); - spdlog::error("[WasiLogging] Error Level = {}"sv, - static_cast<uint32_t>(WASILOGGING::WasiLoggingLevel::Error)); - spdlog::error( - "[WasiLogging] Critical Level = {}"sv, - static_cast<uint32_t>(WASILOGGING::WasiLoggingLevel::Critical)); - return Unexpect(ErrCode::Value::HostFuncError); - } - return {}; -} - -} // namespace Host -} // namespace WasmEdge \ No newline at end of file diff --git a/plugins/wasi_logging/module.cpp b/plugins/wasi_logging/module.cpp deleted file mode 100644 index 6ebd7879f46f..000000000000 --- a/plugins/wasi_logging/module.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "wasi_logging/module.h" -#include "wasi_logging/func.h" -#include <string_view> - -namespace WasmEdge { -namespace Host { - -using namespace std::literals; - -WasiLoggingModule::WasiLoggingModule() - : ModuleInstance("wasi:logging/logging"sv) { - addHostFunc("log"sv, std::make_unique<WasiLoggingLog>(Env)); -} - -} // namespace Host -} // namespace WasmEdge \ No newline at end of file diff --git a/plugins/wasi_logging/wasi_logging/base.h b/plugins/wasi_logging/wasi_logging/base.h deleted file mode 100644 index 11b5504af764..000000000000 --- a/plugins/wasi_logging/wasi_logging/base.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "wasi_logging/env.h" - -#include "common/errcode.h" -#include "runtime/callingframe.h" -#include "runtime/hostfunc.h" - -namespace WasmEdge { -namespace Host { - -template <typename T> class WasiLogging : public Runtime::HostFunction<T> { -public: - WasiLogging(WasiLoggingEnvironment &HostEnv) - : Runtime::HostFunction<T>(0), Env(HostEnv) {} - -protected: - WasiLoggingEnvironment &Env; -}; - -} // namespace Host -} // namespace WasmEdge \ No newline at end of file diff --git a/plugins/wasi_logging/wasi_logging/enum.h b/plugins/wasi_logging/wasi_logging/enum.h deleted file mode 100644 index 5c4e2e2549a7..000000000000 --- a/plugins/wasi_logging/wasi_logging/enum.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include <cstdint> - -namespace WasmEdge { -namespace Host { -namespace WASILOGGING { - -enum WasiLoggingLevel : uint32_t { Trace, Debug, Info, Warn, Error, Critical }; - -} // namespace WASILOGGING -} // namespace Host -} // namespace WasmEdge \ No newline at end of file diff --git a/plugins/wasi_logging/wasi_logging/env.h b/plugins/wasi_logging/wasi_logging/env.h deleted file mode 100644 index 8a2864d27413..000000000000 --- a/plugins/wasi_logging/wasi_logging/env.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "plugin/plugin.h" -#include <spdlog/sinks/stdout_color_sinks.h> -namespace WasmEdge { -namespace Host { - -class WasiLoggingEnvironment { -public: - WasiLoggingEnvironment() noexcept { - StdoutLogger->set_level(spdlog::level::trace); - StderrLogger->set_level(spdlog::level::trace); - } - bool isCxtStrStderr = false; - inline const static std::shared_ptr<spdlog::logger> StdoutLogger = - spdlog::stdout_color_mt("wasi_logging_stdout"); - inline const static std::shared_ptr<spdlog::logger> StderrLogger = - spdlog::stderr_color_mt("wasi_logging_stderr"); - static Plugin::PluginRegister Register; -}; - -} // namespace Host -} // namespace WasmEdge diff --git a/plugins/wasi_logging/wasi_logging/func.h b/plugins/wasi_logging/wasi_logging/func.h deleted file mode 100644 index f7631e985c8b..000000000000 --- a/plugins/wasi_logging/wasi_logging/func.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "wasi_logging/base.h" - -namespace WasmEdge { -namespace Host { - -class WasiLoggingLog : public WasiLogging<WasiLoggingLog> { -public: - WasiLoggingLog(WasiLoggingEnvironment &HostEnv) : WasiLogging(HostEnv) {} - Expect<void> body(const Runtime::CallingFrame &Frame, uint32_t Level, - uint32_t CxtPtr, uint32_t CxtLen, uint32_t MsgPtr, - uint32_t MsgLen); -}; - -} // namespace Host -} // namespace WasmEdge diff --git a/plugins/wasi_logging/wasi_logging/module.h b/plugins/wasi_logging/wasi_logging/module.h deleted file mode 100644 index 12504522beeb..000000000000 --- a/plugins/wasi_logging/wasi_logging/module.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "runtime/instance/module.h" -#include "wasi_logging/env.h" - -namespace WasmEdge { -namespace Host { - -class WasiLoggingModule : public Runtime::Instance::ModuleInstance { -public: - WasiLoggingModule(); - - WasiLoggingEnvironment &getEnv() { return Env; } - -private: - WasiLoggingEnvironment Env; -}; - -} // namespace Host -} // namespace WasmEdge diff --git a/plugins/wasi_nn/CMakeLists.txt b/plugins/wasi_nn/CMakeLists.txt index 6fceddf0ce77..328ba9dc9192 100644 --- a/plugins/wasi_nn/CMakeLists.txt +++ b/plugins/wasi_nn/CMakeLists.txt @@ -1,118 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC - -string(TOLOWER ${WASMEDGE_PLUGIN_WASI_NN_BACKEND} BACKEND) -if(BACKEND STREQUAL "ggml") - # llama.cpp options - # Disable warnings and debug messages - set(LLAMA_ALL_WARNINGS OFF) - set(LLAMA_METAL_NDEBUG ON) - set(LLAMA_ACCELERATE OFF) - - if(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_CUBLAS) - message(STATUS "WASI-NN GGML LLAMA backend: Enable LLAMA_CUBLAS") - set(LLAMA_CUBLAS ON) - # If CUBLAS is ON, then OpenBLAS should be OFF. - set(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_BLAS OFF) - else() - message(STATUS "WASI-NN GGML LLAMA backend: Disable LLAMA_CUBLAS") - set(LLAMA_CUBLAS OFF) - endif() - - if(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_BLAS) - message(STATUS "WASI-NN GGML LLAMA backend: Enable LLAMA_BLAS") - # Default use OpenBLAS - set(LLAMA_BLAS ON) - set(LLAMA_BLAS_VENDOR "OpenBLAS") - else() - message(STATUS "WASI-NN GGML LLAMA backend: Disable LLAMA_BLAS") - set(LLAMA_BLAS OFF) - endif() - - if(NOT APPLE) - set(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_METAL OFF) - endif() - - if(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_METAL) - message(STATUS "WASI-NN GGML LLAMA backend: Enable LLAMA_METAL") - set(LLAMA_METAL ON) - else() - message(STATUS "WASI-NN GGML LLAMA backend: Disable LLAMA_METAL") - set(LLAMA_METAL OFF) - endif() - - # setup llama.cpp - message(STATUS "Downloading llama.cpp source") - include(FetchContent) - FetchContent_Declare( - llama - GIT_REPOSITORY https://github.com/ggerganov/llama.cpp.git - GIT_TAG b2029 - PATCH_COMMAND test -f ggml.patched || git apply ${CMAKE_SOURCE_DIR}/thirdparty/ggml/ggml.patch && ${CMAKE_COMMAND} -E touch ggml.patched - GIT_SHALLOW FALSE - ) - FetchContent_MakeAvailable(llama) - set_property(TARGET ggml PROPERTY POSITION_INDEPENDENT_CODE ON) - set_property(TARGET common PROPERTY POSITION_INDEPENDENT_CODE ON) - set_property(TARGET llama PROPERTY POSITION_INDEPENDENT_CODE ON) - - # setup simdjson - find_package(simdjson QUIET) - if(simdjson_FOUND) - message(STATUS "SIMDJSON found") - else() - message(STATUS "Downloading SIMDJSON source") - include(FetchContent) - FetchContent_Declare( - simdjson - GIT_REPOSITORY https://github.com/simdjson/simdjson.git - GIT_TAG tags/v3.2.1 - GIT_SHALLOW TRUE) - - if(MSVC) - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - get_property( - compile_options - DIRECTORY - PROPERTY COMPILE_OPTIONS - ) - set_property( - DIRECTORY - APPEND - PROPERTY COMPILE_OPTIONS - -Wno-undef - -Wno-suggest-override - -Wno-documentation - -Wno-sign-conversion - -Wno-extra-semi-stmt - -Wno-old-style-cast - -Wno-error=unused-parameter - -Wno-error=unused-template - -Wno-conditional-uninitialized - -Wno-implicit-int-conversion - -Wno-shorten-64-to-32 - -Wno-range-loop-bind-reference - -Wno-format-nonliteral - -Wno-unused-exception-parameter - -Wno-unused-member-function - ) - unset(compile_options) - elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - set_property( - DIRECTORY - APPEND - PROPERTY COMPILE_OPTIONS - /wd4100 # unreferenced formal parameter - ) - endif() - endif() - - FetchContent_MakeAvailable(simdjson) - set_property(TARGET simdjson PROPERTY POSITION_INDEPENDENT_CODE ON) - - message(STATUS "Downloading SIMDJSON source -- done") - endif() -endif() +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_library(wasmedgePluginWasiNN SHARED @@ -125,15 +12,191 @@ wasmedge_add_library(wasmedgePluginWasiNN torch.cpp tfl.cpp ggml.cpp + neuralspeed.cpp + piper.cpp + whispercpp.cpp + chattts.cpp ) +foreach(BACKEND ${WASMEDGE_PLUGIN_WASI_NN_BACKEND}) + string(TOLOWER ${BACKEND} BACKEND) + if(BACKEND STREQUAL "ggml") + wasmedge_setup_simdjson() + # llama.cpp options + # Disable warnings and debug messages + set(LLAMA_ALL_WARNINGS OFF) + set(LLAMA_METAL_NDEBUG ON) + set(GGML_ACCELERATE OFF) + set(GGML_BLAS OFF) + set(GGML_OPENMP OFF) + set(BUILD_SHARED_LIBS OFF) + + if(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_NATIVE) + message(STATUS "WASI-NN GGML LLAMA backend: Enable GGML_NATIVE(AVX/AVX2/FMA/F16C)") + set(GGML_NATIVE ON) + else() + message(STATUS "WASI-NN GGML LLAMA backend: Disable GGML_NATIVE(AVX/AVX2/FMA/F16C)") + set(GGML_NATIVE OFF) + set(GGML_AVX OFF) + set(GGML_AVX2 OFF) + set(GGML_FMA OFF) + set(GGML_F16C OFF) + endif() + + if(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_CUBLAS) + message(STATUS "WASI-NN GGML LLAMA backend: Enable GGML_CUDA") + set(GGML_CUDA ON) + # We need to set GGML_USE_CUDA for clip from llava. + add_compile_definitions(GGML_USE_CUDA) + else() + message(STATUS "WASI-NN GGML LLAMA backend: Disable GGML_CUDA") + set(GGML_CUDA OFF) + endif() + + if(APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" AND WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_METAL) + message(STATUS "WASI-NN GGML LLAMA backend: Enable GGML_METAL") + set(GGML_METAL ON) + set(GGML_METAL_EMBED_LIBRARY ON) + else() + message(STATUS "WASI-NN GGML LLAMA backend: Disable GGML_METAL") + set(GGML_METAL OFF) + endif() + + # setup llama.cpp + message(STATUS "Downloading llama.cpp source") + include(FetchContent) + FetchContent_Declare( + llama + GIT_REPOSITORY https://github.com/ggerganov/llama.cpp.git + GIT_TAG b3651 + GIT_SHALLOW FALSE + ) + FetchContent_MakeAvailable(llama) + set_property(TARGET ggml PROPERTY POSITION_INDEPENDENT_CODE ON) + set_property(TARGET common PROPERTY POSITION_INDEPENDENT_CODE ON) + set_property(TARGET llama PROPERTY POSITION_INDEPENDENT_CODE ON) + + # Setup llava from llama.cpp + wasmedge_add_library(llava OBJECT + ${llama_SOURCE_DIR}/examples/llava/clip.cpp + ${llama_SOURCE_DIR}/examples/llava/llava.cpp + ) + if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + target_compile_options(llava + PRIVATE + $<$<COMPILE_LANGUAGE:C,CXX>:/utf-8> + $<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=/utf-8> + $<$<COMPILE_LANGUAGE:C,CXX>:/wd4067> # unexpected tokens following preprocessor directive - expected a newline + $<$<COMPILE_LANGUAGE:C,CXX>:/wd4101> # 'identifier' : unreferenced local variable + $<$<COMPILE_LANGUAGE:C,CXX>:/wd4189> # 'identifier' : local variable is initialized but not referenced + $<$<COMPILE_LANGUAGE:C,CXX>:/wd4244> # 'argument' : conversion from 'type1' to 'type2', possible loss of data + $<$<COMPILE_LANGUAGE:C,CXX>:/wd4267> # 'var' : conversion from 'size_t' to 'type', possible loss of data + $<$<COMPILE_LANGUAGE:C,CXX>:/wd4297> # 'function' : function assumed not to throw an exception but does + $<$<COMPILE_LANGUAGE:C,CXX>:/wd4456> # declaration of 'identifier' hides previous local declaration + $<$<COMPILE_LANGUAGE:C,CXX>:/wd4505> # 'function' : unreferenced local function has been removed + ) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + target_compile_options(llava + PRIVATE + $<$<COMPILE_LANGUAGE:CXX>:-Wno-exceptions> + -Wno-cast-align + -Wno-cast-qual + -Wno-float-conversion + -Wno-implicit-fallthrough + -Wno-unused-macros + -Wno-unused-function + -Wno-unused-variable + ) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + target_compile_options(llava + PRIVATE + $<$<COMPILE_LANGUAGE:CXX>:-Wno-exceptions> + -Wno-cast-align + -Wno-cast-qual + -Wno-disabled-macro-expansion + -Wno-float-conversion + -Wno-implicit-fallthrough + -Wno-implicit-float-conversion + -Wno-unused-macros + -Wno-unused-function + -Wno-unused-variable + -Wno-sign-conversion + -Wno-shorten-64-to-32 + -Wno-implicit-int-conversion + -Wno-old-style-cast + -Wno-extra-semi-stmt + -Wno-format-nonliteral + -Wno-documentation + -Wno-unused-template + ) + endif() + target_link_libraries(llava PRIVATE ggml llama) + target_include_directories(llava PUBLIC + ${llama_SOURCE_DIR} + ${llama_SOURCE_DIR}/common + ${llama_SOURCE_DIR}/examples/llava + ) + target_link_libraries(wasmedgePluginWasiNN PRIVATE + common + simdjson::simdjson + llava + ) + if(APPLE AND WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_METAL) + add_custom_command( + TARGET wasmedgePluginWasiNN + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${llama_SOURCE_DIR}/ggml/src/ggml-metal.metal ggml-metal.metal + COMMAND ${CMAKE_COMMAND} -E copy ${llama_SOURCE_DIR}/ggml/src/ggml-common.h ggml-common.h + ) + endif() + elseif(BACKEND STREQUAL "neuralspeed") + message(NOTICE "WASI-NN NeuralSpeed backend is removed due to the upstream end-of-life.") + message(NOTICE "Reference: https://github.com/intel/neural-speed") + elseif(BACKEND STREQUAL "chattts") + wasmedge_setup_simdjson() + + find_package(Python3 COMPONENTS Interpreter Development) + if(Python3_FOUND) + target_compile_definitions(wasmedgePluginWasiNN + PRIVATE PYTHON_LIB_PATH="${Python3_LIBRARIES}" + ) + include_directories(${Python3_INCLUDE_DIRS}) + target_link_libraries(wasmedgePluginWasiNN PRIVATE ${Python3_LIBRARIES}) + target_link_directories(wasmedgePluginWasiNN PRIVATE ${Python3_RUNTIME_LIBRARY_DIRS}) + else() + message(FATAL_ERROR "Can not find python3.") + endif() + target_link_libraries(wasmedgePluginWasiNN PRIVATE simdjson::simdjson) + elseif(BACKEND STREQUAL "piper") + wasmedge_setup_simdjson() + target_link_libraries(wasmedgePluginWasiNN PRIVATE simdjson::simdjson) + elseif(BACKEND STREQUAL "whisper") + wasmedge_setup_simdjson() + if(APPLE AND CMAKE_SYSTEM_VERSION VERSION_LESS 23) + # `cblas_sgemm()` introduced in macOS 13.3. + set(WHISPER_NO_ACCELERATE ON CACHE INTERNAL "Stable diffusion turn off accelerate") + endif() + set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Whisper not build shared") + include(FetchContent) + FetchContent_Declare( + whisper + GIT_REPOSITORY https://github.com/ggerganov/whisper.cpp.git + GIT_TAG v1.6.2 + GIT_SHALLOW FALSE + ) + FetchContent_MakeAvailable(whisper) + set_property(TARGET whisper PROPERTY POSITION_INDEPENDENT_CODE ON) + target_link_libraries(wasmedgePluginWasiNN PRIVATE + whisper + simdjson::simdjson + ) + endif() +endforeach() + target_compile_options(wasmedgePluginWasiNN PUBLIC -DWASMEDGE_PLUGIN ) -if(WASMEDGE_BUILD_WASI_NN_RPC) - add_definitions(-DWASMEDGE_BUILD_WASI_NN_RPC) -endif() target_include_directories(wasmedgePluginWasiNN PUBLIC @@ -141,16 +204,15 @@ target_include_directories(wasmedgePluginWasiNN ${CMAKE_CURRENT_SOURCE_DIR} ) -if(BACKEND STREQUAL "ggml") - target_include_directories(wasmedgePluginWasiNN PUBLIC ${CMAKE_BINARY_DIR}/_deps/llama-src) - target_link_libraries(wasmedgePluginWasiNN PRIVATE common simdjson) - if(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_METAL) - add_custom_command( - TARGET wasmedgePluginWasiNN - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/_deps/llama-src/ggml-metal.metal ggml-metal.metal - ) - endif() +if(WASMEDGE_BUILD_WASI_NN_RPC) + add_definitions(-DWASMEDGE_BUILD_WASI_NN_RPC) + target_include_directories(wasmedgePluginWasiNN + SYSTEM BEFORE PUBLIC ${Protobuf_INCLUDE_DIR} + ) + target_link_libraries(wasmedgePluginWasiNN + PRIVATE + wasiNNRPC + ) endif() if(WASMEDGE_LINK_PLUGINS_STATIC) @@ -165,17 +227,10 @@ else() ) endif() -if(WASMEDGE_BUILD_WASI_NN_RPC) - target_include_directories(wasmedgePluginWasiNN - SYSTEM BEFORE PUBLIC ${Protobuf_INCLUDE_DIR} - ) - target_link_libraries(wasmedgePluginWasiNN - PRIVATE - wasiNNRPC - ) -endif() - include(WASINNDeps) wasmedge_setup_wasinn_target(wasmedgePluginWasiNN) -install(TARGETS wasmedgePluginWasiNN DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge) +install( + TARGETS wasmedgePluginWasiNN + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) diff --git a/plugins/wasi_nn/chattts.cpp b/plugins/wasi_nn/chattts.cpp new file mode 100644 index 000000000000..ecd4f99ee35d --- /dev/null +++ b/plugins/wasi_nn/chattts.cpp @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "chattts.h" +#include "wasinnenv.h" + +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_CHATTTS +#include "simdjson.h" + +#if !defined(_WIN32) && !defined(_WIN64) && !defined(__WIN32__) && \ + !defined(__TOS_WIN__) && !defined(__WINDOWS__) +#include <dlfcn.h> +#endif +#include <chrono> +#include <time.h> +#endif + +namespace WasmEdge::Host::WASINN::ChatTTS { +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_CHATTTS +#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || \ + defined(__TOS_WIN__) || defined(__WINDOWS__) +HINSTANCE SharedLib = LoadLibrary(PYTHON_LIB_PATH); +#else +void *SharedLib = dlopen(PYTHON_LIB_PATH, RTLD_GLOBAL | RTLD_NOW); +#endif +Expect<WASINN::ErrNo> load(WASINN::WasiNNEnvironment &Env, + Span<const Span<uint8_t>>, WASINN::Device, + uint32_t &GraphId) noexcept { + // Add a new graph. + Env.NNGraph.emplace_back(Backend::ChatTTS); + auto &GraphRef = Env.NNGraph.back().get<Graph>(); + // Initialize the plugin parameters. + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN] ChatTTS backend: Load."sv); + } + + // Create Model class + if (!Py_IsInitialized()) { + Py_Initialize(); + } + if (GraphRef.ChatTTSModule == nullptr) { + GraphRef.ChatTTSModule = PyImport_ImportModule("ChatTTS"); + if (GraphRef.ChatTTSModule == nullptr) { + spdlog::error( + "[WASI-NN] ChatTTS backend: Can not find ChatTTS library."sv); + Env.NNGraph.pop_back(); + return WASINN::ErrNo::RuntimeError; + } + } + if (GraphRef.Chat == nullptr) { + PyObject *ChatFunction = + PyObject_GetAttrString(GraphRef.ChatTTSModule, "Chat"); + if (ChatFunction == nullptr || !PyCallable_Check(ChatFunction)) { + spdlog::error( + "[WASI-NN] ChatTTS backend: Can not find Chat class in ChatTTS."sv); + Env.NNGraph.pop_back(); + return WASINN::ErrNo::RuntimeError; + } + GraphRef.Chat = PyObject_CallObject(ChatFunction, nullptr); + Py_XDECREF(ChatFunction); + if (GraphRef.Chat == nullptr) { + spdlog::error("[WASI-NN] ChatTTS backend: Can not create chat."sv); + Env.NNGraph.pop_back(); + return WASINN::ErrNo::RuntimeError; + } + PyObject *LoadMethod = PyObject_GetAttrString(GraphRef.Chat, "load"); + if (LoadMethod == nullptr || !PyCallable_Check(LoadMethod)) { + spdlog::error("[WASI-NN] ChatTTS backend: Can not load chat."sv); + Env.NNGraph.pop_back(); + return WASINN::ErrNo::RuntimeError; + } + PyObject *Value = PyObject_CallObject(LoadMethod, nullptr); + Py_XDECREF(Value); + Py_XDECREF(LoadMethod); + } + // Store the loaded graph. + GraphId = Env.NNGraph.size() - 1; + + return WASINN::ErrNo::Success; +} + +Expect<WASINN::ErrNo> initExecCtx(WasiNNEnvironment &Env, uint32_t GraphId, + uint32_t &ContextId) noexcept { + if (!Py_IsInitialized()) { + spdlog::error( + "[WASI-NN] ChatTTS backend: Model has been released, please reload it."sv); + return WASINN::ErrNo::RuntimeError; + } + Env.NNContext.emplace_back(GraphId, Env.NNGraph[GraphId]); + ContextId = Env.NNContext.size() - 1; + return ErrNo::Success; +} + +Expect<WASINN::ErrNo> setInput(WasiNNEnvironment &Env, uint32_t ContextId, + uint32_t Index, + const TensorData &Tensor) noexcept { + auto &CxtRef = Env.NNContext[ContextId].get<Context>(); + auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get<Graph>(); + if (!Py_IsInitialized()) { + spdlog::error( + "[WASI-NN] ChatTTS backend: Model has been released, please reload it."sv); + return WASINN::ErrNo::RuntimeError; + } + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN] ChatTTS backend: setInput"sv); + } + if (Index == 0) { + // Set the input. + std::string Prompt(reinterpret_cast<char *>(Tensor.Tensor.data()), + Tensor.Tensor.size()); + CxtRef.Inputs.clear(); + CxtRef.Inputs = Prompt; + return WASINN::ErrNo::Success; + } else if (Index == 1) { + // Set metadata. + std::string Metadata = std::string( + reinterpret_cast<char *>(Tensor.Tensor.data()), Tensor.Tensor.size()); + simdjson::dom::parser Parser; + simdjson::dom::element Doc; + auto ParseError = Parser.parse(Metadata).get(Doc); + if (ParseError) { + spdlog::error("[WASI-NN] ChatTTS backend: Parse metadata error"sv); + Env.NNGraph.pop_back(); + return ErrNo::InvalidEncoding; + } + // Handle Refine Text Params + PyObject *PromptObj = nullptr; + if (Doc.at_key("prompt").error() == simdjson::SUCCESS) { + std::string_view PromptView; + auto Err = Doc["prompt"].get<std::string_view>().get(PromptView); + if (Err) { + spdlog::error( + "[WASI-NN] ChatTTS backend: Unable to retrieve the prompt option."sv); + return ErrNo::InvalidArgument; + } + PromptObj = PyUnicode_FromString(std::string(PromptView).c_str()); + } + if (PromptObj != nullptr) { + PyObject *Args = PyTuple_New(0); + PyObject *Kwargs = PyDict_New(); + PyDict_SetItemString(Kwargs, "prompt", PromptObj); + PyObject *RefineTextParamsFun = + PyObject_GetAttrString(GraphRef.Chat, "RefineTextParams"); + GraphRef.ParamsRefineText = + PyObject_Call(RefineTextParamsFun, Args, Kwargs); + Py_XDECREF(PromptObj); + Py_XDECREF(Args); + Py_XDECREF(Kwargs); + Py_XDECREF(RefineTextParamsFun); + } + // Handle Infer Code Params + PyObject *InferKwargs = PyDict_New(); + if (Doc.at_key("temperature").error() == simdjson::SUCCESS) { + double Temperature; + auto Err = Doc["temperature"].get<double>().get(Temperature); + if (Err) { + spdlog::error( + "[WASI-NN] ChatTTS backend: Unable to retrieve the temperature option."sv); + return ErrNo::InvalidArgument; + } + PyObject *TemperatureObject = PyFloat_FromDouble(Temperature); + PyDict_SetItemString(InferKwargs, "temperature", TemperatureObject); + Py_XDECREF(TemperatureObject); + } + if (Doc.at_key("top_K").error() == simdjson::SUCCESS) { + double TopK; + auto Err = Doc["top_K"].get<double>().get(TopK); + if (Err) { + spdlog::error( + "[WASI-NN] ChatTTS backend: Unable to retrieve the topK option."sv); + return ErrNo::InvalidArgument; + } + PyObject *TopKObject = PyFloat_FromDouble(TopK); + PyDict_SetItemString(InferKwargs, "top_K", TopKObject); + Py_XDECREF(TopKObject); + } + if (Doc.at_key("top_P").error() == simdjson::SUCCESS) { + double TopP; + auto Err = Doc["top_P"].get<double>().get(TopP); + if (Err) { + spdlog::error( + "[WASI-NN] ChatTTS backend: Unable to retrieve the temperature option."sv); + return ErrNo::InvalidArgument; + } + PyObject *TopPObject = PyFloat_FromDouble(TopP); + PyDict_SetItemString(InferKwargs, "top_P", TopPObject); + Py_XDECREF(TopPObject); + } + if (Doc.at_key("spk_emb").error() == simdjson::SUCCESS) { + std::string_view SpkEmb; + auto Err = Doc["spk_emb"].get<std::string_view>().get(SpkEmb); + if (Err) { + spdlog::error( + "[WASI-NN] ChatTTS backend: Unable to retrieve the spk_emb option."sv); + return ErrNo::InvalidArgument; + } + if (SpkEmb == "random") { + PyObject *SampleRandomSpeaker = + PyObject_GetAttrString(GraphRef.Chat, "sample_random_speaker"); + PyObject *Spk = PyObject_CallNoArgs(SampleRandomSpeaker); + PyDict_SetItemString(InferKwargs, "spk_emb", Spk); + Py_XDECREF(SampleRandomSpeaker); + Py_XDECREF(Spk); + } else { + PyObject *Spk = PyUnicode_FromString(std::string(SpkEmb).c_str()); + PyDict_SetItemString(InferKwargs, "spk_emb", Spk); + Py_XDECREF(Spk); + } + } + if (PyDict_Size(InferKwargs) != 0) { + PyObject *Args = PyTuple_New(0); + PyObject *InferCodeParams = + PyObject_GetAttrString(GraphRef.Chat, "InferCodeParams"); + GraphRef.ParamsInferCode = + PyObject_Call(InferCodeParams, Args, InferKwargs); + Py_XDECREF(Args); + Py_XDECREF(InferCodeParams); + } + Py_XDECREF(InferKwargs); + return WASINN::ErrNo::Success; + } + return WASINN::ErrNo::InvalidArgument; +} + +Expect<WASINN::ErrNo> getOutput(WasiNNEnvironment &Env, uint32_t ContextId, + uint32_t Index, Span<uint8_t> OutBuffer, + uint32_t &BytesWritten) noexcept { + auto &CxtRef = Env.NNContext[ContextId].get<Context>(); + auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get<Graph>(); + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN] ChatTTS backend: getOutput"sv); + } + if (Index == 0) { + std::copy_n(CxtRef.Outputs.data(), CxtRef.Outputs.size(), OutBuffer.data()); + BytesWritten = CxtRef.Outputs.size(); + return WASINN::ErrNo::Success; + } + return WASINN::ErrNo::InvalidArgument; +} +Expect<WASINN::ErrNo> compute(WasiNNEnvironment &Env, + uint32_t ContextId) noexcept { + if (!Py_IsInitialized()) { + spdlog::error( + "[WASI-NN] ChatTTS backend: Model has been released, please reload it."sv); + return WASINN::ErrNo::RuntimeError; + } + auto &CxtRef = Env.NNContext[ContextId].get<Context>(); + auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get<Graph>(); + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN] ChatTTS backend: compute"sv); + } + if (CxtRef.Inputs.size() == 0) { + spdlog::error("[WASI-NN] ChatTTS backend: Input is not set!"sv); + return ErrNo::InvalidArgument; + } + PyObject *InputStr = PyUnicode_FromString(CxtRef.Inputs.c_str()); + PyObject *InferMethod = PyObject_GetAttrString(GraphRef.Chat, "infer"); + PyObject *Result = nullptr; + if (InferMethod == nullptr || !PyCallable_Check(InferMethod)) { + spdlog::error( + "[WASI-NN] ChatTTS backend: Can not find infer method in Chat."sv); + PyErr_Print(); + Py_XDECREF(InferMethod); + return WASINN::ErrNo::RuntimeError; + } + if (GraphRef.ParamsRefineText == nullptr && + GraphRef.ParamsInferCode == nullptr) { + PyObject *Args = PyTuple_Pack(1, InputStr); + Result = PyObject_CallObject(InferMethod, Args); + Py_XDECREF(Args); + } else { + PyObject *Args = PyTuple_New(0); + PyObject *Kwargs = PyDict_New(); + PyDict_SetItemString(Kwargs, "text", InputStr); + if (GraphRef.ParamsRefineText != nullptr) { + PyDict_SetItemString(Kwargs, "params_refine_text", + GraphRef.ParamsRefineText); + } + if (GraphRef.ParamsInferCode != nullptr) { + PyDict_SetItemString(Kwargs, "params_infer_code", + GraphRef.ParamsInferCode); + } + Result = PyObject_Call(InferMethod, Args, Kwargs); + Py_XDECREF(Args); + Py_XDECREF(Kwargs); + } + if (Result != nullptr) { + PyObject *Wav0 = PyList_GetItem(Result, 0); + PyObject *BytesObj = PyObject_CallMethod(Wav0, "tobytes", nullptr); + char *Bytes = PyBytes_AsString(BytesObj); + Py_ssize_t size = PyBytes_Size(BytesObj); + CxtRef.Outputs = std::vector<uint8_t>(Bytes, Bytes + size); + Py_XDECREF(BytesObj); + } else { + spdlog::error( + "[WASI-NN] ChatTTS backend: Can not get output from infer method."sv); + Py_XDECREF(InputStr); + Py_XDECREF(InferMethod); + return WASINN::ErrNo::RuntimeError; + } + Py_XDECREF(Result); + Py_XDECREF(InputStr); + Py_XDECREF(InferMethod); + return WASINN::ErrNo::Success; +} + +Expect<WASINN::ErrNo> unload(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId) noexcept { + auto &CxtRef = Env.NNContext[ContextId].get<Context>(); + auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get<Graph>(); + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN] Neural speed backend: start unload."sv); + } + if (Py_IsInitialized()) { + Py_XDECREF(GraphRef.ParamsRefineText); + Py_XDECREF(GraphRef.ParamsInferCode); + Py_XDECREF(GraphRef.Chat); + Py_XDECREF(GraphRef.ChatTTSModule); + GraphRef.Chat = nullptr; + GraphRef.ChatTTSModule = nullptr; + Py_Finalize(); + } + return WASINN::ErrNo::Success; +} + +#else +namespace { +Expect<WASINN::ErrNo> reportBackendNotSupported() noexcept { + spdlog::error("[WASI-NN] ChatTTS backend is not built. use " + "-WASMEDGE_PLUGIN_WASI_NN_BACKEND=\"ChatTTS\" to build it."sv); + return WASINN::ErrNo::InvalidArgument; +} +} // namespace + +Expect<WASINN::ErrNo> load(WASINN::WasiNNEnvironment &, + Span<const Span<uint8_t>>, WASINN::Device, + uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> initExecCtx(WASINN::WasiNNEnvironment &, uint32_t, + uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> setInput(WASINN::WasiNNEnvironment &, uint32_t, uint32_t, + const TensorData &) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> getOutput(WASINN::WasiNNEnvironment &, uint32_t, uint32_t, + Span<uint8_t>, uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> compute(WASINN::WasiNNEnvironment &, uint32_t) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> unload(WASINN::WasiNNEnvironment &, uint32_t) noexcept { + return reportBackendNotSupported(); +} +#endif + +} // namespace WasmEdge::Host::WASINN::ChatTTS diff --git a/plugins/wasi_nn/chattts.h b/plugins/wasi_nn/chattts.h new file mode 100644 index 000000000000..46cab0a35edb --- /dev/null +++ b/plugins/wasi_nn/chattts.h @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "plugin/plugin.h" +#include "types.h" + +#include <mutex> +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_CHATTTS +#include <Python.h> +#endif + +namespace WasmEdge::Host::WASINN { +struct WasiNNEnvironment; +} + +namespace WasmEdge::Host::WASINN::ChatTTS { +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_CHATTTS +struct Graph { + bool EnableDebugLog = false; + Graph() noexcept { Py_Initialize(); } + ~Graph() noexcept { + if (Py_IsInitialized()) { + Py_XDECREF(Chat); + Py_XDECREF(ChatTTSModule); + } + } + PyObject *Chat = nullptr; + PyObject *ChatTTSModule = nullptr; + PyObject *ParamsRefineText = nullptr; + PyObject *ParamsInferCode = nullptr; +}; +struct Context { + Context(size_t Gid, Graph &) noexcept : GraphId(Gid) {} + size_t GraphId; + std::string Inputs; + std::vector<uint8_t> Outputs; +}; +#else +struct Graph {}; +struct Context { + Context(size_t, Graph &) noexcept {} +}; +#endif + +struct Environ {}; + +Expect<WASINN::ErrNo> load(WASINN::WasiNNEnvironment &Env, + Span<const Span<uint8_t>> Builders, + WASINN::Device Device, uint32_t &GraphId) noexcept; +Expect<WASINN::ErrNo> initExecCtx(WASINN::WasiNNEnvironment &Env, + uint32_t GraphId, + uint32_t &ContextId) noexcept; +Expect<WASINN::ErrNo> setInput(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId, uint32_t Index, + const TensorData &Tensor) noexcept; +Expect<WASINN::ErrNo> getOutput(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId, uint32_t Index, + Span<uint8_t> OutBuffer, + uint32_t &BytesWritten) noexcept; +Expect<WASINN::ErrNo> compute(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId) noexcept; +Expect<WASINN::ErrNo> unload(WASINN::WasiNNEnvironment &Env, + uint32_t GraphId) noexcept; +} // namespace WasmEdge::Host::WASINN::ChatTTS diff --git a/plugins/wasi_nn/ggml.cpp b/plugins/wasi_nn/ggml.cpp index 2d83eafb4de6..6268e3225091 100644 --- a/plugins/wasi_nn/ggml.cpp +++ b/plugins/wasi_nn/ggml.cpp @@ -1,21 +1,54 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "ggml.h" #include "wasinnenv.h" #ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_GGML #include "simdjson.h" +#include <algorithm> +#include <base64.hpp> +#include <clip.h> #include <common.h> #include <cstdlib> +#include <filesystem> +#include <fmt/ranges.h> +#include <json-schema-to-grammar.h> +#include <json.hpp> #include <llama.h> +#include <llava.h> #include <sstream> #endif namespace WasmEdge::Host::WASINN::GGML { #ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_GGML -namespace details { +namespace { + +void LlamaLogCallback(ggml_log_level LogLevel, const char *LogText, + void *UserData) { + Graph &GraphRef = *reinterpret_cast<Graph *>(UserData); + if (!GraphRef.EnableLog) { + return; + } + std::string Text(LogText); + // Remove the trailing newlines. + Text = Text.erase(Text.find_last_not_of("\n") + 1); + // Skip for "." + if (Text == ".") { + return; + } + if (LogLevel == GGML_LOG_LEVEL_ERROR) { + spdlog::error("[WASI-NN] llama.cpp: {}"sv, Text); + } else if (LogLevel == GGML_LOG_LEVEL_WARN) { + spdlog::warn("[WASI-NN] llama.cpp: {}"sv, Text); + } else if (LogLevel == GGML_LOG_LEVEL_INFO) { + spdlog::info("[WASI-NN] llama.cpp: {}"sv, Text); + } else if (LogLevel == GGML_LOG_LEVEL_DEBUG) { + spdlog::debug("[WASI-NN] llama.cpp: {}"sv, Text); + } +} + Expect<ErrNo> parseMetadata(Graph &GraphRef, const std::string &Metadata, bool *IsModelUpdated = nullptr) noexcept { simdjson::dom::parser Parser; @@ -27,12 +60,42 @@ Expect<ErrNo> parseMetadata(Graph &GraphRef, const std::string &Metadata, } // Get metadata from the json. - // Need to update Model: - // * n_gpu_layers + + // Currently supported metadata: + // Plugin parameters (used by this plugin): + // enable-log: bool + // enable-debug-log: bool + // stream-stdout: bool + // embedding: bool + // n-predict: uint64_t + // reverse-prompt: string + // mmproj: string + // image: string + // use-mmap: bool + // Model parameters (need to reload the model if updated): + // n-gpu-layers: int64_t + // main-gpu: int64_t + // tensor-split: string, comma-separated floating number list + // use-mmap: use mmap + // Context parameters (used by the llama context): + // ctx-size: uint64_t + // batch-size: uint64_t + // ubatch-size: uint64_t + // threads: uint64_t + // Sampling parameters (used by the llama sampling context). + // temp: double + // top-p: double + // repeat-penalty: double + // presence-penalty: double + // frequency-penalty: double + // grammar: string // Get the current llama parameters. llama_model_params ModelParams = llama_model_default_params(); - ModelParams.n_gpu_layers = GraphRef.NGPULayers; + ModelParams.n_gpu_layers = static_cast<int32_t>(GraphRef.NGPULayers); + ModelParams.main_gpu = static_cast<int32_t>(GraphRef.MainGPU); + ModelParams.tensor_split = GraphRef.TensorSplit.data(); + ModelParams.use_mmap = GraphRef.UseMMap; // The plugin parameters. if (Doc.at_key("enable-log").error() == simdjson::SUCCESS) { @@ -42,7 +105,6 @@ Expect<ErrNo> parseMetadata(Graph &GraphRef, const std::string &Metadata, "[WASI-NN] GGML backend: Unable to retrieve the enable-log option."sv); return ErrNo::InvalidArgument; } - llama_log_set(nullptr, &GraphRef.EnableLog); } if (Doc.at_key("enable-debug-log").error() == simdjson::SUCCESS) { auto Err = Doc["enable-debug-log"].get<bool>().get(GraphRef.EnableDebugLog); @@ -86,6 +148,26 @@ Expect<ErrNo> parseMetadata(Graph &GraphRef, const std::string &Metadata, } GraphRef.ReversePrompt = ReversePrompt; } + if (Doc.at_key("mmproj").error() == simdjson::SUCCESS) { + std::string_view MMProjModelPath; + auto Err = Doc["mmproj"].get<std::string_view>().get(MMProjModelPath); + if (Err) { + spdlog::error( + "[WASI-NN] GGML backend: Unable to retrieve the mmproj option."sv); + return ErrNo::InvalidArgument; + } + GraphRef.MMProjModelPath = MMProjModelPath; + } + if (Doc.at_key("image").error() == simdjson::SUCCESS) { + std::string_view ImagePath; + auto Err = Doc["image"].get<std::string_view>().get(ImagePath); + if (Err) { + spdlog::error( + "[WASI-NN] GGML backend: Unable to retrieve the image option."sv); + return ErrNo::InvalidArgument; + } + GraphRef.ImagePath = ImagePath; + } // The model parameters. if (Doc.at_key("n-gpu-layers").error() == simdjson::SUCCESS) { @@ -96,6 +178,52 @@ Expect<ErrNo> parseMetadata(Graph &GraphRef, const std::string &Metadata, return ErrNo::InvalidArgument; } } + if (Doc.at_key("main-gpu").error() == simdjson::SUCCESS) { + auto Err = Doc["main-gpu"].get<int64_t>().get(GraphRef.MainGPU); + if (Err) { + spdlog::error( + "[WASI-NN] GGML backend: Unable to retrieve the main-gpu option."sv); + return ErrNo::InvalidArgument; + } + } + if (Doc.at_key("tensor-split").error() == simdjson::SUCCESS) { + // The TensorSplit is a comma-separated list of non-negative values. + // E.g., "3,2" presents 60% of the data to GPU 0 and 40% to GPU 1. + std::string_view TSV; + auto Err = Doc["tensor-split"].get<std::string_view>().get(TSV); + if (Err) { + spdlog::error( + "[WASI-NN] GGML backend: Unable to retrieve the tensor-split option."sv); + return ErrNo::InvalidArgument; + } + std::string TS(TSV); + std::replace(TS.begin(), TS.end(), ',', ' '); + std::stringstream SS(TS); + GraphRef.TensorSplit.clear(); + while (SS.good()) { + float TmpTensor; + SS >> TmpTensor; + GraphRef.TensorSplit.push_back(TmpTensor); + } + size_t NDevices = llama_max_devices(); + if (GraphRef.TensorSplit.size() > NDevices) { + spdlog::error( + "[WASI-NN] GGML backend: Number of Tensor-Split is larger " + "than MaxDevices, please reduce the size of tensor-split."sv); + return ErrNo::InvalidArgument; + } + for (size_t Idx = GraphRef.TensorSplit.size(); Idx < NDevices; Idx++) { + GraphRef.TensorSplit.push_back(0.0f); + } + } + if (Doc.at_key("use-mmap").error() == simdjson::SUCCESS) { + auto Err = Doc["use-mmap"].get<bool>().get(GraphRef.UseMMap); + if (Err) { + spdlog::error( + "[WASI-NN] GGML backend: Unable to retrieve the use-mmap option."sv); + return ErrNo::InvalidArgument; + } + } // The context parameters. if (Doc.at_key("ctx-size").error() == simdjson::SUCCESS) { @@ -114,6 +242,14 @@ Expect<ErrNo> parseMetadata(Graph &GraphRef, const std::string &Metadata, return ErrNo::InvalidArgument; } } + if (Doc.at_key("ubatch-size").error() == simdjson::SUCCESS) { + auto Err = Doc["ubatch-size"].get<uint64_t>().get(GraphRef.UBatchSize); + if (Err) { + spdlog::error( + "[WASI-NN] GGML backend: Unable to retrieve the ubatch-size option."sv); + return ErrNo::InvalidArgument; + } + } if (Doc.at_key("threads").error() == simdjson::SUCCESS) { auto Err = Doc["threads"].get<uint64_t>().get(GraphRef.Threads); if (Err) { @@ -122,6 +258,7 @@ Expect<ErrNo> parseMetadata(Graph &GraphRef, const std::string &Metadata, return ErrNo::InvalidArgument; } } + // The sampling parameters. if (Doc.at_key("temp").error() == simdjson::SUCCESS) { auto Err = Doc["temp"].get<double>().get(GraphRef.Temp); @@ -166,6 +303,27 @@ Expect<ErrNo> parseMetadata(Graph &GraphRef, const std::string &Metadata, return ErrNo::InvalidArgument; } } + if (Doc.at_key("grammar").error() == simdjson::SUCCESS) { + std::string_view Grammar; + auto Err = Doc["grammar"].get<std::string_view>().get(Grammar); + if (Err) { + spdlog::error( + "[WASI-NN] GGML backend: Unable to retrieve the grammar option."sv); + return ErrNo::InvalidArgument; + } + GraphRef.Grammar = Grammar; + } + if (Doc.at_key("json-schema").error() == simdjson::SUCCESS) { + std::string_view JsonSchema; + auto Err = Doc["json-schema"].get<std::string_view>().get(JsonSchema); + if (Err) { + spdlog::error( + "[WASI-NN] GGML backend: Unable to retrieve the json-schema option."sv); + return ErrNo::InvalidArgument; + } + GraphRef.Grammar = + json_schema_to_grammar(nlohmann::ordered_json::parse(JsonSchema)); + } // Check if the model is updated. if (IsModelUpdated && ModelParams.n_gpu_layers != GraphRef.NGPULayers) { @@ -175,15 +333,35 @@ Expect<ErrNo> parseMetadata(Graph &GraphRef, const std::string &Metadata, return ErrNo::Success; } +Expect<ErrNo> setupGPTParam(Graph &GraphRef, gpt_params &GPTParams) { + GPTParams.sparams.temp = static_cast<float>(GraphRef.Temp); + GPTParams.sparams.top_p = static_cast<float>(GraphRef.TopP); + GPTParams.sparams.penalty_repeat = static_cast<float>(GraphRef.RepeatPenalty); + GPTParams.sparams.penalty_present = + static_cast<float>(GraphRef.PresencePenalty); + GPTParams.sparams.grammar = GraphRef.Grammar; + return ErrNo::Success; +} + +Expect<ErrNo> setupContextParam(Graph &GraphRef, + llama_context_params &ContextParams) { + ContextParams.n_ctx = static_cast<uint32_t>(GraphRef.CtxSize); + ContextParams.n_batch = static_cast<uint32_t>(GraphRef.BatchSize); + ContextParams.n_ubatch = static_cast<uint32_t>(GraphRef.UBatchSize); + ContextParams.n_threads = static_cast<uint32_t>(GraphRef.Threads); + ContextParams.n_threads_batch = static_cast<uint32_t>(GraphRef.Threads); + ContextParams.embeddings = GraphRef.Embedding; + return ErrNo::Success; +} + Expect<ErrNo> buildOutputMetadata(Context &CxtRef, std::string &Metadata) noexcept { - std::ostringstream OS; - OS << R"({"input_tokens": )" << CxtRef.LlamaInputs.size() - << R"(, "output_tokens": )" << CxtRef.LlamaOutputTokens.size() - << R"(, "llama_build_number": )" << LLAMA_BUILD_NUMBER - << R"(, "llama_commit": ")" << LLAMA_COMMIT << R"("})"; - Metadata = OS.str(); - + Metadata = fmt::format(R"({{"input_tokens": {}, )" + R"("output_tokens": {}, )" + R"("llama_build_number": {}, )" + R"("llama_commit": "{}"}})"sv, + CxtRef.LlamaNInputs, CxtRef.LlamaOutputTokens.size(), + LLAMA_BUILD_NUMBER, LLAMA_COMMIT); return ErrNo::Success; } @@ -200,14 +378,103 @@ void buildOutputEmbedding(std::string &Embedding, int32_t NEmbd, // | (n_embedding-1)*(',') | // | ']' | // | '}' | - std::ostringstream OS; - OS.precision(10); - OS << R"({"n_embedding": )" << NEmbd << R"(, "embedding": [)"; - for (int32_t Idx = 0; Idx < NEmbd - 1; Idx++) { - OS << Embeddings[Idx] << ","; + Embedding = + fmt::format(R"({{"n_embedding": {:.10}, )" + R"("embedding": [{:.10}]}})"sv, + NEmbd, fmt::join(Embeddings, Embeddings + NEmbd, ","sv)); +} + +ErrNo evaluateTokens(Graph &GraphRef, struct llama_context *LlamaContext, + std::vector<llama_token> Tokens, int &NPast) noexcept { + uint32_t NCtx = llama_n_ctx(LlamaContext); + + // End the inference if the context is full. + if (NPast + static_cast<uint32_t>(Tokens.size()) > NCtx) { + if (GraphRef.EnableLog) { + spdlog::info( + "[WASI-NN] GGML backend: the context if full ({} / {} tokens). Please increase your context size."sv, + NPast + static_cast<uint32_t>(Tokens.size()), NCtx); + } + return ErrNo::ContextFull; + } + + for (int I = 0; I < static_cast<int>(Tokens.size()); + I += static_cast<int>(GraphRef.BatchSize)) { + int NEval = static_cast<int>(Tokens.size()) - I; + if (NEval > static_cast<int>(GraphRef.BatchSize)) { + NEval = static_cast<int>(GraphRef.BatchSize); + } + // llama_batch_get_one(*token, n_tokens, position, sequence_id) + // This will return batch for single sequence of tokens starting at + // position. + const llama_seq_id SequenceId = 0; + auto Status = + llama_decode(LlamaContext, + llama_batch_get_one(&Tokens[I], NEval, NPast, SequenceId)); + if (Status == 1) { + spdlog::error( + "[WASI-NN] GGML backend: failed to llama_decode: try reducing the size of the batch or increasing the size of context"sv); + return ErrNo::RuntimeError; + } else if (Status < 0) { + spdlog::error( + "[WASI-NN] GGML backend: failed to llama_decode: internal fatal error. Please open an issue on GitHub"sv); + return ErrNo::RuntimeError; + } + NPast += NEval; + } + + return ErrNo::Success; +} + +void batchAddSeq(llama_batch &Batch, const std::vector<llama_token> &Tokens, + llama_seq_id SequenceId) noexcept { + for (int I = 0; I < static_cast<int>(Tokens.size()); I++) { + // llama_batch_add_seq(llama_batch, llama_token, llama_pos, + // std::vector<llama_seq_id>, logits); + llama_batch_add(Batch, Tokens[I], I, {SequenceId}, + I == static_cast<int>(Tokens.size()) - 1); } - OS << Embeddings[NEmbd - 1] << "]}"; - Embedding = OS.str(); +} + +ErrNo batchDecode(llama_context *LlamaContext, llama_batch &Batch, + float *Output, int NEmbd) noexcept { + // Clear previous kv_cache values (irrelevant for embeddings) + llama_kv_cache_clear(LlamaContext); + + // Decode the batch. + auto Status = llama_decode(LlamaContext, Batch); + if (Status == 1) { + spdlog::error( + "[WASI-NN] GGML backend: failed to llama_decode: try reducing the size of the batch or increasing the size of context"sv); + return ErrNo::RuntimeError; + } else if (Status < 0) { + spdlog::error( + "[WASI-NN] GGML backend: failed to llama_decode: internal fatal error. Please open an issue on GitHub"sv); + return ErrNo::RuntimeError; + } + + for (int I = 0; I < Batch.n_tokens; I++) { + if (!Batch.logits[I]) { + continue; + } + + // Try to get sequence embeddings. + auto *Embd = llama_get_embeddings_seq(LlamaContext, Batch.seq_id[I][0]); + if (Embd == nullptr) { + Embd = llama_get_embeddings_ith(LlamaContext, I); + if (Embd == nullptr) { + spdlog::error( + "[WASI-NN] GGML backend: failed to get embeddings for token {}"sv, + I); + continue; + } + } + + // Normalize the embeddings. + llama_embd_normalize(Embd, Output, NEmbd); + } + + return ErrNo::Success; } Expect<ErrNo> getEmbedding(WasiNNEnvironment &Env, @@ -241,56 +508,49 @@ Expect<ErrNo> getEmbedding(WasiNNEnvironment &Env, } // Initialize the llama context. llama_context_params ContextParams = llama_context_default_params(); - ContextParams.n_ctx = GraphRef.CtxSize; - ContextParams.n_batch = GraphRef.BatchSize; - ContextParams.embedding = GraphRef.Embedding; + setupContextParam(GraphRef, ContextParams); + // For non-causal models, batch size must be equal to ubatch size + ContextParams.n_ubatch = ContextParams.n_batch; auto *LlamaContext = llama_new_context_with_model(GraphRef.LlamaModel, ContextParams); - // Get the context size. - const uint64_t NCtx = llama_n_ctx(LlamaContext); - // Minus 4 for the special tokens. (Such as <BOS>, <EOS>, ... tokens.) - const uint64_t MaxTokensListSize = NCtx - 4; // Use the const sequence id here. const llama_seq_id SequenceId = 0; + // Return value. + auto ReturnCode = ErrNo::Success; + + // Add SEP if not present. + if (CxtRef.LlamaInputs.back() != llama_token_sep(GraphRef.LlamaModel)) { + CxtRef.LlamaInputs.push_back(llama_token_sep(GraphRef.LlamaModel)); + } // Check if the input is too long. - if (static_cast<uint64_t>(CxtRef.LlamaInputs.size()) > MaxTokensListSize) { + if (static_cast<uint64_t>(CxtRef.LlamaInputs.size()) > + ContextParams.n_batch) { if (GraphRef.EnableLog) { spdlog::info( - "[WASI-NN] GGML backend: the prompt is too long. Your input has {} tokens. Please reduce it to {} tokens."sv, - CxtRef.LlamaInputs.size(), MaxTokensListSize); + "[WASI-NN] GGML backend: the prompt is too long. " + "Your input has {} tokens exceeds batch size {}. " + "Please reduce the input size or increase your batch-size."sv, + CxtRef.LlamaInputs.size(), ContextParams.n_batch); } return ErrNo::PromptTooLong; } - int NPast = 0; - while (!CxtRef.LlamaInputs.empty()) { - const uint64_t NTokens = (ContextParams.n_batch > CxtRef.LlamaInputs.size()) - ? CxtRef.LlamaInputs.size() - : ContextParams.n_batch; - auto Status = llama_decode(LlamaContext, - llama_batch_get_one(CxtRef.LlamaInputs.data(), - NTokens, NPast, SequenceId)); - if (Status == 1) { - spdlog::error( - "[WASI-NN] GGML backend: failed to llama_decode: try reducing the size of the batch or increasing the size of context"sv); - return ErrNo::RuntimeError; - } - if (Status < 0) { - spdlog::error( - "[WASI-NN] GGML backend: failed to llama_decode: internal fatal error. Please open an issue on GitHub"sv); - return ErrNo::RuntimeError; - } - - NPast += NTokens; - CxtRef.LlamaInputs.erase(CxtRef.LlamaInputs.begin(), - CxtRef.LlamaInputs.begin() + NTokens); - } const int32_t NEmbd = llama_n_embd(GraphRef.LlamaModel); - const auto *Embeddings = llama_get_embeddings(LlamaContext); + struct llama_batch Batch = llama_batch_init( + /* n_tokens_alloc */ static_cast<int32_t>(GraphRef.BatchSize), + /* embd */ 0, + /* n_seq_max */ 1); + std::vector<float> Embeddings(NEmbd); + batchAddSeq(Batch, CxtRef.LlamaInputs, SequenceId); + ReturnCode = batchDecode(LlamaContext, Batch, Embeddings.data(), NEmbd); + if (ReturnCode != ErrNo::Success) { + spdlog::error("[WASI-NN] GGML backend: failed to evaluate input tokens."sv); + return ReturnCode; + } - details::buildOutputEmbedding(CxtRef.LlamaOutputs, NEmbd, Embeddings); + buildOutputEmbedding(CxtRef.LlamaOutputs, NEmbd, Embeddings.data()); if (GraphRef.EnableDebugLog) { spdlog::info( @@ -304,15 +564,127 @@ Expect<ErrNo> getEmbedding(WasiNNEnvironment &Env, // We free the contexts here to keep the ggml plugin stateless. // Users could fully control the contexts by themselves via their prompt. llama_free(LlamaContext); + llama_batch_free(Batch); if (GraphRef.EnableDebugLog) { - spdlog::info("[WASI-NN][Debug] GGML backend: compute...Done"sv); + spdlog::info("[WASI-NN][Debug] GGML backend: getEmbedding...Done"sv); + } + + return ErrNo::Success; +} + +const std::string_view Base64ImageTagPrefix = "<img src=\"data:image/"sv; +const std::string_view Base64ImageBytesPrefix = ";base64,"sv; +const std::string_view Base64ImageTagSuffix = "\">"sv; +const std::string_view PromptImagePlaceholder = "<image>"sv; + +bool containsBase64Image(Graph &GraphRef, std::string_view Prompt) noexcept { + // Check if the prompt contains a base64 image. + // Follow this link for the supported image formats: + // https://github.com/ggerganov/llama.cpp/blob/master/common/stb_image.h + + auto Base64ImageTagBeginPos = Prompt.find(Base64ImageTagPrefix); + if (Base64ImageTagBeginPos == std::string::npos) { + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: No base64 image tag found in the prompt."sv); + } + return false; + } + auto Base64ImageTagEndPos = + Prompt.find(Base64ImageTagSuffix, Base64ImageTagBeginPos); + if (Base64ImageTagEndPos == std::string::npos) { + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: Found an unclosed base64 image tag."sv); + } + return false; + } + return true; +} + +struct llava_image_embed * +loadBase64ImageFromPrompt(Graph &GraphRef, clip_ctx *ClipContext, + std::string_view Prompt) noexcept { + // Load the base64 image from the prompt. + // Follow this link for the supported image formats: + // https://github.com/ggerganov/llama.cpp/blob/master/common/stb_image.h + + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: loadBase64ImageFromPrompt"sv); + } + + // Find `<img src="data:image/` + auto Base64ImageTagBeginPos = Prompt.find(Base64ImageTagPrefix); + if (Base64ImageTagBeginPos == std::string::npos) { + return nullptr; + } + + // Find `;base64,` (skip the image type part) + auto Base64ImageBytesBeginPos = + Prompt.find(Base64ImageBytesPrefix, Base64ImageTagBeginPos); + if (Base64ImageTagBeginPos == std::string::npos) { + return nullptr; + } + + // Find `">` + auto Base64ImageTagEndPos = + Prompt.find(Base64ImageTagSuffix, Base64ImageBytesBeginPos); + if (Base64ImageTagEndPos == std::string::npos) { + return nullptr; } + auto Base64Str = + Prompt.substr(Base64ImageBytesBeginPos + Base64ImageBytesPrefix.size(), + Base64ImageTagEndPos - Base64ImageBytesBeginPos - + Base64ImageBytesPrefix.size()); + + // Decode the base64 image. + auto RequiredBytes = base64::required_encode_size(Base64Str.size()); + auto ImageBytes = std::vector<unsigned char>(RequiredBytes); + try { + base64::decode(Base64Str.begin(), Base64Str.end(), ImageBytes.begin()); + } catch (const base64_error &E) { + spdlog::error("[WASI-NN] GGML backend: Error when base64::decode: {}"sv, + E.what()); + return nullptr; + } + + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: loadBase64ImageFromPrompt...Done"sv); + } + + return llava_image_embed_make_with_bytes( + ClipContext, static_cast<int>(GraphRef.Threads), ImageBytes.data(), + static_cast<int>(ImageBytes.size())); +} + +ErrNo replaceBase64ImagePlaceholderInPrompt(std::string &Prompt) noexcept { + // Replace the base64 image in the prompt with a placeholder. + + // Find `<img src="data:image/` + auto Base64ImageTagBeginPos = Prompt.find(Base64ImageTagPrefix); + if (Base64ImageTagBeginPos == std::string::npos) { + return ErrNo::InvalidArgument; + } + + // Find `">` + auto Base64ImageTagEndPos = + Prompt.find(Base64ImageTagSuffix, Base64ImageTagBeginPos); + if (Base64ImageTagEndPos == std::string::npos) { + return ErrNo::InvalidArgument; + } + + auto Base64ImageTagLength = Base64ImageTagEndPos - Base64ImageTagBeginPos + + Base64ImageTagSuffix.size(); + Prompt.replace(Base64ImageTagBeginPos, Base64ImageTagLength, + PromptImagePlaceholder); + return ErrNo::Success; } -} // namespace details +} // namespace Expect<ErrNo> load(WasiNNEnvironment &Env, Span<const Span<uint8_t>> Builders, [[maybe_unused]] Device Device, uint32_t &GraphId) noexcept { @@ -323,15 +695,14 @@ Expect<ErrNo> load(WasiNNEnvironment &Env, Span<const Span<uint8_t>> Builders, // Initialize the plugin parameters. auto ContextDefault = llama_context_default_params(); GraphRef.EnableLog = false; + GraphRef.EnableDebugLog = false; GraphRef.StreamStdout = false; - GraphRef.ReversePrompt = ""sv; GraphRef.NPredict = ContextDefault.n_ctx; + GraphRef.ReversePrompt = ""sv; + GraphRef.MMProjModelPath = ""sv; + GraphRef.ImagePath = ""sv; // Initialize the model parameters. GraphRef.NGPULayers = 0; -#ifdef __APPLE__ - // We will always set the ngl to 1 on macOS to enable Metal. - GraphRef.NGPULayers = 1; -#endif // Initialize the context parameters. GraphRef.CtxSize = ContextDefault.n_ctx; GraphRef.BatchSize = ContextDefault.n_batch; @@ -343,13 +714,17 @@ Expect<ErrNo> load(WasiNNEnvironment &Env, Span<const Span<uint8_t>> Builders, GraphRef.RepeatPenalty = SamplingDefault.penalty_repeat; GraphRef.PresencePenalty = SamplingDefault.penalty_present; GraphRef.FrequencyPenalty = SamplingDefault.penalty_freq; + GraphRef.Grammar = SamplingDefault.grammar; + + // Set llama log callback. + llama_log_set(LlamaLogCallback, &GraphRef); // If the graph builder length > 1, the data of builder[1] is the metadata. if (Builders.size() > 1) { const std::string Metadata(reinterpret_cast<char *>(Builders[1].data()), Builders[1].size()); // Ignore context or model updates when initializing the graph. - auto Res = details::parseMetadata(GraphRef, Metadata); + auto Res = parseMetadata(GraphRef, Metadata); if (Res != ErrNo::Success) { spdlog::error("[WASI-NN] GGML backend: Failed to parse metadata."sv); Env.NNGraph.pop_back(); @@ -367,20 +742,21 @@ Expect<ErrNo> load(WasiNNEnvironment &Env, Span<const Span<uint8_t>> Builders, } // Handle the model path. auto Weight = Builders[0]; - const std::string BinModel(reinterpret_cast<char *>(Weight.data()), - Weight.size()); + const std::string_view BinModel(reinterpret_cast<char *>(Weight.data()), + Weight.size()); std::string ModelFilePath; - if (BinModel.substr(0, 8) == "preload:") { + if (BinModel.substr(0, 8) == "preload:"sv) { ModelFilePath = BinModel.substr(8); } else { if (GraphRef.EnableDebugLog) { spdlog::info( - "[WASI-NN][Debug] GGML backend: Model path not found in nn-preload, write model into a tmpfile."sv); + "[WASI-NN][Debug] GGML backend: Model path not found in nn-preload, " + "write model into a tmpfile."sv); } // TODO: pass the model directly to ggml // Write ggml model to file. ModelFilePath = "ggml-model.bin"sv; - std::ofstream TempFile(ModelFilePath); + std::ofstream TempFile(ModelFilePath, std::ios::out | std::ios::binary); if (!TempFile) { spdlog::error( "[WASI-NN] GGML backend: Failed to create the temporary file. " @@ -390,7 +766,7 @@ Expect<ErrNo> load(WasiNNEnvironment &Env, Span<const Span<uint8_t>> Builders, Env.NNGraph.pop_back(); return ErrNo::InvalidArgument; } - TempFile << BinModel; + TempFile.write(BinModel.data(), BinModel.size()); TempFile.close(); if (GraphRef.EnableDebugLog) { spdlog::info( @@ -401,6 +777,12 @@ Expect<ErrNo> load(WasiNNEnvironment &Env, Span<const Span<uint8_t>> Builders, spdlog::info( "[WASI-NN][Debug] GGML backend: Finished handling model path."sv); } + // Check if the model exists. + if (!std::filesystem::exists(std::filesystem::u8path(ModelFilePath))) { + spdlog::error("[WASI-NN] GGML backend: Model file not found."sv); + Env.NNGraph.pop_back(); + return ErrNo::ModelNotFound; + } if (GraphRef.EnableDebugLog) { spdlog::info( @@ -409,7 +791,10 @@ Expect<ErrNo> load(WasiNNEnvironment &Env, Span<const Span<uint8_t>> Builders, // Initialize ggml model with model parameters. GraphRef.ModelFilePath = ModelFilePath; llama_model_params ModelParams = llama_model_default_params(); - ModelParams.n_gpu_layers = GraphRef.NGPULayers; + ModelParams.n_gpu_layers = static_cast<int32_t>(GraphRef.NGPULayers); + ModelParams.main_gpu = static_cast<int32_t>(GraphRef.MainGPU); + ModelParams.tensor_split = GraphRef.TensorSplit.data(); + ModelParams.use_mmap = GraphRef.UseMMap; GraphRef.LlamaModel = llama_load_model_from_file(GraphRef.ModelFilePath.c_str(), ModelParams); if (GraphRef.LlamaModel == nullptr) { @@ -423,7 +808,7 @@ Expect<ErrNo> load(WasiNNEnvironment &Env, Span<const Span<uint8_t>> Builders, } // Store the loaded graph. - GraphId = Env.NNGraph.size() - 1; + GraphId = static_cast<uint32_t>(Env.NNGraph.size() - 1); // Disable llama log by default. log_disable(); @@ -433,13 +818,19 @@ Expect<ErrNo> load(WasiNNEnvironment &Env, Span<const Span<uint8_t>> Builders, Expect<ErrNo> initExecCtx(WasiNNEnvironment &Env, uint32_t GraphId, uint32_t &ContextId) noexcept { - Env.NNContext.emplace_back(GraphId, Env.NNGraph[GraphId]); - ContextId = Env.NNContext.size() - 1; auto &GraphRef = Env.NNGraph[GraphId].get<Graph>(); + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: initExecCtx"sv); + } + Env.NNContext.emplace_back(GraphId, Env.NNGraph[GraphId]); + ContextId = static_cast<uint32_t>(Env.NNContext.size() - 1); if (GraphRef.EnableLog) { spdlog::info("[WASI-NN] GGML backend: llama_system_info: {}"sv, llama_print_system_info()); } + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: initExecCtx...Done"sv); + } return ErrNo::Success; } @@ -460,8 +851,7 @@ Expect<ErrNo> setInput(WasiNNEnvironment &Env, uint32_t ContextId, } const std::string Metadata(reinterpret_cast<char *>(Tensor.Tensor.data()), Tensor.Tensor.size()); - auto Res = - details::parseMetadata(GraphRef, Metadata, &IsModelParamsUpdated); + auto Res = parseMetadata(GraphRef, Metadata, &IsModelParamsUpdated); if (Res != ErrNo::Success) { spdlog::error("[WASI-NN] GGML backend: Failed to parse metadata."sv); @@ -477,7 +867,7 @@ Expect<ErrNo> setInput(WasiNNEnvironment &Env, uint32_t ContextId, { if (IsModelParamsUpdated) { llama_model_params ModelParams = llama_model_default_params(); - ModelParams.n_gpu_layers = GraphRef.NGPULayers; + ModelParams.n_gpu_layers = static_cast<int32_t>(GraphRef.NGPULayers); llama_free_model(GraphRef.LlamaModel); GraphRef.LlamaModel = llama_load_model_from_file( GraphRef.ModelFilePath.c_str(), ModelParams); @@ -503,13 +893,8 @@ Expect<ErrNo> setInput(WasiNNEnvironment &Env, uint32_t ContextId, spdlog::info("[WASI-NN][Debug] GGML backend: init llama context"sv); } llama_context_params ContextParams = llama_context_default_params(); - ContextParams.n_ctx = GraphRef.CtxSize; - ContextParams.n_batch = GraphRef.BatchSize; - ContextParams.n_threads = GraphRef.Threads; - ContextParams.n_threads_batch = GraphRef.Threads; - ContextParams.embedding = GraphRef.Embedding; - - auto *LlamaContext = + setupContextParam(GraphRef, ContextParams); + auto LlamaContext = llama_new_context_with_model(GraphRef.LlamaModel, ContextParams); if (GraphRef.EnableDebugLog) { spdlog::info("[WASI-NN][Debug] GGML backend: init llama context...Done"sv); @@ -519,10 +904,112 @@ Expect<ErrNo> setInput(WasiNNEnvironment &Env, uint32_t ContextId, if (GraphRef.EnableDebugLog) { spdlog::info("[WASI-NN][Debug] GGML backend: set the input"sv); } - const bool AddBos = llama_should_add_bos_token(GraphRef.LlamaModel); - const std::string Prompt(reinterpret_cast<char *>(Tensor.Tensor.data()), - Tensor.Tensor.size()); - CxtRef.LlamaInputs = llama_tokenize(LlamaContext, Prompt, AddBos, true); + const bool AddSpecial = true; + const bool ParseSpecial = true; + std::string Prompt(reinterpret_cast<char *>(Tensor.Tensor.data()), + Tensor.Tensor.size()); + CxtRef.LlamaInputs.clear(); + if (GraphRef.MMProjModelPath == ""sv) { + // Text only prompt. + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: tokenize text prompt"sv); + } + CxtRef.LlamaInputs = + llama_tokenize(LlamaContext, Prompt, AddSpecial, ParseSpecial); + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: tokenize text prompt...Done"sv); + } + } else { + // Handle llava format prompt. + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: handle llava format prompt"sv); + } + // Check if the prompt contains a base64 image. + bool ContainsBase64Image = containsBase64Image(GraphRef, Prompt); + if (GraphRef.ImagePath == ""sv && ContainsBase64Image == false) { + spdlog::error( + "[WASI-NN] GGML backend: Error: when using llava model, " + "you need to specify the image path or have the base64 encoded " + "image in the prompt."sv); + return ErrNo::InvalidArgument; + } + + // Show some warnings. + if (GraphRef.EnableLog) { + if (GraphRef.CtxSize < 4096) { + spdlog::info( + "[WASI-NN] GGML backend: Context size is {}, " + "we recommend context size >= 2048 when using llava-v1.5 " + "and context size >= 4096 when using llava-v1.6 for better results."sv, + GraphRef.CtxSize); + } + } + + // Load image for llava. + int LlavaVerbosity = 0; + if (GraphRef.EnableLog) { + LlavaVerbosity = 1; + } + auto ClipContext = + clip_model_load(GraphRef.MMProjModelPath.c_str(), LlavaVerbosity); + if (ContainsBase64Image) { + // Load the base64 image from the prompt. + CxtRef.LlavaImageEmbd = + loadBase64ImageFromPrompt(GraphRef, ClipContext, Prompt); + // Replace the base64 image in the prompt with a placeholder. + auto Res = replaceBase64ImagePlaceholderInPrompt(Prompt); + if (Res != ErrNo::Success) { + spdlog::error( + "[WASI-NN] GGML backend: Error: unable to replace the base64 image in the prompt."sv); + clip_free(ClipContext); + return Res; + } + } else { + // Load the image from the file. + CxtRef.LlavaImageEmbd = llava_image_embed_make_with_filename( + ClipContext, static_cast<int>(GraphRef.Threads), + GraphRef.ImagePath.c_str()); + } + clip_free(ClipContext); + if (CxtRef.LlavaImageEmbd == nullptr) { + spdlog::error( + "[WASI-NN] GGML backend: Error: unable to load the image."sv); + return ErrNo::InvalidArgument; + } + + // We split prompt by <image> as placeholder and save the position. + auto PlaceholderPosition = Prompt.find(PromptImagePlaceholder); + if (PlaceholderPosition == std::string::npos) { + spdlog::error( + "[WASI-NN] GGML backend: Error: unable to find the placeholder in the llava prompt."sv); + return ErrNo::InvalidArgument; + } + std::string PromptBeforeImage = Prompt.substr(0, PlaceholderPosition); + std::string PromptAfterImage = + Prompt.substr(PlaceholderPosition + PromptImagePlaceholder.length()); + std::vector<llama_token> EmbdInputBeforeImage = llama_tokenize( + LlamaContext, PromptBeforeImage, AddSpecial, ParseSpecial); + // Do not add special token (such as <BOS>, <EOS>, ... tokens.) to the + // tokens after the image. + std::vector<llama_token> EmbdInputAfterImage = + llama_tokenize(LlamaContext, PromptAfterImage, false, ParseSpecial); + CxtRef.LlavaImagePosition = EmbdInputBeforeImage.size(); + CxtRef.LlamaInputs.reserve(EmbdInputBeforeImage.size() + + EmbdInputAfterImage.size()); + CxtRef.LlamaInputs.insert(CxtRef.LlamaInputs.end(), + EmbdInputBeforeImage.begin(), + EmbdInputBeforeImage.end()); + CxtRef.LlamaInputs.insert(CxtRef.LlamaInputs.end(), + EmbdInputAfterImage.begin(), + EmbdInputAfterImage.end()); + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: handle llava format prompt...Done"sv); + } + } + CxtRef.LlamaNInputs = CxtRef.LlamaInputs.size(); if (GraphRef.EnableDebugLog) { spdlog::info("[WASI-NN][Debug] GGML backend: set the input...Done"sv); } @@ -548,23 +1035,38 @@ Expect<ErrNo> getOutput(WasiNNEnvironment &Env, uint32_t ContextId, uint32_t Index, Span<uint8_t> OutBuffer, uint32_t &BytesWritten) noexcept { auto &CxtRef = Env.NNContext[ContextId].get<Context>(); + auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get<Graph>(); + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: getOutput with Index {}"sv, + Index); + } // Index 1 is for the metadata of the outputs. if (Index == 1) { std::string Metadata; - auto Res = details::buildOutputMetadata(CxtRef, Metadata); + auto Res = buildOutputMetadata(CxtRef, Metadata); if (Res != ErrNo::Success) { spdlog::error( "[WASI-NN] GGML backend: Failed to build output metadata."sv); return Res; } std::copy_n(Metadata.data(), Metadata.length(), OutBuffer.data()); - BytesWritten = Metadata.length(); + BytesWritten = static_cast<uint32_t>(Metadata.length()); + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: getOutput with Index {}...Done"sv, + Index); + } return ErrNo::Success; } std::copy_n(CxtRef.LlamaOutputs.data(), CxtRef.LlamaOutputs.length(), OutBuffer.data()); - BytesWritten = CxtRef.LlamaOutputs.length(); + BytesWritten = static_cast<uint32_t>(CxtRef.LlamaOutputs.length()); + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: getOutput with Index {}...Done"sv, + Index); + } return ErrNo::Success; } @@ -576,7 +1078,7 @@ Expect<ErrNo> compute(WasiNNEnvironment &Env, uint32_t ContextId) noexcept { } if (GraphRef.Embedding) { - return details::getEmbedding(Env, ContextId); + return getEmbedding(Env, ContextId); } if (CxtRef.LlamaInputs.size() == 0) { @@ -596,151 +1098,122 @@ Expect<ErrNo> compute(WasiNNEnvironment &Env, uint32_t ContextId) noexcept { "[WASI-NN][Debug] GGML backend: clear the previous output and tokens...Done"sv); } - // Main predict loop. - if (GraphRef.EnableDebugLog) { - spdlog::info("[WASI-NN][Debug] GGML backend: enter main predict loop"sv); - } - gpt_params GPTParams; - GPTParams.sparams.temp = GraphRef.Temp; - GPTParams.sparams.top_p = GraphRef.TopP; - GPTParams.sparams.penalty_repeat = GraphRef.RepeatPenalty; - GPTParams.sparams.penalty_present = GraphRef.PresencePenalty; - GPTParams.sparams.penalty_freq = GraphRef.FrequencyPenalty; - struct llama_sampling_context *CtxSampling = - llama_sampling_init(GPTParams.sparams); - std::vector<llama_token> Embd; - uint64_t NPast = 0; - uint64_t NConsumed = 0; - int32_t NRemain = GraphRef.NPredict; // Initialize the llama context. + gpt_params GPTParams; llama_context_params ContextParams = llama_context_default_params(); - ContextParams.n_ctx = GraphRef.CtxSize; - ContextParams.n_batch = GraphRef.BatchSize; - auto *LlamaContext = + setupGPTParam(GraphRef, GPTParams); + setupContextParam(GraphRef, ContextParams); + auto LlamaContext = llama_new_context_with_model(GraphRef.LlamaModel, ContextParams); - + struct llama_sampling_context *CtxSampling = + llama_sampling_init(GPTParams.sparams); + // Prepare variables; + int32_t NPast = 0; + uint64_t NRemain = GraphRef.NPredict; // Get the context size. const uint64_t NCtx = llama_n_ctx(LlamaContext); // Minus 4 for the special tokens. (Such as <BOS>, <EOS>, ... tokens.) const uint64_t MaxTokensListSize = NCtx - 4; - // Use the const sequence id here. - const llama_seq_id SequenceId = 0; // Return value. auto ReturnCode = ErrNo::Success; // Check if the input is too long. if (static_cast<uint64_t>(CxtRef.LlamaInputs.size()) > MaxTokensListSize) { if (GraphRef.EnableLog) { - spdlog::info( - "[WASI-NN] GGML backend: the prompt is too long. Your input has {} tokens. Please reduce it to {} tokens."sv, - CxtRef.LlamaInputs.size(), MaxTokensListSize); + spdlog::info("[WASI-NN] GGML backend: the prompt is too long. Your input " + "has {} tokens. Please reduce it to {} tokens."sv, + CxtRef.LlamaInputs.size(), MaxTokensListSize); } return ErrNo::PromptTooLong; } + // Evaluate input tokens. + if (CxtRef.LlavaImageEmbd == nullptr) { + // Text only prompt. + ReturnCode = evaluateTokens(GraphRef, LlamaContext, + std::move(CxtRef.LlamaInputs), NPast); + if (ReturnCode != ErrNo::Success) { + spdlog::error( + "[WASI-NN] GGML backend: failed to evaluate input tokens."sv); + return ReturnCode; + } + } else { + // Llava format prompt with image data. + std::vector<llama_token> EmbdInputBeforeImage( + CxtRef.LlamaInputs.begin(), + CxtRef.LlamaInputs.begin() + CxtRef.LlavaImagePosition); + std::vector<llama_token> EmbdInputAfterImage(CxtRef.LlamaInputs.begin() + + CxtRef.LlavaImagePosition, + CxtRef.LlamaInputs.end()); + ReturnCode = evaluateTokens(GraphRef, LlamaContext, + std::move(EmbdInputBeforeImage), NPast); + if (ReturnCode != ErrNo::Success) { + spdlog::error( + "[WASI-NN] GGML backend: failed to evaluate input tokens before image."sv); + return ReturnCode; + } + bool EvalImageStatus = + llava_eval_image_embed(LlamaContext, CxtRef.LlavaImageEmbd, + static_cast<int>(GraphRef.BatchSize), &NPast); + if (!EvalImageStatus) { + spdlog::error( + "[WASI-NN] GGML backend: failed to evaluate embed image tokens."sv); + return ErrNo::RuntimeError; + } + ReturnCode = evaluateTokens(GraphRef, LlamaContext, + std::move(EmbdInputAfterImage), NPast); + if (ReturnCode != ErrNo::Success) { + spdlog::error( + "[WASI-NN] GGML backend: failed to evaluate input tokens after image."sv); + return ReturnCode; + } + } + // Main predict loop. + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: enter main predict loop"sv); + } while (NRemain > 0) { - // Preidct - if (!Embd.empty()) { - // Input too long. - if (static_cast<uint64_t>(Embd.size()) > MaxTokensListSize) { - if (GraphRef.EnableLog) { - spdlog::info( - "[WASI-NN] GGML backend: the prompt is too long. Your input has {} tokens. Please reduce it to {} tokens."sv, - Embd.size(), MaxTokensListSize); - } - ReturnCode = ErrNo::PromptTooLong; - break; - } - - // We do not swap context here. End the inference if the context is full. - if (NPast + static_cast<uint64_t>(Embd.size()) > NCtx) { - if (GraphRef.EnableLog) { - spdlog::info( - "[WASI-NN] GGML backend: the context if full ({} / {} tokens). Please increase your ctx-size."sv, - NPast + static_cast<int>(Embd.size()), NCtx); - } - ReturnCode = ErrNo::ContextFull; - break; - } - - // Evaluate tokens in batches. - for (int I = 0; I < static_cast<int>(Embd.size()); - I += GraphRef.BatchSize) { - uint64_t NEval = static_cast<uint64_t>(Embd.size()) - I; - if (NEval > static_cast<uint64_t>(GraphRef.BatchSize)) { - NEval = GraphRef.BatchSize; - } - // llama_batch_get_one(*token, n_tokens, position, sequence_id) - // This will return batch for single sequence of tokens starting at - // position. - auto Status = - llama_decode(LlamaContext, llama_batch_get_one(&Embd[I], NEval, - NPast, SequenceId)); - if (Status == 1) { - spdlog::error( - "[WASI-NN] GGML backend: failed to llama_decode: try reducing the size of the batch or increasing the size of context"sv); - return ErrNo::RuntimeError; - } - if (Status < 0) { - spdlog::error( - "[WASI-NN] GGML backend: failed to llama_decode: internal fatal error. Please open an issue on GitHub"sv); - return ErrNo::RuntimeError; - } - - NPast += NEval; - } + const llama_token Id = + llama_sampling_sample(CtxSampling, LlamaContext, nullptr); + llama_sampling_accept(CtxSampling, LlamaContext, Id, true); + --NRemain; + + // Save the output token. + CxtRef.LlamaOutputTokens.emplace_back(Id); + CxtRef.LlamaOutputs += llama_token_to_piece(LlamaContext, Id); + // When setting StreamStdout, we print the output to stdout. + if (GraphRef.StreamStdout) { + fmt::print("{}"sv, llama_token_to_piece(LlamaContext, Id)); + std::fflush(stdout); } - - Embd.clear(); - - if (static_cast<uint64_t>(CxtRef.LlamaInputs.size()) <= NConsumed) { - const llama_token Id = - llama_sampling_sample(CtxSampling, LlamaContext, nullptr); - llama_sampling_accept(CtxSampling, LlamaContext, Id, true); - Embd.emplace_back(Id); - --NRemain; - // Save the output token. - CxtRef.LlamaOutputTokens.emplace_back(Id); - CxtRef.LlamaOutputs += llama_token_to_piece(LlamaContext, Id); - // When setting StreamStdout, we print the output to stdout. - if (GraphRef.StreamStdout) { - std::cout << llama_token_to_piece(LlamaContext, Id) << std::flush; - } - // Break if reverse prompt is found. - if (!GraphRef.ReversePrompt.empty() && - CxtRef.LlamaOutputs.find(GraphRef.ReversePrompt) != - std::string::npos) { - if (GraphRef.EnableLog) { - spdlog::info("[WASI-NN] GGML backend: reverse prompt found"sv); - } - break; - } - // Deal with end of text token. - if (llama_sampling_last(CtxSampling) == - llama_token_eos(GraphRef.LlamaModel)) { - if (GraphRef.EnableLog) { - spdlog::info("[WASI-NN] GGML backend: EOS token found"sv); - } - break; + // Break if reverse prompt is found. + if (!GraphRef.ReversePrompt.empty() && + CxtRef.LlamaOutputs.find(GraphRef.ReversePrompt) != std::string::npos) { + if (GraphRef.EnableLog) { + spdlog::info("[WASI-NN] GGML backend: reverse prompt found"sv); } - } else { - while (static_cast<uint64_t>(CxtRef.LlamaInputs.size()) > NConsumed) { - Embd.push_back(CxtRef.LlamaInputs[NConsumed]); - // Push the prompt in the sampling context. - llama_sampling_accept(CtxSampling, LlamaContext, - CxtRef.LlamaInputs[NConsumed], false); - ++NConsumed; - if (Embd.size() >= GraphRef.BatchSize) { - break; - } + break; + } + // Deal with end of text token. + if (llama_token_is_eog(GraphRef.LlamaModel, + llama_sampling_last(CtxSampling))) { + if (GraphRef.EnableLog) { + spdlog::info("[WASI-NN] GGML backend: EOS token found"sv); } + break; + } + // Evaluate the output token. + ReturnCode = evaluateTokens(GraphRef, LlamaContext, {Id}, NPast); + if (ReturnCode != ErrNo::Success) { + break; } } if (GraphRef.EnableDebugLog) { spdlog::info( "[WASI-NN][Debug] GGML backend: enter main predict loop...Done"sv); } + // End of main predict loop. if (GraphRef.EnableLog) { llama_print_timings(LlamaContext); @@ -748,8 +1221,20 @@ Expect<ErrNo> compute(WasiNNEnvironment &Env, uint32_t ContextId) noexcept { // We free the contexts here to keep the ggml plugin stateless. // Users could fully control the contexts by themselves via their prompt. + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: delete llama context to make it stateless"sv); + } llama_sampling_free(CtxSampling); llama_free(LlamaContext); + if (CxtRef.LlavaImageEmbd != nullptr) { + llava_image_embed_free(CxtRef.LlavaImageEmbd); + CxtRef.LlavaImageEmbd = nullptr; + } + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: delete llama context to make it stateless...Done"sv); + } if (GraphRef.EnableDebugLog) { spdlog::info("[WASI-NN][Debug] GGML backend: compute...Done"sv); @@ -762,23 +1247,39 @@ Expect<ErrNo> getOutputSingle(WasiNNEnvironment &Env, uint32_t ContextId, uint32_t Index, Span<uint8_t> OutBuffer, uint32_t &BytesWritten) noexcept { auto &CxtRef = Env.NNContext[ContextId].get<Context>(); + auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get<Graph>(); + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: getOutputSingle with Index {}"sv, + Index); + } // Index 1 is for the metadata of the outputs. if (Index == 1) { std::string Metadata; - auto Res = details::buildOutputMetadata(CxtRef, Metadata); + auto Res = buildOutputMetadata(CxtRef, Metadata); if (Res != ErrNo::Success) { spdlog::error( "[WASI-NN] GGML backend: Failed to build output metadata."sv); return Res; } std::copy_n(Metadata.data(), Metadata.length(), OutBuffer.data()); - BytesWritten = Metadata.length(); + BytesWritten = static_cast<uint32_t>(Metadata.length()); + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: getOutputSingle with Index {}...Done"sv, + Index); + } return ErrNo::Success; } std::string LastToken = llama_token_to_piece(CxtRef.LlamaContext, CxtRef.LlamaOutputTokens.back()); std::copy_n(LastToken.data(), LastToken.length(), OutBuffer.data()); - BytesWritten = LastToken.length(); + BytesWritten = static_cast<uint32_t>(LastToken.length()); + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: getOutputSingle with Index {}...Done"sv, + Index); + } return ErrNo::Success; } @@ -791,13 +1292,15 @@ Expect<ErrNo> computeSingle(WasiNNEnvironment &Env, if (GraphRef.EnableDebugLog) { spdlog::info("[WASI-NN][Debug] GGML backend: computeSingleToken"sv); } - if (CxtRef.LlamaInputs.size() == 0) { - spdlog::error("[WASI-NN] GGML backend: Llama input is not set!"sv); - return ErrNo::InvalidArgument; - } // New compute single token context. if (CxtRef.LlamaContext == nullptr) { + // Check if the input is set before setting up the context. + if (CxtRef.LlamaInputs.size() == 0) { + spdlog::error("[WASI-NN] GGML backend: Llama input is not set!"sv); + return ErrNo::InvalidArgument; + } + // Clear the outputs. if (GraphRef.EnableDebugLog) { spdlog::info( @@ -812,139 +1315,124 @@ Expect<ErrNo> computeSingle(WasiNNEnvironment &Env, // Initialize the llama context. gpt_params GPTParams; - GPTParams.sparams.temp = GraphRef.Temp; - GPTParams.sparams.top_p = GraphRef.TopP; - GPTParams.sparams.penalty_repeat = GraphRef.RepeatPenalty; - GPTParams.sparams.penalty_present = GraphRef.PresencePenalty; - GPTParams.sparams.penalty_freq = GraphRef.FrequencyPenalty; - CxtRef.LlamaSampling = llama_sampling_init(GPTParams.sparams); llama_context_params ContextParams = llama_context_default_params(); - ContextParams.n_ctx = GraphRef.CtxSize; - ContextParams.n_batch = GraphRef.BatchSize; - ContextParams.n_threads = GraphRef.Threads; - ContextParams.n_threads_batch = GraphRef.Threads; + setupGPTParam(GraphRef, GPTParams); + setupContextParam(GraphRef, ContextParams); CxtRef.LlamaContext = llama_new_context_with_model(GraphRef.LlamaModel, ContextParams); - CxtRef.LlamaEmbd.clear(); + CxtRef.LlamaSampling = llama_sampling_init(GPTParams.sparams); CxtRef.LlamaNPast = 0; - CxtRef.LlamaNConsumed = 0; - } - - // Get the context size. - const uint64_t NCtx = llama_n_ctx(CxtRef.LlamaContext); - // Minus 4 for the special tokens. (Such as <BOS>, <EOS>, ... tokens.) - const uint64_t MaxTokensListSize = NCtx - 4; - // Use the const sequence id here. - const llama_seq_id SequenceId = 0; - // Check if the input is too long. - if (static_cast<uint64_t>(CxtRef.LlamaInputs.size()) > MaxTokensListSize) { - if (GraphRef.EnableLog) { - spdlog::info( - "[WASI-NN] GGML backend: the prompt is too long. Your input has {} tokens. Please reduce it to {} tokens."sv, - CxtRef.LlamaInputs.size(), MaxTokensListSize); + // Get the context size. + const uint64_t NCtx = llama_n_ctx(CxtRef.LlamaContext); + // Minus 4 for the special tokens. (Such as <BOS>, <EOS>, ... tokens.) + const uint64_t MaxTokensListSize = NCtx - 4; + // Return value. + auto ReturnCode = ErrNo::Success; + + // Check if the input is too long. + if (static_cast<uint64_t>(CxtRef.LlamaInputs.size()) > MaxTokensListSize) { + if (GraphRef.EnableLog) { + spdlog::info( + "[WASI-NN] GGML backend: the prompt is too long. Your input has {} tokens. Please reduce it to {} tokens."sv, + CxtRef.LlamaInputs.size(), MaxTokensListSize); + } + return ErrNo::PromptTooLong; } - return ErrNo::PromptTooLong; - } - // Main predict loop. - while (true) { - if (!CxtRef.LlamaEmbd.empty()) { - // Input too long. - if (static_cast<uint64_t>(CxtRef.LlamaEmbd.size()) > MaxTokensListSize) { - if (GraphRef.EnableLog) { - spdlog::info( - "[WASI-NN] GGML backend: the prompt is too long. Your input has {} tokens. Please reduce it to {} tokens."sv, - CxtRef.LlamaEmbd.size(), MaxTokensListSize); - } - return ErrNo::PromptTooLong; + // Evaluate input tokens. + if (CxtRef.LlavaImageEmbd == nullptr) { + // Text only prompt. + ReturnCode = + evaluateTokens(GraphRef, CxtRef.LlamaContext, + std::move(CxtRef.LlamaInputs), CxtRef.LlamaNPast); + if (ReturnCode != ErrNo::Success) { + spdlog::error( + "[WASI-NN] GGML backend: failed to evaluate input tokens."sv); + return ReturnCode; } - - // We do not swap context here. End the inference if the context is full. - if (CxtRef.LlamaNPast + static_cast<uint64_t>(CxtRef.LlamaEmbd.size()) > - NCtx) { - if (GraphRef.EnableLog) { - spdlog::info( - "[WASI-NN] GGML backend: the context if full ({} / {} tokens). Please increase your ctx-size."sv, - CxtRef.LlamaNPast + - static_cast<uint64_t>(CxtRef.LlamaEmbd.size()), - NCtx); - } - return ErrNo::ContextFull; + } else { + // Llava format prompt with image data. + std::vector<llama_token> EmbdInputBeforeImage( + CxtRef.LlamaInputs.begin(), + CxtRef.LlamaInputs.begin() + CxtRef.LlavaImagePosition); + std::vector<llama_token> EmbdInputAfterImage( + CxtRef.LlamaInputs.begin() + CxtRef.LlavaImagePosition, + CxtRef.LlamaInputs.end()); + ReturnCode = + evaluateTokens(GraphRef, CxtRef.LlamaContext, + std::move(EmbdInputBeforeImage), CxtRef.LlamaNPast); + if (ReturnCode != ErrNo::Success) { + spdlog::error( + "[WASI-NN] GGML backend: failed to evaluate input tokens before image."sv); + return ReturnCode; } - - // Evaluate tokens in batches. - for (uint64_t I = 0; I < static_cast<uint64_t>(CxtRef.LlamaEmbd.size()); - I += GraphRef.BatchSize) { - uint64_t NEval = static_cast<uint64_t>(CxtRef.LlamaEmbd.size()) - I; - if (NEval > static_cast<uint64_t>(GraphRef.BatchSize)) { - NEval = GraphRef.BatchSize; - } - // llama_batch_get_one(*token, n_tokens, position, sequence_id) - // This will return batch for single sequence of tokens starting at - // position. - auto Status = - llama_decode(CxtRef.LlamaContext, - llama_batch_get_one(&CxtRef.LlamaEmbd[I], NEval, - CxtRef.LlamaNPast, SequenceId)); - if (Status == 1) { - spdlog::error( - "[WASI-NN] GGML backend: failed to llama_decode: try reducing the size of the batch or increasing the size of context"sv); - return ErrNo::RuntimeError; - } - if (Status < 0) { - spdlog::error( - "[WASI-NN] GGML backend: failed to llama_decode: internal fatal error. Please open an issue on GitHub"sv); - return ErrNo::RuntimeError; - } - - CxtRef.LlamaNPast += NEval; + bool EvalImageStatus = llava_eval_image_embed( + CxtRef.LlamaContext, CxtRef.LlavaImageEmbd, + static_cast<int>(GraphRef.BatchSize), &CxtRef.LlamaNPast); + if (!EvalImageStatus) { + spdlog::error( + "[WASI-NN] GGML backend: failed to evaluate embed image tokens."sv); + return ErrNo::RuntimeError; + } + ReturnCode = + evaluateTokens(GraphRef, CxtRef.LlamaContext, + std::move(EmbdInputAfterImage), CxtRef.LlamaNPast); + if (ReturnCode != ErrNo::Success) { + spdlog::error( + "[WASI-NN] GGML backend: failed to evaluate input tokens after image."sv); + return ReturnCode; } } + } - CxtRef.LlamaEmbd.clear(); - - if (static_cast<uint64_t>(CxtRef.LlamaInputs.size()) <= - CxtRef.LlamaNConsumed) { - const llama_token Id = llama_sampling_sample( - CxtRef.LlamaSampling, CxtRef.LlamaContext, nullptr); - llama_sampling_accept(CxtRef.LlamaSampling, CxtRef.LlamaContext, Id, - true); - CxtRef.LlamaEmbd.emplace_back(Id); - // Save the output token. - CxtRef.LlamaOutputTokens.emplace_back(Id); - CxtRef.LlamaOutputs += llama_token_to_piece(CxtRef.LlamaContext, Id); - // Deal with end of text token. - if (llama_sampling_last(CxtRef.LlamaSampling) == - llama_token_eos(GraphRef.LlamaModel)) { - if (GraphRef.EnableLog) { - spdlog::info("[WASI-NN] GGML backend: EOS token found"sv); - } - return ErrNo::EndOfSequence; - } - return ErrNo::Success; - } else { - while (static_cast<uint64_t>(CxtRef.LlamaInputs.size()) > - CxtRef.LlamaNConsumed) { - CxtRef.LlamaEmbd.push_back(CxtRef.LlamaInputs[CxtRef.LlamaNConsumed]); - // Push the prompt in the sampling context. - llama_sampling_accept(CxtRef.LlamaSampling, CxtRef.LlamaContext, - CxtRef.LlamaInputs[CxtRef.LlamaNConsumed], false); - ++CxtRef.LlamaNConsumed; - if (CxtRef.LlamaEmbd.size() >= GraphRef.BatchSize) { - break; - } - } + // Main predict process. + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: enter main predict process"sv); + } + auto ReturnCode = ErrNo::Success; + const llama_token Id = + llama_sampling_sample(CxtRef.LlamaSampling, CxtRef.LlamaContext, nullptr); + llama_sampling_accept(CxtRef.LlamaSampling, CxtRef.LlamaContext, Id, true); + + // Save the output token. + // In single token mode, we do not handle StreamStdout and ReversePrompt. + CxtRef.LlamaOutputTokens.emplace_back(Id); + CxtRef.LlamaOutputs += llama_token_to_piece(CxtRef.LlamaContext, Id); + // Deal with end of text token. + if (llama_token_is_eog(GraphRef.LlamaModel, + llama_sampling_last(CxtRef.LlamaSampling))) { + ReturnCode = ErrNo::EndOfSequence; + if (GraphRef.EnableLog) { + spdlog::info("[WASI-NN] GGML backend: EOS token found"sv); } } + // Evaluate the output token if not EOS. + if (ReturnCode != ErrNo::EndOfSequence) { + ReturnCode = + evaluateTokens(GraphRef, CxtRef.LlamaContext, {Id}, CxtRef.LlamaNPast); + } + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: enter main predict process...Done"sv); + } + // End of main predict process. - return ErrNo::Success; + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: computeSingleToken...Done"sv); + } + + return ReturnCode; } Expect<ErrNo> finiSingle(WasiNNEnvironment &Env, uint32_t ContextId) noexcept { auto &CxtRef = Env.NNContext[ContextId].get<Context>(); auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get<Graph>(); + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: finiSingle"sv); + } + // Logging for the llama timings. if (GraphRef.EnableLog) { llama_print_timings(CxtRef.LlamaContext); @@ -971,19 +1459,49 @@ Expect<ErrNo> finiSingle(WasiNNEnvironment &Env, uint32_t ContextId) noexcept { llama_free(CxtRef.LlamaContext); CxtRef.LlamaSampling = nullptr; CxtRef.LlamaContext = nullptr; + if (CxtRef.LlavaImageEmbd != nullptr) { + llava_image_embed_free(CxtRef.LlavaImageEmbd); + CxtRef.LlavaImageEmbd = nullptr; + } if (GraphRef.EnableDebugLog) { spdlog::info( "[WASI-NN][Debug] GGML backend: finiSingle: free the llama context...Done"sv); } // Reset the context variables. - CxtRef.LlamaEmbd.clear(); CxtRef.LlamaNPast = 0; - CxtRef.LlamaNConsumed = 0; + + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: finiSingle...Done"sv); + } return ErrNo::Success; } +Expect<ErrNo> unload(WasiNNEnvironment &Env, uint32_t GraphId) noexcept { + auto &GraphRef = Env.NNGraph[GraphId].get<Graph>(); + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: unload"sv); + } + if (GraphRef.LlamaModel != nullptr) { + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: unload: free llama model"sv); + } + llama_free_model(GraphRef.LlamaModel); + GraphRef.LlamaModel = nullptr; + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: unload: free llama model...Done"sv); + } + } + Env.NNGraph.erase(Env.NNGraph.begin() + GraphId); + Env.mdRemoveById(GraphId); + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: unload...Done"sv); + } + return ErrNo::Success; +} + #else namespace { Expect<ErrNo> reportBackendNotSupported() noexcept { @@ -1011,6 +1529,19 @@ Expect<ErrNo> getOutput(WasiNNEnvironment &, uint32_t, uint32_t, Span<uint8_t>, Expect<ErrNo> compute(WasiNNEnvironment &, uint32_t) noexcept { return reportBackendNotSupported(); } +Expect<ErrNo> getOutputSingle(WasiNNEnvironment &, uint32_t, uint32_t, + Span<uint8_t>, uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect<ErrNo> computeSingle(WasiNNEnvironment &, uint32_t) noexcept { + return reportBackendNotSupported(); +} +Expect<ErrNo> finiSingle(WasiNNEnvironment &, uint32_t) noexcept { + return reportBackendNotSupported(); +} +Expect<ErrNo> unload(WasiNNEnvironment &, uint32_t) noexcept { + return reportBackendNotSupported(); +} #endif } // namespace WasmEdge::Host::WASINN::GGML diff --git a/plugins/wasi_nn/ggml.h b/plugins/wasi_nn/ggml.h index ad3f28d9b073..b29dcd0b2c78 100644 --- a/plugins/wasi_nn/ggml.h +++ b/plugins/wasi_nn/ggml.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once @@ -9,6 +9,7 @@ #ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_GGML #include <common.h> #include <llama.h> +#include <llava.h> #endif namespace WasmEdge::Host::WASINN { @@ -28,11 +29,17 @@ struct Graph { bool Embedding = false; uint64_t NPredict; std::string ReversePrompt; + std::string MMProjModelPath; + std::string ImagePath; // Model parameters: + int64_t MainGPU = 0; // Use GPU 0 by default int64_t NGPULayers = 0; + std::vector<float> TensorSplit; + bool UseMMap = true; // Context parameters: uint64_t CtxSize; uint64_t BatchSize; + uint64_t UBatchSize; uint64_t Threads; // Sampling parameters: double Temp = 0.80; @@ -40,6 +47,7 @@ struct Graph { double RepeatPenalty = 1.10; double PresencePenalty = 0.00; double FrequencyPenalty = 0.00; + std::string Grammar; }; struct Context { @@ -47,14 +55,16 @@ struct Context { Context(size_t GId, Graph &) noexcept : GraphId(GId) {} size_t GraphId; std::vector<llama_token> LlamaInputs; + uint64_t LlamaNInputs = 0; std::string LlamaOutputs; std::vector<llama_token> LlamaOutputTokens; // Preserve for computing single token llama_context *LlamaContext = nullptr; struct llama_sampling_context *LlamaSampling = nullptr; - std::vector<llama_token> LlamaEmbd; - uint64_t LlamaNPast; - uint64_t LlamaNConsumed; + int32_t LlamaNPast = 0; + // Preserve for llava + struct llava_image_embed *LlavaImageEmbd = nullptr; + size_t LlavaImagePosition = 0; }; #else struct Graph {}; @@ -88,4 +98,6 @@ Expect<WASINN::ErrNo> computeSingle(WASINN::WasiNNEnvironment &Env, uint32_t ContextId) noexcept; Expect<WASINN::ErrNo> finiSingle(WASINN::WasiNNEnvironment &Env, uint32_t ContextId) noexcept; +Expect<WASINN::ErrNo> unload(WASINN::WasiNNEnvironment &Env, + uint32_t GraphId) noexcept; } // namespace WasmEdge::Host::WASINN::GGML diff --git a/plugins/wasi_nn/neuralspeed.cpp b/plugins/wasi_nn/neuralspeed.cpp new file mode 100644 index 000000000000..0d29c59c77fb --- /dev/null +++ b/plugins/wasi_nn/neuralspeed.cpp @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "neuralspeed.h" +#include "wasinnenv.h" + +namespace WasmEdge::Host::WASINN::NeuralSpeed { +namespace { +Expect<WASINN::ErrNo> reportBackendNotSupported() noexcept { + spdlog::error("[WASI-NN] Neural Speed backend is removed due to the upstream " + "end-of-life. " + "Reference: https://github.com/intel/neural-speed"sv); + return WASINN::ErrNo::InvalidArgument; +} +} // namespace + +Expect<WASINN::ErrNo> load(WASINN::WasiNNEnvironment &, + Span<const Span<uint8_t>>, WASINN::Device, + uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> initExecCtx(WASINN::WasiNNEnvironment &, uint32_t, + uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> setInput(WASINN::WasiNNEnvironment &, uint32_t, uint32_t, + const TensorData &) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> getOutput(WASINN::WasiNNEnvironment &, uint32_t, uint32_t, + Span<uint8_t>, uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> compute(WASINN::WasiNNEnvironment &, uint32_t) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> unload(WASINN::WasiNNEnvironment &, uint32_t) noexcept { + return reportBackendNotSupported(); +} +} // namespace WasmEdge::Host::WASINN::NeuralSpeed diff --git a/plugins/wasi_nn/neuralspeed.h b/plugins/wasi_nn/neuralspeed.h new file mode 100644 index 000000000000..b74b3c2782e2 --- /dev/null +++ b/plugins/wasi_nn/neuralspeed.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "plugin/plugin.h" +#include "types.h" + +namespace WasmEdge::Host::WASINN { +struct WasiNNEnvironment; +} + +namespace WasmEdge::Host::WASINN::NeuralSpeed { +struct Graph {}; +struct Context { + Context(size_t, Graph &) noexcept {} +}; + +struct Environ {}; + +Expect<WASINN::ErrNo> load(WASINN::WasiNNEnvironment &Env, + Span<const Span<uint8_t>> Builders, + WASINN::Device Device, uint32_t &GraphId) noexcept; +Expect<WASINN::ErrNo> initExecCtx(WASINN::WasiNNEnvironment &Env, + uint32_t GraphId, + uint32_t &ContextId) noexcept; +Expect<WASINN::ErrNo> setInput(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId, uint32_t Index, + const TensorData &Tensor) noexcept; +Expect<WASINN::ErrNo> getOutput(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId, uint32_t Index, + Span<uint8_t> OutBuffer, + uint32_t &BytesWritten) noexcept; +Expect<WASINN::ErrNo> compute(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId) noexcept; +Expect<WASINN::ErrNo> unload(WASINN::WasiNNEnvironment &Env, + uint32_t GraphId) noexcept; + +} // namespace WasmEdge::Host::WASINN::NeuralSpeed diff --git a/plugins/wasi_nn/onnx.cpp b/plugins/wasi_nn/onnx.cpp index 3fa4b32611e6..7b7cb6f977ef 100644 --- a/plugins/wasi_nn/onnx.cpp +++ b/plugins/wasi_nn/onnx.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "onnx.h" #include "wasinnenv.h" diff --git a/plugins/wasi_nn/onnx.h b/plugins/wasi_nn/onnx.h index e5aaff1add73..6d46e02b3c25 100644 --- a/plugins/wasi_nn/onnx.h +++ b/plugins/wasi_nn/onnx.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasi_nn/openvino.cpp b/plugins/wasi_nn/openvino.cpp index 9c0625ac394e..72fcb70c25c1 100644 --- a/plugins/wasi_nn/openvino.cpp +++ b/plugins/wasi_nn/openvino.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "openvino.h" #include "wasinnenv.h" diff --git a/plugins/wasi_nn/openvino.h b/plugins/wasi_nn/openvino.h index 0ae3a2a78088..b3616666965b 100644 --- a/plugins/wasi_nn/openvino.h +++ b/plugins/wasi_nn/openvino.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasi_nn/piper.cpp b/plugins/wasi_nn/piper.cpp new file mode 100644 index 000000000000..fdc5c262475b --- /dev/null +++ b/plugins/wasi_nn/piper.cpp @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "piper.h" +#include "wasinnenv.h" + +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_PIPER +#include "simdjson.h" +#include "types.h" +#include <cstring> +#include <filesystem> +#include <fstream> +#include <functional> +#include <ios> +#include <map> +#include <memory> +#include <optional> +#include <piper.hpp> +#include <string> +#include <string_view> +#include <tuple> +#include <vector> +#endif + +namespace WasmEdge::Host::WASINN::Piper { +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_PIPER + +template <typename T> +std::tuple<WASINN::ErrNo, bool> getOption(simdjson::dom::object &Object, + std::string_view Key, T &Result) { + if (auto Error = Object[Key].get(Result)) { + if (Error == simdjson::error_code::NO_SUCH_FIELD) { + return {WASINN::ErrNo::Success, false}; + } + spdlog::error( + "[WASI-NN] Piper backend: Unable to retrieve the \"{}\" option: {}"sv, + Key, simdjson::error_message(Error)); + return {WASINN::ErrNo::InvalidArgument, false}; + } + return {WASINN::ErrNo::Success, true}; +} + +template <typename T, typename U = T> +WASINN::ErrNo getOptionalOption(simdjson::dom::object &Object, + std::string_view Key, + std::optional<T> &Result) { + auto Value = U{}; + auto [Err, HasValue] = getOption(Object, Key, Value); + if (HasValue) { + Result = Value; + } + return Err; +} + +Expect<WASINN::ErrNo> parseRunConfig(RunConfig &RunConfig, + const std::string &String) noexcept { + simdjson::dom::parser Parser; + simdjson::dom::element Doc; + if (auto Error = Parser.parse(String).get(Doc)) { + spdlog::error("[WASI-NN] Piper backend: Parse run config error: {}"sv, + simdjson::error_message(Error)); + return WASINN::ErrNo::InvalidEncoding; + } + simdjson::dom::object Object; + if (auto Error = Doc.get(Object)) { + spdlog::error( + "[WASI-NN] Piper backend: The run config is not an object: {}"sv, + simdjson::error_message(Error)); + return WASINN::ErrNo::InvalidArgument; + } + + auto ModelPath = std::optional<std::string_view>{}; + if (auto Err = getOptionalOption(Object, "model", ModelPath); + Err != WASINN::ErrNo::Success) { + return Err; + } + // Verify model file exists + if (ModelPath) { + auto Path = std::filesystem::u8path(ModelPath.value()); + if (!std::filesystem::exists(Path)) { + spdlog::error("[WASI-NN] Piper backend: Model file doesn't exist"sv); + return WASINN::ErrNo::InvalidArgument; + } + RunConfig.ModelPath = Path; + } else { + spdlog::error( + "[WASI-NN] Piper backend: The model option is required but not provided"sv); + return WASINN::ErrNo::InvalidArgument; + } + + auto ModelConfigPath = std::optional<std::string_view>{}; + if (auto Err = getOptionalOption(Object, "config", ModelConfigPath); + Err != WASINN::ErrNo::Success) { + return Err; + } + if (ModelConfigPath) { + RunConfig.ModelConfigPath = + std::filesystem::u8path(ModelConfigPath.value()); + } else { + RunConfig.ModelConfigPath = RunConfig.ModelPath; + RunConfig.ModelConfigPath += ".json"; + } + // Verify model config exists + if (!std::filesystem::exists(RunConfig.ModelConfigPath)) { + spdlog::error("[WASI-NN] Piper backend: Model config doesn't exist"sv); + return WASINN::ErrNo::InvalidArgument; + } + + { + auto Value = std::optional<std::string_view>{}; + if (auto Err = getOptionalOption(Object, "output_type", Value); + Err != WASINN::ErrNo::Success) { + return Err; + } + if (Value) { + if (Value.value() == "wav") { + RunConfig.OutputType = RunConfigOutputType::OUTPUT_WAV; + } else if (Value.value() == "raw") { + RunConfig.OutputType = RunConfigOutputType::OUTPUT_RAW; + } else { + spdlog::error( + "[WASI-NN] Piper backend: The output_type option has an unknown value {}."sv, + Value.value()); + return WASINN::ErrNo::InvalidArgument; + } + } + } + if (auto Err = getOptionalOption(Object, "speaker", RunConfig.SpeakerId); + Err != WASINN::ErrNo::Success) { + return Err; + } + if (auto Err = getOptionalOption<float, double>(Object, "noise_scale", + RunConfig.NoiseScale); + Err != WASINN::ErrNo::Success) { + return Err; + } + if (auto Err = getOptionalOption<float, double>(Object, "length_scale", + RunConfig.LengthScale); + Err != WASINN::ErrNo::Success) { + return Err; + } + if (auto Err = + getOptionalOption<float, double>(Object, "noise_w", RunConfig.NoiseW); + Err != WASINN::ErrNo::Success) { + return Err; + } + if (auto Err = getOptionalOption<float, double>( + Object, "sentence_silence", RunConfig.SentenceSilenceSeconds); + Err != WASINN::ErrNo::Success) { + return Err; + } + { + auto PhonemeSilence = std::optional<simdjson::dom::object>{}; + if (auto Err = getOptionalOption(Object, "phoneme_silence", PhonemeSilence); + Err != WASINN::ErrNo::Success) { + return Err; + } + if (PhonemeSilence) { + for (auto [Key, Value] : PhonemeSilence.value()) { + auto PhonemeStr = std::string{Key}; + if (!piper::isSingleCodepoint(PhonemeStr)) { + spdlog::error( + "[WASI-NN] Piper backend: Phoneme '{}' is not a single codepoint (phoneme_silence)."sv, + PhonemeStr); + return WASINN::ErrNo::InvalidArgument; + } + auto Seconds = Value.get_double(); + if (auto Error = Seconds.error()) { + spdlog::error( + "[WASI-NN] Piper backend: Failed to get silence seconds for phoneme '{}' as a double: {}"sv, + PhonemeStr, simdjson::error_message(Error)); + return WASINN::ErrNo::InvalidArgument; + } + if (!RunConfig.PhonemeSilenceSeconds) { + RunConfig.PhonemeSilenceSeconds.emplace(); + } + auto Phoneme = piper::getCodepoint(PhonemeStr); + RunConfig.PhonemeSilenceSeconds.value()[Phoneme] = Seconds.value(); + } + } + } + { + auto Path = std::optional<std::string_view>{}; + if (auto Err = getOptionalOption(Object, "espeak_data", Path); + Err != WASINN::ErrNo::Success) { + return Err; + } + if (Path) { + RunConfig.ESpeakDataPath = std::filesystem::u8path(Path.value()); + } + } + { + auto Path = std::optional<std::string_view>{}; + if (auto Err = getOptionalOption(Object, "tashkeel_model", Path); + Err != WASINN::ErrNo::Success) { + return Err; + } + if (Path) { + RunConfig.TashkeelModelPath = std::filesystem::u8path(Path.value()); + } + } + if (auto Err = + std::get<0>(getOption(Object, "json_input", RunConfig.JsonInput)); + Err != WASINN::ErrNo::Success) { + return Err; + } + return WASINN::ErrNo::Success; +} + +Expect<WASINN::ErrNo> load(WASINN::WasiNNEnvironment &Env, + Span<const Span<uint8_t>> Builders, WASINN::Device, + uint32_t &GraphId) noexcept { + // The graph builder length must be 1. + if (Builders.size() != 1) { + spdlog::error( + "[WASI-NN] Piper backend: Wrong GraphBuilder Length {:d}, expect 1"sv, + Builders.size()); + return WASINN::ErrNo::InvalidArgument; + } + + // Add a new graph. + auto &GraphRef = Env.NNGraph.emplace_back(Backend::Piper).get<Graph>(); + GraphRef.Config = std::make_unique<RunConfig>(); + auto String = std::string{Builders[0].begin(), Builders[0].end()}; + if (auto Res = parseRunConfig(*GraphRef.Config, String); + Res != WASINN::ErrNo::Success) { + Env.NNGraph.pop_back(); + spdlog::error("[WASI-NN] Piper backend: Failed to parse run config."sv); + return Res; + } + + GraphRef.PiperConfig = std::make_unique<piper::PiperConfig>(); + GraphRef.Voice = std::make_unique<piper::Voice>(); + piper::loadVoice(*GraphRef.PiperConfig, GraphRef.Config->ModelPath.string(), + GraphRef.Config->ModelConfigPath.string(), *GraphRef.Voice, + GraphRef.Config->SpeakerId); + GraphRef.SpeakerId = GraphRef.Config->SpeakerId; + + if (GraphRef.Voice->phonemizeConfig.phonemeType == + piper::PhonemeType::eSpeakPhonemes) { + if (!GraphRef.Config->ESpeakDataPath) { + spdlog::error( + "[WASI-NN] Piper backend: espeak-ng data directory is required for eSpeakPhonemes"sv); + Env.NNGraph.pop_back(); + return WASINN::ErrNo::InvalidArgument; + } + if (!std::filesystem::exists(GraphRef.Config->ESpeakDataPath.value())) { + spdlog::error( + "[WASI-NN] Piper backend: espeak-ng data directory doesn't exist"sv); + Env.NNGraph.pop_back(); + return WASINN::ErrNo::InvalidArgument; + } + // User provided path + GraphRef.PiperConfig->eSpeakDataPath = + GraphRef.Config->ESpeakDataPath->string(); + } else { + // Not using eSpeak + GraphRef.PiperConfig->useESpeak = false; + } + + // Enable libtashkeel for Arabic + if (GraphRef.Voice->phonemizeConfig.eSpeak.voice == "ar") { + if (!GraphRef.Config->TashkeelModelPath) { + spdlog::error( + "[WASI-NN] Piper backend: libtashkeel ort model is required for Arabic"sv); + Env.NNGraph.pop_back(); + return WASINN::ErrNo::InvalidArgument; + } + if (!std::filesystem::exists(GraphRef.Config->TashkeelModelPath.value())) { + spdlog::error( + "[WASI-NN] Piper backend: libtashkeel ort model doesn't exist"sv); + Env.NNGraph.pop_back(); + return WASINN::ErrNo::InvalidArgument; + } + GraphRef.PiperConfig->useTashkeel = true; + // User provided path + GraphRef.PiperConfig->tashkeelModelPath = + GraphRef.Config->TashkeelModelPath->string(); + } + + piper::initialize(*GraphRef.PiperConfig); + + // Scales + if (GraphRef.Config->NoiseScale) { + GraphRef.Voice->synthesisConfig.noiseScale = + GraphRef.Config->NoiseScale.value(); + } + + if (GraphRef.Config->LengthScale) { + GraphRef.Voice->synthesisConfig.lengthScale = + GraphRef.Config->LengthScale.value(); + } + + if (GraphRef.Config->NoiseW) { + GraphRef.Voice->synthesisConfig.noiseW = GraphRef.Config->NoiseW.value(); + } + + if (GraphRef.Config->SentenceSilenceSeconds) { + GraphRef.Voice->synthesisConfig.sentenceSilenceSeconds = + GraphRef.Config->SentenceSilenceSeconds.value(); + } + + if (GraphRef.Config->PhonemeSilenceSeconds) { + if (!GraphRef.Voice->synthesisConfig.phonemeSilenceSeconds) { + // Overwrite + GraphRef.Voice->synthesisConfig.phonemeSilenceSeconds = + GraphRef.Config->PhonemeSilenceSeconds; + } else { + // Merge + for (const auto &[Phoneme, SilenceSeconds] : + *GraphRef.Config->PhonemeSilenceSeconds) { + GraphRef.Voice->synthesisConfig.phonemeSilenceSeconds->try_emplace( + Phoneme, SilenceSeconds); + } + } + } // if phonemeSilenceSeconds + + // Store the loaded graph. + GraphId = Env.NNGraph.size() - 1; + return WASINN::ErrNo::Success; +} + +Expect<WASINN::ErrNo> initExecCtx(WASINN::WasiNNEnvironment &Env, + uint32_t GraphId, + uint32_t &ContextId) noexcept { + // Create context. + Env.NNContext.emplace_back(GraphId, Env.NNGraph[GraphId]); + ContextId = Env.NNContext.size() - 1; + return WASINN::ErrNo::Success; +} + +template <typename T> +WASINN::ErrNo getOptionalInputOption(simdjson::dom::object &Object, + std::string_view Key, + std::optional<T> &Result) { + auto Value = T{}; + if (auto Error = Object[Key].get(Value)) { + if (Error == simdjson::error_code::NO_SUCH_FIELD) { + return WASINN::ErrNo::Success; + } + spdlog::error( + "[WASI-NN] Piper backend: Unable to retrieve \"{}\" from json input: {}"sv, + Key, simdjson::error_message(Error)); + return WASINN::ErrNo::InvalidArgument; + } + Result = Value; + return WASINN::ErrNo::Success; +} + +Expect<WASINN::ErrNo> setInput(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId, uint32_t Index, + const TensorData &Tensor) noexcept { + if (Index != 0) { + spdlog::error("[WASI-NN] Piper backend: Input index must be 0."sv); + return WASINN::ErrNo::InvalidArgument; + } + if (!(Tensor.Dimension.size() == 1 && Tensor.Dimension[0] == 1)) { + spdlog::error( + "[WASI-NN] Piper backend: Input tensor dimension must be [1]."sv); + return WASINN::ErrNo::InvalidArgument; + } + + auto &CxtRef = Env.NNContext[ContextId].get<Context>(); + auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get<Graph>(); + + auto Line = std::string{Tensor.Tensor.begin(), Tensor.Tensor.end()}; + + if (GraphRef.Config->JsonInput) { + simdjson::dom::parser Parser; + simdjson::dom::element Doc; + if (auto Error = Parser.parse(Line).get(Doc)) { + spdlog::error("[WASI-NN] Piper backend: Parse json input error: {}"sv, + simdjson::error_message(Error)); + return WASINN::ErrNo::InvalidEncoding; + } + simdjson::dom::object Object; + if (auto Error = Doc.get(Object)) { + spdlog::error( + "[WASI-NN] Piper backend: The json input is not an object: {}"sv, + simdjson::error_message(Error)); + return WASINN::ErrNo::InvalidArgument; + } + + // Text is required + auto Text = std::string_view{}; + if (auto Error = Object["text"].get(Text)) { + spdlog::error( + "[WASI-NN] Piper backend: Unable to retrieve required \"text\" from json input: {}"sv, + simdjson::error_message(Error)); + return WASINN::ErrNo::InvalidArgument; + } + Line = Text; + + // Override speaker id + auto SpeakerId = std::optional<piper::SpeakerId>{}; + if (auto Err = getOptionalInputOption(Object, "speaker_id", SpeakerId); + Err != WASINN::ErrNo::Success) { + return Err; + } + if (SpeakerId) { + GraphRef.Voice->synthesisConfig.speakerId = SpeakerId; + } else { + auto SpeakerName = std::optional<std::string_view>{}; + if (auto Err = getOptionalInputOption(Object, "speaker", SpeakerName); + Err != WASINN::ErrNo::Success) { + return Err; + } + if (SpeakerName) { + // Resolve to id using speaker id map + auto Name = std::string{SpeakerName.value()}; + if (GraphRef.Voice->modelConfig.speakerIdMap && + GraphRef.Voice->modelConfig.speakerIdMap->count(Name) > 0) { + GraphRef.Voice->synthesisConfig.speakerId = + GraphRef.Voice->modelConfig.speakerIdMap.value()[Name]; + } else { + spdlog::warn("[WASI-NN] Piper backend: No speaker named: {}"sv, Name); + } + } + } + } + CxtRef.Line = Line; + return WASINN::ErrNo::Success; +} + +Expect<WASINN::ErrNo> getOutput(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId, uint32_t Index, + Span<uint8_t> OutBuffer, + uint32_t &BytesWritten) noexcept { + if (Index != 0) { + spdlog::error("[WASI-NN] Piper backend: Output index must be 0."sv); + return WASINN::ErrNo::InvalidArgument; + } + + auto &CxtRef = Env.NNContext[ContextId].get<Context>(); + + if (!CxtRef.Output) { + spdlog::error("[WASI-NN] Piper backend: No output available."sv); + return WASINN::ErrNo::InvalidArgument; + } + + if (CxtRef.Output->size() >= std::numeric_limits<uint32_t>::max()) { + spdlog::error( + "[WASI-NN] Piper backend: Output size {} is greater than std::numeric_limits<uint32_t>::max() {}."sv, + CxtRef.Output->size(), std::numeric_limits<uint32_t>::max()); + return WASINN::ErrNo::InvalidArgument; + } + + if (CxtRef.Output->size() > OutBuffer.size_bytes()) { + spdlog::error( + "[WASI-NN] Piper backend: Output size {} is greater than buffer size {}."sv, + CxtRef.Output->size(), OutBuffer.size_bytes()); + return WASINN::ErrNo::InvalidArgument; + } + + std::memcpy(OutBuffer.data(), CxtRef.Output->data(), CxtRef.Output->size()); + BytesWritten = CxtRef.Output->size(); + return WASINN::ErrNo::Success; +} + +Expect<WASINN::ErrNo> compute(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId) noexcept { + auto &CxtRef = Env.NNContext[ContextId].get<Context>(); + auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get<Graph>(); + + if (!CxtRef.Line) { + spdlog::error("[WASI-NN] Piper backend: Input is not set."sv); + return WASINN::ErrNo::InvalidArgument; + } + + auto Result = piper::SynthesisResult{}; + if (GraphRef.Config->OutputType == RunConfigOutputType::OUTPUT_WAV) { + auto AudioFile = + std::stringstream{std::ios::binary | std::ios::in | std::ios::out}; + piper::textToWavFile(*GraphRef.PiperConfig, *GraphRef.Voice, + CxtRef.Line.value(), AudioFile, Result); + auto String = AudioFile.str(); + CxtRef.Output = std::vector<uint8_t>{String.begin(), String.end()}; + } else if (GraphRef.Config->OutputType == RunConfigOutputType::OUTPUT_RAW) { + auto AudioBuffer = std::vector<int16_t>{}; + piper::textToAudio(*GraphRef.PiperConfig, *GraphRef.Voice, + CxtRef.Line.value(), AudioBuffer, Result, nullptr); + CxtRef.Output = std::vector<uint8_t>( + sizeof(decltype(AudioBuffer)::value_type) * AudioBuffer.size()); + std::memcpy(CxtRef.Output->data(), AudioBuffer.data(), + CxtRef.Output->size()); + } + + // Restore config (json_input) + GraphRef.Voice->synthesisConfig.speakerId = GraphRef.SpeakerId; + return WASINN::ErrNo::Success; +} +#else +namespace { +Expect<WASINN::ErrNo> reportBackendNotSupported() noexcept { + spdlog::error("[WASI-NN] Piper backend is not supported."sv); + return WASINN::ErrNo::InvalidArgument; +} +} // namespace + +Expect<WASINN::ErrNo> load(WASINN::WasiNNEnvironment &, + Span<const Span<uint8_t>>, WASINN::Device, + uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> initExecCtx(WASINN::WasiNNEnvironment &, uint32_t, + uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> setInput(WASINN::WasiNNEnvironment &, uint32_t, uint32_t, + const TensorData &) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> getOutput(WASINN::WasiNNEnvironment &, uint32_t, uint32_t, + Span<uint8_t>, uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect<WASINN::ErrNo> compute(WASINN::WasiNNEnvironment &, uint32_t) noexcept { + return reportBackendNotSupported(); +} +#endif +} // namespace WasmEdge::Host::WASINN::Piper diff --git a/plugins/wasi_nn/piper.h b/plugins/wasi_nn/piper.h new file mode 100644 index 000000000000..5ff6c43c1e71 --- /dev/null +++ b/plugins/wasi_nn/piper.h @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "plugin/plugin.h" +#include "types.h" + +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_PIPER +#include <filesystem> +#include <memory> +#include <optional> +#include <piper.hpp> +#include <string> +#include <vector> +#endif + +namespace WasmEdge::Host::WASINN { +struct WasiNNEnvironment; +} + +namespace WasmEdge::Host::WASINN::Piper { +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_PIPER +enum class RunConfigOutputType { OUTPUT_WAV, OUTPUT_RAW }; +struct RunConfig { + // Path to .onnx voice file + std::filesystem::path ModelPath; + + // Path to JSON voice config file + std::filesystem::path ModelConfigPath; + + // Type of output to produce. + // Default is a WAV file. + RunConfigOutputType OutputType = RunConfigOutputType::OUTPUT_WAV; + + // Numerical id of the default speaker (multi-speaker voices) + std::optional<piper::SpeakerId> SpeakerId; + + // Amount of noise to add during audio generation + std::optional<float> NoiseScale; + + // Speed of speaking (1 = normal, < 1 is faster, > 1 is slower) + std::optional<float> LengthScale; + + // Variation in phoneme lengths + std::optional<float> NoiseW; + + // Seconds of silence to add after each sentence + std::optional<float> SentenceSilenceSeconds; + + // Path to espeak-ng data directory + std::optional<std::filesystem::path> ESpeakDataPath; + + // Path to libtashkeel ort model + // https://github.com/mush42/libtashkeel/ + std::optional<std::filesystem::path> TashkeelModelPath; + + // input is JSON instead of text with format: + // { + // "text": str, (required) + // "speaker_id": int, (optional) + // "speaker": str, (optional) + // } + bool JsonInput = false; + + // Seconds of extra silence to insert after a single phoneme + std::optional<std::map<piper::Phoneme, float>> PhonemeSilenceSeconds; +}; +struct Graph { + std::unique_ptr<RunConfig> Config; + std::unique_ptr<piper::PiperConfig> PiperConfig; + std::unique_ptr<piper::Voice> Voice; + std::optional<piper::SpeakerId> SpeakerId; +}; +struct Context { + Context(size_t GId, Graph &) noexcept : GraphId(GId) {} + size_t GraphId; + std::optional<std::string> Line; + std::optional<std::vector<uint8_t>> Output; +}; +#else +struct Graph {}; +struct Context { + Context(size_t, Graph &) noexcept {} +}; +#endif + +struct Environ {}; + +Expect<WASINN::ErrNo> load(WASINN::WasiNNEnvironment &Env, + Span<const Span<uint8_t>> Builders, + WASINN::Device Device, uint32_t &GraphId) noexcept; +Expect<WASINN::ErrNo> initExecCtx(WASINN::WasiNNEnvironment &Env, + uint32_t GraphId, + uint32_t &ContextId) noexcept; +Expect<WASINN::ErrNo> setInput(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId, uint32_t Index, + const TensorData &Tensor) noexcept; +Expect<WASINN::ErrNo> getOutput(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId, uint32_t Index, + Span<uint8_t> OutBuffer, + uint32_t &BytesWritten) noexcept; +Expect<WASINN::ErrNo> compute(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId) noexcept; +} // namespace WasmEdge::Host::WASINN::Piper diff --git a/plugins/wasi_nn/piper.patch b/plugins/wasi_nn/piper.patch new file mode 100644 index 000000000000..c4ba79e27b11 --- /dev/null +++ b/plugins/wasi_nn/piper.patch @@ -0,0 +1,472 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index f96ec44..1e84722 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.13) + + project(piper C CXX) + ++option(BUILD_SHARED_LIBS "Build using shared libraries" OFF) ++ + file(READ "${CMAKE_CURRENT_LIST_DIR}/VERSION" piper_version) + + set(CMAKE_CXX_STANDARD 17) +@@ -13,11 +15,13 @@ if(MSVC) + add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>") + elseif(NOT APPLE) + # Linux flags +- string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra -Wl,-rpath,'$ORIGIN'") ++ string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra") ++ list(APPEND CMAKE_BUILD_RPATH "$ORIGIN") ++ list(APPEND CMAKE_INSTALL_RPATH "$ORIGIN") + string(APPEND CMAKE_C_FLAGS " -Wall -Wextra") + endif() + +-add_executable(piper src/cpp/main.cpp src/cpp/piper.cpp) ++add_library(piper src/cpp/piper.cpp) + add_executable(test_piper src/cpp/test.cpp src/cpp/piper.cpp) + + # NOTE: external project prefix are shortened because of path length restrictions on Windows +@@ -25,7 +29,21 @@ add_executable(test_piper src/cpp/test.cpp src/cpp/piper.cpp) + + # ---- fmt --- + +-if(NOT DEFINED FMT_DIR) ++set(fmt_FOUND FALSE) ++ ++if(NOT fmt_FOUND AND TARGET "fmt::fmt") ++ list(APPEND FMT_LINK_LIBRARIES "fmt::fmt") ++ set(fmt_FOUND TRUE) ++endif() ++ ++if(NOT fmt_FOUND AND NOT DEFINED FMT_DIR) ++ find_package(fmt) ++ if(fmt_FOUND) ++ list(APPEND FMT_LINK_LIBRARIES "fmt::fmt") ++ endif() ++endif() ++ ++if(NOT fmt_FOUND AND NOT DEFINED FMT_DIR) + set(FMT_VERSION "10.0.0") + set(FMT_DIR "${CMAKE_CURRENT_BINARY_DIR}/fi") + +@@ -41,11 +59,33 @@ if(NOT DEFINED FMT_DIR) + add_dependencies(test_piper fmt_external) + endif() + ++if(NOT fmt_FOUND AND DEFINED FMT_DIR) ++ list(APPEND FMT_LINK_LIBRARIES "fmt") ++ list(APPEND FMT_LINK_DIRECTORIES "${FMT_DIR}/lib") ++ list(APPEND FMT_INCLUDE_DIRECTORIES "${FMT_DIR}/include") ++ set(fmt_FOUND TRUE) ++endif() ++ + # ---- spdlog --- + +-if(NOT DEFINED SPDLOG_DIR) ++set(spdlog_FOUND FALSE) ++ ++if(NOT spdlog_FOUND AND TARGET "spdlog::spdlog") ++ list(APPEND SPDLOG_LINK_LIBRARIES "spdlog::spdlog") ++ set(spdlog_FOUND TRUE) ++endif() ++ ++if(NOT spdlog_FOUND AND NOT DEFINED SPDLOG_DIR) ++ find_package(spdlog) ++ if(spdlog_FOUND) ++ list(APPEND SPDLOG_LINK_LIBRARIES "spdlog::spdlog") ++ endif() ++endif() ++ ++if(NOT spdlog_FOUND AND NOT DEFINED SPDLOG_DIR) + set(SPDLOG_DIR "${CMAKE_CURRENT_BINARY_DIR}/si") + set(SPDLOG_VERSION "1.12.0") ++ include(ExternalProject) + ExternalProject_Add( + spdlog_external + PREFIX "${CMAKE_CURRENT_BINARY_DIR}/s" +@@ -56,81 +96,81 @@ if(NOT DEFINED SPDLOG_DIR) + add_dependencies(test_piper spdlog_external) + endif() + ++if(NOT spdlog_FOUND AND DEFINED SPDLOG_DIR) ++ list(APPEND SPDLOG_LINK_LIBRARIES "spdlog") ++ list(APPEND SPDLOG_LINK_DIRECTORIES "${SPDLOG_DIR}/lib") ++ list(APPEND SPDLOG_INCLUDE_DIRECTORIES "${SPDLOG_DIR}/include") ++ set(spdlog_FOUND TRUE) ++endif() ++ + # ---- piper-phonemize --- + +-if(NOT DEFINED PIPER_PHONEMIZE_DIR) +- set(PIPER_PHONEMIZE_DIR "${CMAKE_CURRENT_BINARY_DIR}/pi") +- ExternalProject_Add( +- piper_phonemize_external +- PREFIX "${CMAKE_CURRENT_BINARY_DIR}/p" +- URL "https://github.com/rhasspy/piper-phonemize/archive/refs/heads/master.zip" +- CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${PIPER_PHONEMIZE_DIR} +- ) +- add_dependencies(piper piper_phonemize_external) +- add_dependencies(test_piper piper_phonemize_external) +-endif() ++include(FetchContent) ++find_program(GIT_CMD git REQUIRED) ++FetchContent_Declare( ++ piper_phonemize ++ GIT_REPOSITORY "https://github.com/rhasspy/piper-phonemize.git" ++ GIT_TAG "bfc2e7549957829b0227c66a305d11cc88167bda" # master ++ UPDATE_DISCONNECTED TRUE ++ PATCH_COMMAND "${GIT_CMD}" "apply" "${CMAKE_CURRENT_SOURCE_DIR}/piper-phonemize.patch" ++) ++FetchContent_MakeAvailable(piper_phonemize) + + # ---- Declare executable ---- + + if((NOT MSVC) AND (NOT APPLE)) + # Linux flags +- string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra -Wl,-rpath,'$ORIGIN'") ++ string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra") ++ list(APPEND CMAKE_BUILD_RPATH "$ORIGIN") ++ list(APPEND CMAKE_INSTALL_RPATH "$ORIGIN") + string(APPEND CMAKE_C_FLAGS " -Wall -Wextra") +- target_link_libraries(piper -static-libgcc -static-libstdc++) ++ target_link_libraries(piper PRIVATE -static-libgcc -static-libstdc++) + + set(PIPER_EXTRA_LIBRARIES "pthread") + endif() + +-target_link_libraries(piper +- fmt +- spdlog ++target_link_libraries(piper PRIVATE ++ "${FMT_LINK_LIBRARIES}" ++ "${SPDLOG_LINK_LIBRARIES}" + espeak-ng +- piper_phonemize + onnxruntime + ${PIPER_EXTRA_LIBRARIES} ++ PUBLIC piper_phonemize + ) + +-target_link_directories(piper PUBLIC +- ${FMT_DIR}/lib +- ${SPDLOG_DIR}/lib +- ${PIPER_PHONEMIZE_DIR}/lib +-) +- +-target_include_directories(piper PUBLIC +- ${FMT_DIR}/include +- ${SPDLOG_DIR}/include +- ${PIPER_PHONEMIZE_DIR}/include ++target_link_directories(piper PRIVATE ++ "${FMT_LINK_DIRECTORIES}" ++ "${SPDLOG_LINK_DIRECTORIES}" + ) + +-target_compile_definitions(piper PUBLIC _PIPER_VERSION=${piper_version}) ++set(PIPER_INTERFACE_INCLUDE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include") ++file(COPY src/cpp/piper.hpp src/cpp/json.hpp DESTINATION "${PIPER_INTERFACE_INCLUDE_DIRECTORY}") + +-# ---- Declare test ---- +-include(CTest) +-enable_testing() +-add_test( +- NAME test_piper +- COMMAND test_piper "${CMAKE_SOURCE_DIR}/etc/test_voice.onnx" "${PIPER_PHONEMIZE_DIR}/share/espeak-ng-data" "${CMAKE_CURRENT_BINARY_DIR}/test.wav" ++target_include_directories(piper PRIVATE ++ "${FMT_INCLUDE_DIRECTORIES}" ++ "${SPDLOG_INCLUDE_DIRECTORIES}" ++ INTERFACE "${PIPER_INTERFACE_INCLUDE_DIRECTORY}" + ) + ++target_compile_definitions(piper PRIVATE _PIPER_VERSION=${piper_version}) ++ + target_compile_features(test_piper PUBLIC cxx_std_17) + + target_include_directories( + test_piper PUBLIC +- ${FMT_DIR}/include +- ${SPDLOG_DIR}/include +- ${PIPER_PHONEMIZE_DIR}/include ++ "${FMT_INCLUDE_DIRECTORIES}" ++ "${SPDLOG_INCLUDE_DIRECTORIES}" + ) + + target_link_directories( + test_piper PUBLIC +- ${FMT_DIR}/lib +- ${SPDLOG_DIR}/lib +- ${PIPER_PHONEMIZE_DIR}/lib ++ "${FMT_LINK_DIRECTORIES}" ++ "${SPDLOG_LINK_DIRECTORIES}" + ) + + target_link_libraries(test_piper PUBLIC +- fmt +- spdlog ++ "${FMT_LINK_LIBRARIES}" ++ "${SPDLOG_LINK_LIBRARIES}" + espeak-ng + piper_phonemize + onnxruntime +@@ -141,32 +181,3 @@ target_link_libraries(test_piper PUBLIC + install( + TARGETS piper + DESTINATION ${CMAKE_INSTALL_PREFIX}) +- +-# Dependencies +-install( +- DIRECTORY ${PIPER_PHONEMIZE_DIR}/bin/ +- DESTINATION ${CMAKE_INSTALL_PREFIX} +- USE_SOURCE_PERMISSIONS # keep +x +- FILES_MATCHING +- PATTERN "piper_phonemize" +- PATTERN "espeak-ng" +- PATTERN "*.dll" +-) +- +-install( +- DIRECTORY ${PIPER_PHONEMIZE_DIR}/lib/ +- DESTINATION ${CMAKE_INSTALL_PREFIX} +- FILES_MATCHING +- PATTERN "*.dll" +- PATTERN "*.so*" +-) +- +-install( +- DIRECTORY ${PIPER_PHONEMIZE_DIR}/share/espeak-ng-data +- DESTINATION ${CMAKE_INSTALL_PREFIX} +-) +- +-install( +- FILES ${PIPER_PHONEMIZE_DIR}/share/libtashkeel_model.ort +- DESTINATION ${CMAKE_INSTALL_PREFIX} +-) +diff --git a/VERSION b/VERSION +index 26aaba0..867e524 100644 +--- a/VERSION ++++ b/VERSION +@@ -1 +1 @@ +-1.2.0 ++1.2.0 +\ No newline at end of file +diff --git a/piper-phonemize.patch b/piper-phonemize.patch +new file mode 100644 +index 0000000..c4676cb +--- /dev/null ++++ b/piper-phonemize.patch +@@ -0,0 +1,214 @@ ++diff --git a/CMakeLists.txt b/CMakeLists.txt ++index ec7b501..39275a6 100644 ++--- a/CMakeLists.txt +++++ b/CMakeLists.txt ++@@ -10,6 +10,8 @@ project( ++ LANGUAGES CXX ++ ) ++ +++option(BUILD_SHARED_LIBS "Build using shared libraries" ON) +++ ++ if(MSVC) ++ # Force compiler to use UTF-8 for IPA constants ++ add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>") ++@@ -17,12 +19,14 @@ if(MSVC) ++ ++ elseif(NOT APPLE) ++ # Linux flags ++- string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra -Wl,-rpath,'$ORIGIN'") +++ string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra") +++ list(APPEND CMAKE_BUILD_RPATH "$ORIGIN") +++ list(APPEND CMAKE_INSTALL_RPATH "$ORIGIN") ++ string(APPEND CMAKE_C_FLAGS " -Wall -Wextra") ++ endif() ++ ++ add_library( ++- piper_phonemize SHARED +++ piper_phonemize ++ src/phonemize.cpp ++ src/phoneme_ids.cpp ++ src/tashkeel.cpp ++@@ -36,12 +40,33 @@ set_target_properties(piper_phonemize PROPERTIES ++ ++ # ---- onnxruntime --- ++ ++-# Look for onnxruntime files in <root>/lib ++-if(NOT DEFINED ONNXRUNTIME_DIR) ++- if(NOT DEFINED ONNXRUNTIME_VERSION) ++- set(ONNXRUNTIME_VERSION "1.14.1") +++set(onnxruntime_FOUND FALSE) +++ +++if(NOT DEFINED ONNXRUNTIME_VERSION) +++ set(ONNXRUNTIME_VERSION "1.14.1") +++endif() +++ +++if(NOT onnxruntime_FOUND AND NOT DEFINED ONNXRUNTIME_DIR) +++ find_package(onnxruntime "${ONNXRUNTIME_VERSION}") +++ if(onnxruntime_FOUND) +++ list(APPEND ONNXRUNTIME_LINK_LIBRARIES "onnxruntime::onnxruntime") ++ endif() +++endif() +++ +++if(NOT onnxruntime_FOUND AND NOT DEFINED ONNXRUNTIME_DIR) +++ find_library(ONNXRUNTIME_LIBRARY onnxruntime) +++ if(NOT "${ONNXRUNTIME_LIBRARY}" STREQUAL "ONNXRUNTIME_LIBRARY-NOTFOUND") +++ find_path(ONNXRUNTIME_PATH "onnxruntime_cxx_api.h" PATH_SUFFIXES "onnxruntime") +++ if(NOT "${ONNXRUNTIME_PATH}" STREQUAL "ONNXRUNTIME_PATH-NOTFOUND") +++ list(APPEND ONNXRUNTIME_INCLUDE_DIRECTORIES "${ONNXRUNTIME_PATH}") +++ list(APPEND ONNXRUNTIME_LINK_LIBRARIES "${ONNXRUNTIME_LIBRARY}") +++ set(onnxruntime_FOUND TRUE) +++ endif() +++ endif() +++endif() ++ +++# Look for onnxruntime files in <root>/lib +++if(NOT onnxruntime_FOUND AND NOT DEFINED ONNXRUNTIME_DIR) ++ if(WIN32) ++ # Windows x86-64 ++ set(ONNXRUNTIME_PREFIX "onnxruntime-win-x64-${ONNXRUNTIME_VERSION}") ++@@ -95,19 +120,31 @@ if(NOT DEFINED ONNXRUNTIME_DIR) ++ endif() ++ endif() ++ +++if(NOT onnxruntime_FOUND AND DEFINED ONNXRUNTIME_DIR) +++ list(APPEND ONNXRUNTIME_INCLUDE_DIRECTORIES "${ONNXRUNTIME_DIR}/include") +++ list(APPEND ONNXRUNTIME_LINK_DIRECTORIES "${ONNXRUNTIME_DIR}/lib") +++ list(APPEND ONNXRUNTIME_LINK_LIBRARIES "onnxruntime") +++ set(onnxruntime_FOUND TRUE) +++endif() +++ ++ # ---- espeak-ng --- ++ ++ if(NOT DEFINED ESPEAK_NG_DIR) ++ set(ESPEAK_NG_DIR "${CMAKE_CURRENT_BINARY_DIR}/ei") ++ +++ find_program(GIT_PROGRAM "git" REQUIRED) ++ include(ExternalProject) ++ ExternalProject_Add( ++ espeak_ng_external ++ PREFIX "${CMAKE_CURRENT_BINARY_DIR}/e" ++- URL "https://github.com/rhasspy/espeak-ng/archive/0f65aa301e0d6bae5e172cc74197d32a6182200f.zip" +++ GIT_REPOSITORY "https://github.com/rhasspy/espeak-ng" +++ GIT_TAG "0f65aa301e0d6bae5e172cc74197d32a6182200f" +++ GIT_PROGRESS TRUE +++ UPDATE_DISCONNECTED TRUE +++ PATCH_COMMAND "${GIT_PROGRAM}" "apply" "${CMAKE_CURRENT_SOURCE_DIR}/espeak-ng.patch" ++ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${ESPEAK_NG_DIR} ++ CMAKE_ARGS -DUSE_ASYNC:BOOL=OFF ++- CMAKE_ARGS -DBUILD_SHARED_LIBS:BOOL=ON +++ CMAKE_ARGS "-DBUILD_SHARED_LIBS:BOOL=${BUILD_SHARED_LIBS}" ++ CMAKE_ARGS -DUSE_MBROLA:BOOL=OFF ++ CMAKE_ARGS -DUSE_LIBSONIC:BOOL=OFF ++ CMAKE_ARGS -DUSE_LIBPCAUDIO:BOOL=OFF ++@@ -116,6 +153,8 @@ if(NOT DEFINED ESPEAK_NG_DIR) ++ CMAKE_ARGS -DEXTRA_cmn:BOOL=ON ++ CMAKE_ARGS -DEXTRA_ru:BOOL=ON ++ CMAKE_ARGS -DCMAKE_C_FLAGS="-D_FILE_OFFSET_BITS=64" +++ CMAKE_ARGS "-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=${CMAKE_POSITION_INDEPENDENT_CODE}" +++ USES_TERMINAL_DOWNLOAD TRUE ++ ) ++ add_dependencies(piper_phonemize espeak_ng_external) ++ endif() ++@@ -123,23 +162,27 @@ endif() ++ ++ # ---- Declare library ---- ++ +++set(PIPER_PHONEMIZE_INTERFACE_INCLUDE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include") +++file(COPY "src/" DESTINATION "${PIPER_PHONEMIZE_INTERFACE_INCLUDE_DIRECTORY}/piper-phonemize" FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp") +++ ++ target_include_directories( ++ piper_phonemize PUBLIC ++ "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>" ++ ${ESPEAK_NG_DIR}/include ++- ${ONNXRUNTIME_DIR}/include +++ ${ONNXRUNTIME_INCLUDE_DIRECTORIES} +++ INTERFACE "${PIPER_PHONEMIZE_INTERFACE_INCLUDE_DIRECTORY}" ++ ) ++ ++ target_link_directories( ++ piper_phonemize PUBLIC ++ ${ESPEAK_NG_DIR}/lib ++- ${ONNXRUNTIME_DIR}/lib +++ ${ONNXRUNTIME_LINK_DIRECTORIES} ++ ) ++ ++ target_link_libraries( ++ piper_phonemize ++ espeak-ng ++- onnxruntime +++ ${ONNXRUNTIME_LINK_LIBRARIES} ++ ) ++ ++ target_compile_features(piper_phonemize PUBLIC cxx_std_17) ++@@ -173,12 +216,13 @@ target_link_libraries(piper_phonemize_exe PUBLIC ++ # ---- Declare test ---- ++ ++ include(CTest) ++-enable_testing() ++ add_executable(test_piper_phonemize src/test.cpp src/phoneme_ids.cpp) ++-add_test( ++- NAME test_piper_phonemize ++- COMMAND test_piper_phonemize "${ESPEAK_NG_DIR}/share/espeak-ng-data" "${CMAKE_SOURCE_DIR}/etc/libtashkeel_model.ort" ++-) +++if(BUILD_TESTING) +++ add_test( +++ NAME test_piper_phonemize +++ COMMAND test_piper_phonemize "${ESPEAK_NG_DIR}/share/espeak-ng-data" "${CMAKE_SOURCE_DIR}/etc/libtashkeel_model.ort" +++ ) +++endif() ++ ++ target_compile_features(test_piper_phonemize PUBLIC cxx_std_17) ++ ++@@ -207,7 +251,7 @@ install( ++ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) ++ ++ install( ++- DIRECTORY ${CMAKE_SOURCE_DIR}/src/ +++ DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/" ++ DESTINATION include/piper-phonemize ++ FILES_MATCHING ++ PATTERN "*.h" ++@@ -218,7 +262,7 @@ install( ++ ARCHIVE DESTINATION ${CMAKE_INSTALL_BINDIR}) ++ ++ install( ++- FILES ${CMAKE_SOURCE_DIR}/etc/libtashkeel_model.ort +++ FILES "${CMAKE_CURRENT_SOURCE_DIR}/etc/libtashkeel_model.ort" ++ TYPE DATA) ++ ++ # Dependencies ++@@ -226,10 +270,12 @@ install( ++ DIRECTORY ${ESPEAK_NG_DIR}/ ++ DESTINATION ${CMAKE_INSTALL_PREFIX}) ++ ++-install( ++- DIRECTORY ${ONNXRUNTIME_DIR}/include/ ++- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +++if(DEFINED ONNXRUNTIME_DIR) +++ install( +++ DIRECTORY ${ONNXRUNTIME_DIR}/include/ +++ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) ++ ++-install( ++- DIRECTORY ${ONNXRUNTIME_DIR}/lib/ ++- DESTINATION ${CMAKE_INSTALL_LIBDIR}) +++ install( +++ DIRECTORY ${ONNXRUNTIME_DIR}/lib/ +++ DESTINATION ${CMAKE_INSTALL_LIBDIR}) +++endif() ++diff --git a/espeak-ng.patch b/espeak-ng.patch ++new file mode 100644 ++index 0000000..a51d146 ++--- /dev/null +++++ b/espeak-ng.patch ++@@ -0,0 +1,10 @@ +++diff --git a/src/ucd-tools/CMakeLists.txt b/src/ucd-tools/CMakeLists.txt +++index 2050c114..4bd7d17e 100644 +++--- a/src/ucd-tools/CMakeLists.txt ++++++ b/src/ucd-tools/CMakeLists.txt +++@@ -1,4 +1,4 @@ +++-add_library(ucd STATIC ++++add_library(ucd OBJECT +++ src/case.c +++ src/categories.c +++ src/ctype.c diff --git a/plugins/wasi_nn/tf.cpp b/plugins/wasi_nn/tf.cpp index 353d1cf77109..6dd02ef3c29a 100644 --- a/plugins/wasi_nn/tf.cpp +++ b/plugins/wasi_nn/tf.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "tf.h" #include "wasinnenv.h" diff --git a/plugins/wasi_nn/tf.h b/plugins/wasi_nn/tf.h index 20e38b598c3a..6f822af48a03 100644 --- a/plugins/wasi_nn/tf.h +++ b/plugins/wasi_nn/tf.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasi_nn/tfl.cpp b/plugins/wasi_nn/tfl.cpp index 32d3c5f3f1d6..28e1a6a98558 100644 --- a/plugins/wasi_nn/tfl.cpp +++ b/plugins/wasi_nn/tfl.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "tfl.h" #include "wasinnenv.h" diff --git a/plugins/wasi_nn/tfl.h b/plugins/wasi_nn/tfl.h index 84d8227a21cb..451fcf6d6dcd 100644 --- a/plugins/wasi_nn/tfl.h +++ b/plugins/wasi_nn/tfl.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasi_nn/torch.cpp b/plugins/wasi_nn/torch.cpp index 153ed32f09f4..7470ce348b69 100644 --- a/plugins/wasi_nn/torch.cpp +++ b/plugins/wasi_nn/torch.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "torch.h" #include "wasinnenv.h" diff --git a/plugins/wasi_nn/torch.h b/plugins/wasi_nn/torch.h index 8961efc897f9..fa480cfb8c91 100644 --- a/plugins/wasi_nn/torch.h +++ b/plugins/wasi_nn/torch.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasi_nn/types.h b/plugins/wasi_nn/types.h index 453b320bed5f..12eede09d105 100644 --- a/plugins/wasi_nn/types.h +++ b/plugins/wasi_nn/types.h @@ -1,9 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once -#include "common/log.h" + #include "common/span.h" +#include "common/spdlog.h" + #include <cstdint> namespace WasmEdge::Host::WASINN { @@ -21,6 +23,7 @@ enum class ErrNo : uint32_t { EndOfSequence = 100, // End of Sequence Found. ContextFull = 101, // Context Full. PromptTooLong = 102, // Prompt Too Long. + ModelNotFound = 103, // Model Not Found. }; enum class TensorType : uint8_t { F16 = 0, F32 = 1, U8 = 2, I32 = 3 }; @@ -35,10 +38,23 @@ enum class Backend : uint8_t { TensorflowLite = 4, Autodetect = 5, GGML = 6, + NeuralSpeed = 7, + Whisper = 9, + Piper = 11, + ChatTTS = 12, }; #define FOR_EACH_BACKEND(F) \ - F(OpenVINO) F(ONNX) F(Tensorflow) F(PyTorch) F(TensorflowLite) F(GGML) + F(OpenVINO) \ + F(ONNX) \ + F(Tensorflow) \ + F(PyTorch) \ + F(TensorflowLite) \ + F(GGML) \ + F(NeuralSpeed) \ + F(Whisper) \ + F(Piper) \ + F(ChatTTS) struct TensorData { Span<uint32_t> Dimension; diff --git a/plugins/wasi_nn/wasinnbase.h b/plugins/wasi_nn/wasinnbase.h index 4568dc76cc01..008980035ad2 100644 --- a/plugins/wasi_nn/wasinnbase.h +++ b/plugins/wasi_nn/wasinnbase.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasi_nn/wasinnenv.cpp b/plugins/wasi_nn/wasinnenv.cpp index 438c7f024554..331e496306ff 100644 --- a/plugins/wasi_nn/wasinnenv.cpp +++ b/plugins/wasi_nn/wasinnenv.cpp @@ -1,7 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "wasinnenv.h" +#include "types.h" #include "wasinnmodule.h" #include <sstream> @@ -15,6 +16,7 @@ namespace Host { namespace WASINN { +namespace { Runtime::Instance::ModuleInstance * create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { return new WasiNNModule; @@ -27,7 +29,11 @@ std::map<std::string_view, Backend> BackendMap = { {"pytorch"sv, Backend::PyTorch}, {"tensorflowlite"sv, Backend::TensorflowLite}, {"autodetect"sv, Backend::Autodetect}, - {"ggml"sv, Backend::GGML}}; + {"ggml"sv, Backend::GGML}, + {"neuralspeed"sv, Backend::NeuralSpeed}, + {"whisper"sv, Backend::Whisper}, + {"piper"sv, Backend::Piper}, + {"chattts"sv, Backend::ChatTTS}}; std::map<std::string_view, Device> DeviceMap = {{"cpu"sv, Device::CPU}, {"gpu"sv, Device::GPU}, @@ -48,6 +54,7 @@ bool load(const std::filesystem::path &Path, std::vector<uint8_t> &Data) { File.close(); return true; } +} // namespace WasiNNEnvironment::WasiNNEnvironment() noexcept { #ifdef WASMEDGE_BUILD_WASI_NN_RPC @@ -87,22 +94,35 @@ WasiNNEnvironment::WasiNNEnvironment() noexcept { std::vector<std::vector<uint8_t>> Models; Models.reserve(Paths.size()); std::transform(Encode.begin(), Encode.end(), Encode.begin(), - [](unsigned char C) { return std::tolower(C); }); + [](unsigned char C) { + return static_cast<unsigned char>(std::tolower(C)); + }); std::transform(Target.begin(), Target.end(), Target.begin(), - [](unsigned char C) { return std::tolower(C); }); + [](unsigned char C) { + return static_cast<unsigned char>(std::tolower(C)); + }); auto Backend = BackendMap.find(Encode); auto Device = DeviceMap.find(Target); if (Backend != BackendMap.end() && Device != DeviceMap.end()) { - for (const std::string &Path : Paths) { - if (Backend->second == Backend::GGML) { - // We write model path to model data to avoid file IO in llama.cpp. - std::string ModelPath = "preload:" + Path; - std::vector<uint8_t> ModelPathData(ModelPath.begin(), - ModelPath.end()); - Models.push_back(std::move(ModelPathData)); - } else { + if (Backend->second == Backend::GGML) { + // In GGML, we only support loading one model from nn-preload config. + // To handle paths on Windows that contains `:` in the path, we combine + // the Paths into a single string separated by `:`. + std::string P; + for (const std::string &PathSegment : Paths) { + P += PathSegment; + if (PathSegment != Paths.back()) { + P += ":"; + } + } + // We write model path to model data to avoid file IO in llama.cpp. + std::string ModelPath = "preload:" + P; + std::vector<uint8_t> ModelPathData(ModelPath.begin(), ModelPath.end()); + Models.push_back(std::move(ModelPathData)); + } else { + for (const std::string &P : Paths) { std::vector<uint8_t> Model; - if (load(std::filesystem::u8path(Path), Model)) { + if (load(std::filesystem::u8path(P), Model)) { Models.push_back(std::move(Model)); } } @@ -129,6 +149,7 @@ PO::Option<std::string> WasiNNEnvironment::NNRPCURI( PO::MetaVar("URI"sv), PO::DefaultValue(std::string(""))); #endif +namespace { void addOptions(const Plugin::Plugin::PluginDescriptor *, PO::ArgumentParser &Parser) noexcept { Parser.add_option("nn-preload"sv, WasiNNEnvironment::NNModels); @@ -140,26 +161,30 @@ void addOptions(const Plugin::Plugin::PluginDescriptor *, #endif } +static Plugin::PluginModule::ModuleDescriptor MD[] = { + { + /* Name */ "wasi_nn", + /* Description */ "", + /* Create */ create, + }, +}; + Plugin::Plugin::PluginDescriptor Descriptor{ - .Name = "wasi_nn", - .Description = "", - .APIVersion = Plugin::Plugin::CurrentAPIVersion, - .Version = {0, 10, 1, 0}, - .ModuleCount = 1, - .ModuleDescriptions = - (Plugin::PluginModule::ModuleDescriptor[]){ - { - .Name = "wasi_nn", - .Description = "", - .Create = create, - }, - }, - .AddOptions = addOptions, + /* Name */ "wasi_nn", + /* Description */ "", + /* APIVersion */ Plugin::Plugin::CurrentAPIVersion, + /* Version */ {0, 10, 1, 0}, + /* ModuleCount */ 1, + /* ModuleDescriptions */ MD, + /* ComponentCount */ 0, + /* ComponentDescriptions */ nullptr, + /* AddOptions */ addOptions, }; +} // namespace -} // namespace WASINN +EXPORT_GET_DESCRIPTOR(Descriptor) -Plugin::PluginRegister WASINN::WasiNNEnvironment::Register(&Descriptor); +} // namespace WASINN } // namespace Host } // namespace WasmEdge diff --git a/plugins/wasi_nn/wasinnenv.h b/plugins/wasi_nn/wasinnenv.h index 00c8df0fb0dd..6ec0077f89be 100644 --- a/plugins/wasi_nn/wasinnenv.h +++ b/plugins/wasi_nn/wasinnenv.h @@ -1,21 +1,25 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once -#include "common/log.h" +#include "common/spdlog.h" #include "plugin/plugin.h" #include <cstdint> #include <functional> #include <vector> +#include "chattts.h" #include "ggml.h" +#include "neuralspeed.h" #include "onnx.h" #include "openvino.h" +#include "piper.h" #include "tf.h" #include "tfl.h" #include "torch.h" #include "types.h" +#include "whispercpp.h" #ifdef WASMEDGE_BUILD_WASI_NN_RPC #include <grpc/grpc.h> @@ -168,6 +172,17 @@ struct WasiNNEnvironment : return false; } + void mdRemoveById(uint32_t GraphId) noexcept { + std::unique_lock Lock(MdMutex); + for (auto It = MdMap.begin(); It != MdMap.end();) { + if (It->second == static_cast<uint32_t>(GraphId)) { + It = MdMap.erase(It); + } else { + ++It; + } + } + } + Expect<WASINN::ErrNo> mdBuild(std::string Name, uint32_t &GraphId, Callback Load, std::vector<uint8_t> Config = std::vector<uint8_t>()) noexcept { @@ -206,7 +221,6 @@ struct WasiNNEnvironment : static PO::Option<std::string> NNRPCURI; // For RPC client mode std::shared_ptr<grpc::Channel> NNRPCChannel; #endif - static Plugin::PluginRegister Register; }; } // namespace WASINN diff --git a/plugins/wasi_nn/wasinnfunc.cpp b/plugins/wasi_nn/wasinnfunc.cpp index 6ccf2b459126..d9fb5e690061 100644 --- a/plugins/wasi_nn/wasinnfunc.cpp +++ b/plugins/wasi_nn/wasinnfunc.cpp @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "wasinnfunc.h" -#include "common/log.h" +#include "common/spdlog.h" #include "wasinnenv.h" #include <string> @@ -36,6 +36,16 @@ Expect<WASINN::ErrNo> load(WASINN::WasiNNEnvironment &Env, return WASINN::ErrNo::InvalidEncoding; } } +#ifdef WASMEDGE_BUILD_WASI_NN_RPC +WASINN::ErrNo metadataToErrNo( + const std::multimap<grpc::string_ref, grpc::string_ref> &Metadata) { + if (Metadata.find("errno") != Metadata.end()) { + auto ErrNo = std::stoi(Metadata.find("errno")->second.data()); + return static_cast<WASINN::ErrNo>(ErrNo); + } + return WASINN::ErrNo::Success; +} +#endif // #ifdef WASMEDGE_BUILD_WASI_NN_RPC } // namespace Expect<WASINN::ErrNo> @@ -136,9 +146,8 @@ WasiNNLoadByName::bodyImpl(const Runtime::CallingFrame &Frame, uint32_t NamePtr, wasi_ephemeral_nn::LoadByNameResult Res; auto Status = Stub->LoadByName(&ClientContext, Req, &Res); if (!Status.ok()) { - spdlog::error("[WASI-NN] Failed when calling remote LoadByName: {}"sv, - Status.error_message()); - return WASINN::ErrNo::RuntimeError; + auto Metadata = ClientContext.GetServerTrailingMetadata(); + return metadataToErrNo(Metadata); } *GraphId = Res.graph_handle(); return WASINN::ErrNo::Success; @@ -157,14 +166,6 @@ WasiNNLoadByName::bodyImpl(const Runtime::CallingFrame &Frame, uint32_t NamePtr, Expect<WASINN::ErrNo> WasiNNLoadByNameWithConfig::bodyImpl( const Runtime::CallingFrame &Frame, uint32_t NamePtr, uint32_t NameLen, uint32_t ConfigPtr, uint32_t ConfigLen, uint32_t GraphIdPtr) { -#ifdef WASMEDGE_BUILD_WASI_NN_RPC - if (Env.NNRPCChannel != nullptr) { - // TODO: implement RPC for LoadByNameWithConfig - spdlog::error( - "[WASI-NN] RPC client is not implemented for LoadByNameWithConfig"sv); - return WASINN::ErrNo::UnsupportedOperation; - } -#endif auto *MemInst = Frame.getMemoryByIndex(0); if (MemInst == nullptr) { return Unexpect(ErrCode::Value::HostFuncError); @@ -192,6 +193,26 @@ Expect<WASINN::ErrNo> WasiNNLoadByNameWithConfig::bodyImpl( return WASINN::ErrNo::InvalidArgument; } +#ifdef WASMEDGE_BUILD_WASI_NN_RPC + if (Env.NNRPCChannel != nullptr) { + auto Stub = wasi_ephemeral_nn::Graph::NewStub(Env.NNRPCChannel); + grpc::ClientContext ClientContext; + wasi_ephemeral_nn::LoadByNameWithConfigRequest Req; + auto NameStrView = MemInst->getStringView(NamePtr, NameLen); + auto ConfigStrView = MemInst->getStringView(ConfigPtr, ConfigLen); + Req.set_name(NameStrView.data(), NameStrView.size()); + Req.set_config(ConfigStrView.data(), ConfigStrView.size()); + wasi_ephemeral_nn::LoadByNameWithConfigResult Res; + auto Status = Stub->LoadByNameWithConfig(&ClientContext, Req, &Res); + if (!Status.ok()) { + auto Metadata = ClientContext.GetServerTrailingMetadata(); + return metadataToErrNo(Metadata); + } + *GraphId = Res.graph_handle(); + return WASINN::ErrNo::Success; + } +#endif // ifdef WASMEDGE_BUILD_WASI_NN_RPC + // Get the model std::string ModelName(reinterpret_cast<const char *>(Name), NameLen); std::vector<uint8_t> ModelConfig(reinterpret_cast<const uint8_t *>(Config), @@ -228,10 +249,8 @@ WasiNNInitExecCtx::bodyImpl(const Runtime::CallingFrame &Frame, wasi_ephemeral_nn::InitExecutionContextResult Res; auto Status = Stub->InitExecutionContext(&ClientContext, Req, &Res); if (!Status.ok()) { - spdlog::error( - "[WASI-NN] Failed when calling remote InitExecutionContext: {}"sv, - Status.error_message()); - return WASINN::ErrNo::RuntimeError; + auto Metadata = ClientContext.GetServerTrailingMetadata(); + return metadataToErrNo(Metadata); } *Context = Res.ctx_handle(); return WASINN::ErrNo::Success; @@ -325,9 +344,8 @@ WasiNNSetInput::bodyImpl(const Runtime::CallingFrame &Frame, uint32_t Context, google::protobuf::Empty Res; auto Status = Stub->SetInput(&ClientContext, Req, &Res); if (!Status.ok()) { - spdlog::error("[WASI-NN] Failed when calling remote SetInput: {}"sv, - Status.error_message()); - return WASINN::ErrNo::RuntimeError; + auto Metadata = ClientContext.GetServerTrailingMetadata(); + return metadataToErrNo(Metadata); } return WASINN::ErrNo::Success; } @@ -383,9 +401,8 @@ WasiNNGetOutput::bodyImpl(const Runtime::CallingFrame &Frame, uint32_t Context, wasi_ephemeral_nn::GetOutputResult Res; auto Status = Stub->GetOutput(&ClientContext, Req, &Res); if (!Status.ok()) { - spdlog::error("[WASI-NN] Failed when calling remote GetOutput: {}"sv, - Status.error_message()); - return WASINN::ErrNo::RuntimeError; + auto Metadata = ClientContext.GetServerTrailingMetadata(); + return metadataToErrNo(Metadata); } uint32_t BytesWrittenVal = std::min(static_cast<uint32_t>(Res.data().size()), OutBufferMaxSize); @@ -416,25 +433,11 @@ Expect<WASINN::ErrNo> WasiNNGetOutputSingle::bodyImpl( const Runtime::CallingFrame &Frame, uint32_t Context, uint32_t Index, uint32_t OutBufferPtr, uint32_t OutBufferMaxSize, uint32_t BytesWrittenPtr) { -#ifdef WASMEDGE_BUILD_WASI_NN_RPC - if (Env.NNRPCChannel != nullptr) { - // TODO: implement RPC for GetOutputSingle - spdlog::error( - "[WASI-NN] RPC client is not implemented for GetOutputSingle"sv); - return WASINN::ErrNo::UnsupportedOperation; - } -#endif auto *MemInst = Frame.getMemoryByIndex(0); if (MemInst == nullptr) { return Unexpect(ErrCode::Value::HostFuncError); } - if (Env.NNContext.size() <= Context) { - spdlog::error( - "[WASI-NN] get_output_single: Execution Context does not exist"sv); - return WASINN::ErrNo::InvalidArgument; - } - const auto OutBuffer = MemInst->getSpan<uint8_t>(OutBufferPtr, OutBufferMaxSize); if (unlikely(OutBuffer.data() == nullptr)) { @@ -448,6 +451,34 @@ Expect<WASINN::ErrNo> WasiNNGetOutputSingle::bodyImpl( return WASINN::ErrNo::InvalidArgument; } +#ifdef WASMEDGE_BUILD_WASI_NN_RPC + if (Env.NNRPCChannel != nullptr) { + auto Stub = wasi_ephemeral_nn::GraphExecutionContextResource::NewStub( + Env.NNRPCChannel); + grpc::ClientContext ClientContext; + wasi_ephemeral_nn::GetOutputRequest Req; + Req.set_resource_handle(Context); + Req.set_index(Index); + wasi_ephemeral_nn::GetOutputResult Res; + auto Status = Stub->GetOutputSingle(&ClientContext, Req, &Res); + if (!Status.ok()) { + auto Metadata = ClientContext.GetServerTrailingMetadata(); + return metadataToErrNo(Metadata); + } + uint32_t BytesWrittenVal = + std::min(static_cast<uint32_t>(Res.data().size()), OutBufferMaxSize); + std::copy_n(Res.data().begin(), BytesWrittenVal, OutBuffer.begin()); + *BytesWritten = BytesWrittenVal; + return WASINN::ErrNo::Success; + } +#endif // ifdef WASMEDGE_BUILD_WASI_NN_RPC + + if (Env.NNContext.size() <= Context) { + spdlog::error( + "[WASI-NN] get_output_single: Execution Context does not exist"sv); + return WASINN::ErrNo::InvalidArgument; + } + switch (Env.NNContext[Context].getBackend()) { case WASINN::Backend::GGML: return WASINN::GGML::getOutputSingle(Env, Context, Index, OutBuffer, @@ -471,9 +502,8 @@ WasiNNCompute::bodyImpl(const Runtime::CallingFrame &Frame, uint32_t Context) { google::protobuf::Empty Res; auto Status = Stub->Compute(&ClientContext, Req, &Res); if (!Status.ok()) { - spdlog::error("[WASI-NN] Failed when calling remote Compute: {}"sv, - Status.error_message()); - return WASINN::ErrNo::RuntimeError; + auto Metadata = ClientContext.GetServerTrailingMetadata(); + return metadataToErrNo(Metadata); } return WASINN::ErrNo::Success; } @@ -505,12 +535,20 @@ WasiNNComputeSingle::bodyImpl(const Runtime::CallingFrame &Frame, uint32_t Context) { #ifdef WASMEDGE_BUILD_WASI_NN_RPC if (Env.NNRPCChannel != nullptr) { - // TODO: implement RPC for ComputeSingle - spdlog::error( - "[WASI-NN] RPC client is not implemented for ComputeSingle"sv); - return WASINN::ErrNo::UnsupportedOperation; + auto Stub = wasi_ephemeral_nn::GraphExecutionContextResource::NewStub( + Env.NNRPCChannel); + grpc::ClientContext ClientContext; + wasi_ephemeral_nn::ComputeRequest Req; + Req.set_resource_handle(Context); + google::protobuf::Empty Res; + auto Status = Stub->ComputeSingle(&ClientContext, Req, &Res); + if (!Status.ok()) { + auto Metadata = ClientContext.GetServerTrailingMetadata(); + return metadataToErrNo(Metadata); + } + return WASINN::ErrNo::Success; } -#endif +#endif // ifdef WASMEDGE_BUILD_WASI_NN_RPC auto *MemInst = Frame.getMemoryByIndex(0); if (MemInst == nullptr) { return Unexpect(ErrCode::Value::HostFuncError); @@ -537,11 +575,20 @@ WasiNNFiniSingle::bodyImpl(const Runtime::CallingFrame &Frame, uint32_t Context) { #ifdef WASMEDGE_BUILD_WASI_NN_RPC if (Env.NNRPCChannel != nullptr) { - // TODO: implement RPC for FiniSingle - spdlog::error("[WASI-NN] RPC client is not implemented for FiniSingle"sv); - return WASINN::ErrNo::UnsupportedOperation; + auto Stub = wasi_ephemeral_nn::GraphExecutionContextResource::NewStub( + Env.NNRPCChannel); + grpc::ClientContext ClientContext; + wasi_ephemeral_nn::FiniSingleRequest Req; + Req.set_resource_handle(Context); + google::protobuf::Empty Res; + auto Status = Stub->FiniSingle(&ClientContext, Req, &Res); + if (!Status.ok()) { + auto Metadata = ClientContext.GetServerTrailingMetadata(); + return metadataToErrNo(Metadata); + } + return WASINN::ErrNo::Success; } -#endif +#endif // ifdef WASMEDGE_BUILD_WASI_NN_RPC auto *MemInst = Frame.getMemoryByIndex(0); if (MemInst == nullptr) { return Unexpect(ErrCode::Value::HostFuncError); @@ -562,5 +609,38 @@ WasiNNFiniSingle::bodyImpl(const Runtime::CallingFrame &Frame, } } +Expect<WASINN::ErrNo> WasiNNUnload::bodyImpl(const Runtime::CallingFrame &Frame, + uint32_t GraphId) { +#ifdef WASMEDGE_BUILD_WASI_NN_RPC + if (Env.NNRPCChannel != nullptr) { + // TODO: implement RPC for unload + spdlog::error("[WASI-NN] RPC client is not implemented for unload"sv); + return WASINN::ErrNo::UnsupportedOperation; + } +#endif + auto *MemInst = Frame.getMemoryByIndex(0); + if (MemInst == nullptr) { + return Unexpect(ErrCode::Value::HostFuncError); + } + + if (Env.NNGraph.size() <= GraphId) { + spdlog::error("[WASI-NN] unload: GraphId {} does not exist."sv, GraphId); + return WASINN::ErrNo::InvalidArgument; + } + + switch (Env.NNGraph[GraphId].getBackend()) { + case WASINN::Backend::GGML: + return WASINN::GGML::unload(Env, GraphId); + case WASINN::Backend::NeuralSpeed: + return WASINN::NeuralSpeed::unload(Env, GraphId); + case WASINN::Backend::ChatTTS: + return WASINN::ChatTTS::unload(Env, GraphId); + default: + spdlog::error( + "[WASI-NN] unlaod: Only GGML, Neural speed, and ChatTTS backend supports unload."sv); + return WASINN::ErrNo::InvalidArgument; + } +} + } // namespace Host } // namespace WasmEdge diff --git a/plugins/wasi_nn/wasinnfunc.h b/plugins/wasi_nn/wasinnfunc.h index 7dcfbd2ad24c..b955a3000081 100644 --- a/plugins/wasi_nn/wasinnfunc.h +++ b/plugins/wasi_nn/wasinnfunc.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once @@ -161,5 +161,17 @@ class WasiNNFiniSingle : public WasiNN<WasiNNFiniSingle> { uint32_t Context); }; +class WasiNNUnload : public WasiNN<WasiNNUnload> { +public: + WasiNNUnload(WASINN::WasiNNEnvironment &HostEnv) : WasiNN(HostEnv) {} + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, uint32_t GraphId) { + return bodyImpl(Frame, GraphId).map(castErrNo); + } + +private: + Expect<WASINN::ErrNo> bodyImpl(const Runtime::CallingFrame &Frame, + uint32_t GraphId); +}; + } // namespace Host } // namespace WasmEdge diff --git a/plugins/wasi_nn/wasinnmodule.cpp b/plugins/wasi_nn/wasinnmodule.cpp index c224640527c0..6226f89d61d3 100644 --- a/plugins/wasi_nn/wasinnmodule.cpp +++ b/plugins/wasi_nn/wasinnmodule.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "wasinnmodule.h" #include "wasinnfunc.h" @@ -21,6 +21,7 @@ WasiNNModule::WasiNNModule() : ModuleInstance("wasi_ephemeral_nn") { addHostFunc("compute", std::make_unique<WasiNNCompute>(Env)); addHostFunc("compute_single", std::make_unique<WasiNNComputeSingle>(Env)); addHostFunc("fini_single", std::make_unique<WasiNNFiniSingle>(Env)); + addHostFunc("unload", std::make_unique<WasiNNUnload>(Env)); } } // namespace Host diff --git a/plugins/wasi_nn/wasinnmodule.h b/plugins/wasi_nn/wasinnmodule.h index 0c18bd16286c..87b0fd4e5f1e 100644 --- a/plugins/wasi_nn/wasinnmodule.h +++ b/plugins/wasi_nn/wasinnmodule.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasi_nn/whispercpp.cpp b/plugins/wasi_nn/whispercpp.cpp new file mode 100644 index 000000000000..3cc1452d1b93 --- /dev/null +++ b/plugins/wasi_nn/whispercpp.cpp @@ -0,0 +1,513 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "whispercpp.h" +#include "wasinnenv.h" + +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_WHISPER +#define DR_WAV_IMPLEMENTATION +#include "simdjson.h" +#include <examples/dr_wav.h> + +#include <algorithm> +#endif + +namespace WasmEdge::Host::WASINN::Whisper { +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_WHISPER + +namespace { + +bool checkAudioRIFF(const std::string_view Buf, const std::string_view Format) { + if (Buf.size() < 12 || Buf.substr(0, 4) != "RIFF"sv) { + return false; + } + if (Buf.substr(8, 4) != Format) { + return false; + } + uint32_t ChunkSize = *reinterpret_cast<const uint32_t *>(Buf.data() + 4); + if (ChunkSize + 8 != Buf.size()) { + return false; + } + return true; +} + +bool loadWAV(Span<const uint8_t> Buf, std::vector<float> &PCMF32) { + // Not to use the helper function in examples of whisper.cpp to prevent from + // copy. + drwav WAV; + const uint32_t ConstSampleRate = 16000; + + if (!drwav_init_memory(&WAV, Buf.data(), Buf.size(), nullptr)) { + spdlog::error("[WASI-NN] Whisper backend: load WAV failed."sv); + return false; + } + + if (WAV.channels != 1 && WAV.channels != 2) { + spdlog::error("[WASI-NN] Whisper backend: WAV must be mono or stereo."sv); + drwav_uninit(&WAV); + return false; + } + + if (WAV.sampleRate != ConstSampleRate) { + spdlog::error("[WASI-NN] Whisper backend: WAV must be {} kHz."sv, + ConstSampleRate / 1000); + drwav_uninit(&WAV); + return false; + } + + if (WAV.bitsPerSample != 16) { + spdlog::error("[WASI-NN] Whisper backend: WAV must be 16-bit."sv); + drwav_uninit(&WAV); + return false; + } + + const uint32_t N = WAV.totalPCMFrameCount; + std::vector<int16_t> PCM16(N * WAV.channels); + drwav_read_pcm_frames_s16(&WAV, N, PCM16.data()); + drwav_uninit(&WAV); + + PCMF32.resize(N); + if (WAV.channels == 1) { + for (uint64_t I = 0; I < N; I++) { + PCMF32[I] = static_cast<float>(PCM16[I]) / 32768.0f; + } + } else { + for (uint64_t I = 0; I < N; I++) { + PCMF32[I] = + static_cast<float>(PCM16[2 * I] + PCM16[2 * I + 1]) / 65536.0f; + } + } + return true; +} + +void WhisperLogCallback(ggml_log_level LogLevel, const char *LogText, + void *UserData) { + const Graph &GraphRef = *reinterpret_cast<Graph *>(UserData); + if (!GraphRef.WhisperConfig.EnableLog) { + return; + } + std::string Text(LogText); + // Remove the trailing newlines. + Text = Text.erase(Text.find_last_not_of("\n") + 1); + // Skip for "." + if (Text == ".") { + return; + } + if (LogLevel == GGML_LOG_LEVEL_ERROR) { + spdlog::error("[WASI-NN] whisper.cpp: {}"sv, Text); + } else if (LogLevel == GGML_LOG_LEVEL_WARN) { + spdlog::warn("[WASI-NN] whisper.cpp: {}"sv, Text); + } else if (LogLevel == GGML_LOG_LEVEL_INFO) { + spdlog::info("[WASI-NN] whisper.cpp: {}"sv, Text); + } else if (LogLevel == GGML_LOG_LEVEL_DEBUG) { + spdlog::debug("[WASI-NN] whisper.cpp: {}"sv, Text); + } +} + +void WhisperOutputSegmentCallback(struct whisper_context *WhisperCtx, + struct whisper_state * /* state */, int NewN, + void *UserData) { + auto &CxtRef = *reinterpret_cast<Context *>(UserData); + const int SegN = whisper_full_n_segments(WhisperCtx); + + auto ToTimeStr = [](int64_t T) -> std::string { + T *= 10; + uint32_t HR = static_cast<uint32_t>(T / (1000 * 60 * 60)); + T %= 1000 * 60 * 60; + uint32_t M = static_cast<uint32_t>(T / (1000 * 60)); + T %= 1000 * 60; + uint32_t S = static_cast<uint32_t>(T / 1000); + uint32_t MS = static_cast<uint32_t>(T % 1000); + char Buf[32]; + snprintf(Buf, sizeof(Buf), "%02d:%02d:%02d.%03d", HR, M, S, MS); + return std::string(Buf); + }; + + // Output the last new N segments. + for (int I = SegN - NewN; I < SegN; I++) { + int64_t T0 = whisper_full_get_segment_t0(WhisperCtx, I); + int64_t T1 = whisper_full_get_segment_t1(WhisperCtx, I); + // TODO: Add the print timestamp config. + CxtRef.Outputs += "["; + CxtRef.Outputs += ToTimeStr(T0); + CxtRef.Outputs += " --> "; + CxtRef.Outputs += ToTimeStr(T1); + CxtRef.Outputs += "] "; + CxtRef.Outputs += whisper_full_get_segment_text(WhisperCtx, I); + CxtRef.Outputs += "\n"; + } +} + +void setWhisperParams(Context &CxtRef) noexcept { + auto &WParam = CxtRef.WhisperParams; + auto &ConfigRef = CxtRef.WhisperConfig; + WParam.print_progress = false; + WParam.thold_pt = ConfigRef.WordThreshold; + WParam.translate = ConfigRef.Translate; + WParam.language = ConfigRef.SpokenLanguage.c_str(); + WParam.detect_language = ConfigRef.DetectLanguage; + WParam.initial_prompt = ConfigRef.InitialPrompt.c_str(); + WParam.temperature_inc = ConfigRef.TemperatureInc; + WParam.temperature = ConfigRef.Temperature; + WParam.entropy_thold = ConfigRef.EntropyThreshold; + WParam.logprob_thold = ConfigRef.LogprobThreshold; + WParam.grammar_penalty = ConfigRef.GrammarPenalty; + WParam.new_segment_callback = WhisperOutputSegmentCallback; + WParam.new_segment_callback_user_data = &CxtRef; +} + +Expect<ErrNo> parseMetadata(Config &ConfigRef, + const std::string &Metadata) noexcept { + simdjson::dom::parser Parser; + simdjson::dom::element Doc; + auto ParseError = Parser.parse(Metadata).get(Doc); + if (ParseError) { + spdlog::error("[WASI-NN] Whisper backend: Parse metadata error."sv); + return ErrNo::InvalidEncoding; + } + + // Get metadata from the json. + // Currently supported metadata: + // Plugin parameters (used by this plugin): + // enable-log: bool + // enable-debug-log: bool + // translate: bool + // language: string + // detect-language: bool + // prompt: string + + // The plugin parameters. + if (Doc.at_key("enable-log").error() == simdjson::SUCCESS) { + auto Err = Doc["enable-log"].get<bool>().get(ConfigRef.EnableLog); + if (Err) { + spdlog::error( + "[WASI-NN] Whisper backend: Unable to retrieve the enable-log " + "option."sv); + return ErrNo::InvalidArgument; + } + } + if (Doc.at_key("enable-debug-log").error() == simdjson::SUCCESS) { + auto Err = + Doc["enable-debug-log"].get<bool>().get(ConfigRef.EnableDebugLog); + if (Err) { + spdlog::error( + "[WASI-NN] Whisper backend: Unable to retrieve the enable-debug-log " + "option."sv); + return ErrNo::InvalidArgument; + } + } + if (Doc.at_key("translate").error() == simdjson::SUCCESS) { + auto Err = Doc["translate"].get<bool>().get(ConfigRef.Translate); + if (Err) { + spdlog::error( + "[WASI-NN] Whisper backend: Unable to retrieve the translate " + "option."sv); + return ErrNo::InvalidArgument; + } + } + if (Doc.at_key("language").error() == simdjson::SUCCESS) { + std::string_view Language; + auto Err = Doc["language"].get<std::string_view>().get(Language); + if (Err) { + spdlog::error( + "[WASI-NN] Whisper backend: Unable to retrieve the language " + "option."sv); + return ErrNo::InvalidArgument; + } + ConfigRef.SpokenLanguage = Language; + } + if (Doc.at_key("detect-language").error() == simdjson::SUCCESS) { + auto Err = Doc["detect-language"].get<bool>().get(ConfigRef.DetectLanguage); + if (Err) { + spdlog::error( + "[WASI-NN] Whisper backend: Unable to retrieve the detect-language " + "option."sv); + return ErrNo::InvalidArgument; + } + } + if (Doc.at_key("prompt").error() == simdjson::SUCCESS) { + std::string_view Prompt; + auto Err = Doc["prompt"].get<std::string_view>().get(Prompt); + if (Err) { + spdlog::error( + "[WASI-NN] Whisper backend: Unable to retrieve the prompt option."sv); + return ErrNo::InvalidArgument; + } + ConfigRef.InitialPrompt = Prompt; + } + return ErrNo::Success; +} + +Expect<ErrNo> handleTranslationConfig(whisper_context *WhisperCtx, + Config &ConfigRef) noexcept { + assuming(WhisperCtx); + + // Check the language. + if (ConfigRef.SpokenLanguage != "auto"sv && + whisper_lang_id(ConfigRef.SpokenLanguage.c_str()) == -1) { + spdlog::error("[WASI-NN] Whisper backend: Error: unknown language {}."sv, + ConfigRef.SpokenLanguage); + return ErrNo::InvalidArgument; + } + + // Check the translate option. + if (!whisper_is_multilingual(WhisperCtx)) { + if (ConfigRef.SpokenLanguage != "en"sv || ConfigRef.Translate) { + ConfigRef.SpokenLanguage = "en"sv; + ConfigRef.Translate = false; + if (ConfigRef.EnableLog) { + spdlog::info( + "[WASI-NN] Whisper backend: Model is not multilingual. Ignoring " + "language and translation options"sv); + } + } + } + if (ConfigRef.DetectLanguage) { + ConfigRef.SpokenLanguage = "auto"sv; + } + return ErrNo::Success; +} + +} // namespace + +Expect<ErrNo> load(WasiNNEnvironment &Env, Span<const Span<uint8_t>> Builders, + [[maybe_unused]] Device Device, uint32_t &GraphId) noexcept { + // Add a new graph. + Env.NNGraph.emplace_back(Backend::Whisper); + auto &GraphRef = Env.NNGraph.back().get<Graph>(); + + // Initialize the parameters. + auto CParam = whisper_context_default_params(); + GraphRef.ModelFilePath = ""sv; + GraphRef.WhisperConfig.SpokenLanguage = "en"sv; + GraphRef.UseGPU = CParam.use_gpu; + GraphRef.MainGPU = CParam.gpu_device; + + // Set whisper log callback. + whisper_log_set(WhisperLogCallback, &GraphRef); + + // If the graph builder length > 1, the data of builder[1] is the metadata. + if (Builders.size() > 1) { + const std::string Metadata(reinterpret_cast<char *>(Builders[1].data()), + Builders[1].size()); + // Ignore context or model updates when initializing the graph. + auto Res = parseMetadata(GraphRef.WhisperConfig, Metadata); + if (Res != ErrNo::Success) { + spdlog::error("[WASI-NN] Whisper backend: Failed to parse metadata."sv); + Env.NNGraph.pop_back(); + return Res; + } + } + + // Handle the model path. + if (GraphRef.WhisperConfig.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] Whisper backend: Handling model path."sv); + } + auto Weight = Builders[0]; + const std::string_view BinModel(reinterpret_cast<char *>(Weight.data()), + Weight.size()); + if (BinModel.substr(0, 8) == "preload:"sv) { + GraphRef.ModelFilePath = BinModel.substr(8); + } + + // Initialize whisper context from model file with parameters. + if (GraphRef.WhisperConfig.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] Whisper backend: Initialize whisper context with " + "given parameters"sv); + } + if (GraphRef.ModelFilePath == ""sv) { + GraphRef.WhisperCtx = whisper_init_from_buffer_with_params( + Weight.data(), Weight.size(), CParam); + } else { + GraphRef.WhisperCtx = whisper_init_from_file_with_params( + GraphRef.ModelFilePath.c_str(), CParam); + } + if (GraphRef.WhisperCtx == nullptr) { + spdlog::error( + "[WASI-NN] Whisper backend: Error: unable to init whisper context from " + "model."sv); + Env.NNGraph.pop_back(); + return ErrNo::InvalidArgument; + } + if (GraphRef.WhisperConfig.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] Whisper backend: Initialize whisper context with " + "given parameters...Done"sv); + } + + auto ResTranslateConfig = + handleTranslationConfig(GraphRef.WhisperCtx, GraphRef.WhisperConfig); + if (ResTranslateConfig != ErrNo::Success) { + Env.NNGraph.pop_back(); + return ResTranslateConfig; + } + + // Store the loaded graph. + GraphId = Env.NNGraph.size() - 1; + + return ErrNo::Success; +} + +Expect<ErrNo> initExecCtx(WasiNNEnvironment &Env, uint32_t GraphId, + uint32_t &ContextId) noexcept { + auto &GraphRef = Env.NNGraph[GraphId].get<Graph>(); + if (GraphRef.WhisperConfig.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] Whisper backend: initExecCtx"sv); + } + Env.NNContext.emplace_back(GraphId, Env.NNGraph[GraphId]); + ContextId = Env.NNContext.size() - 1; + setWhisperParams(Env.NNContext[ContextId].get<Context>()); + if (GraphRef.WhisperConfig.EnableLog) { + spdlog::info("[WASI-NN] Whisper backend: whisper_system_info: {}"sv, + whisper_print_system_info()); + } + if (GraphRef.WhisperConfig.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] Whisper backend: initExecCtx...Done"sv); + } + return ErrNo::Success; +} + +Expect<ErrNo> setInput(WasiNNEnvironment &Env, uint32_t ContextId, + uint32_t Index [[maybe_unused]], + const TensorData &Tensor) noexcept { + auto &CxtRef = Env.NNContext[ContextId].get<Context>(); + if (CxtRef.WhisperConfig.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] Whisper backend: setInput"sv); + } + + // Use index 1 for metadata. + if (Index == 1) { + if (CxtRef.WhisperConfig.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] Whisper backend: found Metadata, processing"sv); + } + const std::string Metadata(reinterpret_cast<char *>(Tensor.Tensor.data()), + Tensor.Tensor.size()); + auto Res = parseMetadata(CxtRef.WhisperConfig, Metadata); + if (Res != ErrNo::Success) { + spdlog::error("[WASI-NN] Whisper backend: Failed to parse metadata."sv); + return Res; + } + auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get<Graph>(); + Res = handleTranslationConfig(GraphRef.WhisperCtx, CxtRef.WhisperConfig); + if (Res != ErrNo::Success) { + return Res; + } + setWhisperParams(CxtRef); + if (CxtRef.WhisperConfig.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] Whisper backend: found Metadata, processing...Done"sv); + } + return ErrNo::Success; + } + + if (Tensor.Dimension.size() != 2) { + spdlog::error("[WASI-NN] Tensor dimension is out of range, expect 2-dim, " + "but got {}-dim.", + Tensor.Dimension.size()); + return WASINN::ErrNo::InvalidArgument; + } + if (Tensor.Dimension[0] != 1) { + spdlog::error("[WASI-NN] Only 1 channel supported for now."); + return WASINN::ErrNo::InvalidArgument; + } + + // Tensor type not used here. Not to check this. + + // Check the input audio file format and load. Currently WAV supported. + if (!checkAudioRIFF( + std::string_view(reinterpret_cast<char *>(Tensor.Tensor.data()), + Tensor.Tensor.size()), + "WAVE"sv)) { + spdlog::error("[WASI-NN] Only WAV format supported now."sv); + return WASINN::ErrNo::InvalidArgument; + } + if (!loadWAV(Tensor.Tensor, CxtRef.InputPCM)) { + return WASINN::ErrNo::InvalidArgument; + } + + if (CxtRef.WhisperConfig.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] Whisper backend: setInput...Done"sv); + } + return ErrNo::Success; +} + +Expect<ErrNo> getOutput(WasiNNEnvironment &Env, uint32_t ContextId, + uint32_t Index, Span<uint8_t> OutBuffer, + uint32_t &BytesWritten) noexcept { + auto &CxtRef = Env.NNContext[ContextId].get<Context>(); + if (CxtRef.WhisperConfig.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] Whisper backend: getOutput with Index {}"sv, + Index); + } + + // Check out buffer max size. + if (OutBuffer.size() < CxtRef.Outputs.length()) { + spdlog::error("[WASI-NN] Expect out buffer max size {}, but got {}", + CxtRef.Outputs.length(), OutBuffer.size()); + return WASINN::ErrNo::InvalidArgument; + } + + std::copy_n(CxtRef.Outputs.data(), CxtRef.Outputs.length(), OutBuffer.data()); + BytesWritten = CxtRef.Outputs.length(); + if (CxtRef.WhisperConfig.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] Whisper backend: getOutput with Index {}...Done"sv, + Index); + } + return ErrNo::Success; +} + +Expect<ErrNo> compute(WasiNNEnvironment &Env, uint32_t ContextId) noexcept { + auto &CxtRef = Env.NNContext[ContextId].get<Context>(); + auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get<Graph>(); + if (CxtRef.WhisperConfig.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] Whisper backend: compute"sv); + } + + CxtRef.Outputs.clear(); + if (whisper_full(GraphRef.WhisperCtx, CxtRef.WhisperParams, + CxtRef.InputPCM.data(), CxtRef.InputPCM.size()) != 0) { + spdlog::error( + "[WASI-NN] Whisper backend: Error: failed to process audio."sv); + return ErrNo::RuntimeError; + } + + if (CxtRef.WhisperConfig.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] Whisper backend: compute...Done"sv); + } + return ErrNo::Success; +} + +#else + +namespace { +Expect<ErrNo> reportBackendNotSupported() noexcept { + spdlog::error("[WASI-NN] Whisper backend is not built. use " + "-WASMEDGE_PLUGIN_WASI_NN_BACKEND=\"whisper\" to build it."sv); + return ErrNo::InvalidArgument; +} +} // namespace + +Expect<ErrNo> load(WasiNNEnvironment &, Span<const Span<uint8_t>>, Device, + uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect<ErrNo> initExecCtx(WasiNNEnvironment &, uint32_t, uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect<ErrNo> setInput(WasiNNEnvironment &, uint32_t, uint32_t, + const TensorData &) noexcept { + return reportBackendNotSupported(); +} +Expect<ErrNo> getOutput(WasiNNEnvironment &, uint32_t, uint32_t, Span<uint8_t>, + uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect<ErrNo> compute(WasiNNEnvironment &, uint32_t) noexcept { + return reportBackendNotSupported(); +} + +#endif +} // namespace WasmEdge::Host::WASINN::Whisper diff --git a/plugins/wasi_nn/whispercpp.h b/plugins/wasi_nn/whispercpp.h new file mode 100644 index 000000000000..70f727a3cb31 --- /dev/null +++ b/plugins/wasi_nn/whispercpp.h @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "plugin/plugin.h" +#include "types.h" + +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_WHISPER +#include <whisper.h> + +#include <string> +#include <vector> +#endif + +namespace WasmEdge::Host::WASINN { +struct WasiNNEnvironment; +} + +namespace WasmEdge::Host::WASINN::Whisper { +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_WHISPER + +struct Config { + // Whisper parameters: + bool EnableLog = false; + bool EnableDebugLog = false; + bool Translate = false; + bool DetectLanguage = false; + std::string SpokenLanguage; + std::string InitialPrompt; + // Sampling parameters: + float WordThreshold = 0.01f; + float EntropyThreshold = 2.40f; + float LogprobThreshold = -1.00f; + float Temperature = 0.0f; + float TemperatureInc = 0.2f; + float GrammarPenalty = 100.0f; +}; + +struct Graph { + whisper_context *WhisperCtx = nullptr; + std::string ModelFilePath; + // Whisper config: + Config WhisperConfig; + // Context parameters: + bool UseGPU = true; + int64_t MainGPU = 0; // Use GPU 0 by default +}; + +struct Context { +public: + Context(size_t GId, Graph &G) noexcept + : GraphId(GId), WhisperConfig(G.WhisperConfig) {} + size_t GraphId; + // mono-channel F32 PCM input. + std::vector<float> InputPCM; + // Whisper config. Inherit from the graph and accept metadata when setting + // input. + Config WhisperConfig; + whisper_full_params WhisperParams = whisper_full_default_params( + whisper_sampling_strategy::WHISPER_SAMPLING_BEAM_SEARCH); + // Recognition outputs. + std::string Outputs; +}; +#else +struct Graph {}; +struct Context { + Context(size_t, Graph &) noexcept {} +}; +#endif + +struct Environ {}; + +Expect<WASINN::ErrNo> load(WASINN::WasiNNEnvironment &Env, + Span<const Span<uint8_t>> Builders, + WASINN::Device Device, uint32_t &GraphId) noexcept; +Expect<WASINN::ErrNo> initExecCtx(WASINN::WasiNNEnvironment &Env, + uint32_t GraphId, + uint32_t &ContextId) noexcept; +Expect<WASINN::ErrNo> setInput(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId, uint32_t Index, + const TensorData &Tensor) noexcept; +Expect<WASINN::ErrNo> getOutput(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId, uint32_t Index, + Span<uint8_t> OutBuffer, + uint32_t &BytesWritten) noexcept; +Expect<WASINN::ErrNo> compute(WASINN::WasiNNEnvironment &Env, + uint32_t ContextId) noexcept; +} // namespace WasmEdge::Host::WASINN::Whisper diff --git a/plugins/wasmedge_rustls/.gitignore b/plugins/wasi_nn_burnrs/.gitignore similarity index 100% rename from plugins/wasmedge_rustls/.gitignore rename to plugins/wasi_nn_burnrs/.gitignore diff --git a/plugins/wasi_nn_burnrs/CMakeLists.txt b/plugins/wasi_nn_burnrs/CMakeLists.txt new file mode 100644 index 000000000000..ad7c1344d925 --- /dev/null +++ b/plugins/wasi_nn_burnrs/CMakeLists.txt @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CARGO_CMD cargo build) + set(TARGET_DIR "debug") +else() + set(CARGO_CMD cargo build --release) + set(TARGET_DIR "release") +endif() + +message(STATUS "WasmEdge WASI-NN Burn.rs backend plugin model: ${WASMEDGE_PLUGIN_WASI_NN_BURNRS_MODEL}") +set(CARGO_FEATURES "--features=${WASMEDGE_PLUGIN_WASI_NN_BURNRS_MODEL}") + +set(RS_SO ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_DIR}/libwasmedgePluginWasiNN${CMAKE_SHARED_LIBRARY_SUFFIX}) + +set(WASMEDGE_LIB_DIR ${CMAKE_CURRENT_BINARY_DIR}/../../lib/api) + +add_custom_target(wasmedgePluginWasiNNBurnRS ALL + COMMAND WASMEDGE_LIB_DIR=${WASMEDGE_LIB_DIR} LD_LIBARAY_PATH=${WASMEDGE_LIB_DIR} CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR} ${CARGO_CMD} ${CARGO_FEATURES} + COMMAND ${CMAKE_COMMAND} -E copy ${RS_SO} ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS wasmedge_shared +) diff --git a/plugins/wasi_nn_burnrs/Cargo.toml b/plugins/wasi_nn_burnrs/Cargo.toml new file mode 100644 index 000000000000..6a71a2176fad --- /dev/null +++ b/plugins/wasi_nn_burnrs/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "wasi_nn_burnrs" +version = "0.0.1" +edition = "2021" + +[lib] +name = "wasmedgePluginWasiNN" +path = "src/lib.rs" +crate-type = ["cdylib"] + +[features] +default = [] +squeezenet = ["squeezenet-burn"] +whisper = ["whisper-burn", "strum", "strum_macros"] + +[dependencies.squeezenet-burn] +package = "squeezenet-burn" +branch = "prebuilt-feature" +git = "https://github.com/second-state/burn-rs-models.git" +features = ["weights_file"] +default-features = false +optional = true + +[dependencies.whisper-burn] +package = "whisper" +branch = "dev" +git = "https://github.com/second-state/burn-rs-whisper.git" +optional = true + +[dependencies] +burn = { version = "0.13.2", features = ["ndarray", "wgpu"] } +wasmedge_plugin_sdk = { git = "https://github.com/second-state/wasmedge_plugin_rust_sdk.git", features = ["standalone"] } +wasmedge-wasi-nn = "0.8.0" +lazy_static = "1.4.0" +bytemuck = "1.16.0" +cfg-if = "1.0.0" +strum = { version = "0.25.0", optional = true } +strum_macros = { version = "0.25.0", optional = true } diff --git a/plugins/wasi_nn_burnrs/src/helper.rs b/plugins/wasi_nn_burnrs/src/helper.rs new file mode 100644 index 000000000000..81375c348878 --- /dev/null +++ b/plugins/wasi_nn_burnrs/src/helper.rs @@ -0,0 +1,11 @@ +#[macro_export] +macro_rules! get_slice { + ($memory:expr, $ptr:expr, $length:expr, $ty:ty) => {{ + let raw_bytes = $memory + .data_pointer($ptr as usize, $length as usize) + .expect("Failed to get data pointer"); + bytemuck::cast_slice::<u8, $ty>(raw_bytes) + }}; +} + +pub use get_slice; diff --git a/plugins/wasi_nn_burnrs/src/lib.rs b/plugins/wasi_nn_burnrs/src/lib.rs new file mode 100644 index 000000000000..562f83040c63 --- /dev/null +++ b/plugins/wasi_nn_burnrs/src/lib.rs @@ -0,0 +1,382 @@ +mod helper; +mod models; + +pub enum ErrNo { + Success = 0, // No error occurred. + InvalidArgument = 1, // Caller module passed an invalid argument. + InvalidEncoding = 2, // Invalid encoding. + MissingMemory = 3, // Caller module is missing a memory export. + Busy = 4, // Device or resource busy. + RuntimeError = 5, // Runtime Error. + UnsupportedOperation = 6, // Unsupported Operation. + TooLarge = 7, // Too Large. + NotFound = 8, // Not Found. +} +mod wasi_nn { + use crate::helper::get_slice; + #[cfg(feature = "squeezenet")] + use crate::models::squeezenet::*; + #[cfg(feature = "whisper")] + use crate::models::whisper::*; + use crate::ErrNo; + use burn::backend::wgpu::{AutoGraphicsApi, Wgpu, WgpuDevice}; + use burn::backend::NdArray; + use lazy_static::lazy_static; + use std::collections::HashMap; + use std::env; + use std::mem; + use std::process; + use std::sync::Mutex; + + use wasmedge_wasi_nn::TensorType; + use wasmedge_plugin_sdk::{ + error::CoreError, + memory::Memory, + module::{PluginModule, SyncInstanceRef}, + types::{ValType, WasmVal}, + }; + + type NdArrayBackend = NdArray<f32>; + type WgpuBackend = Wgpu<AutoGraphicsApi, f32, i32>; + + pub enum Graph { + /// The model is loaded to the NdArray backend + WithNdArrayBackend(GraphInner<NdArrayBackend>), + /// The model is loaded to the Wgpu backend + WithWgpuBackend(GraphInner<WgpuBackend>), + } + + enum ExecutionContext { + /// The model is loaded to the NdArray backend + WithNdArrayBackend(ContextInner<NdArrayBackend>), + /// The model is loaded to the Wgpu backend + WithWgpuBackend(ContextInner<WgpuBackend>), + } + + lazy_static! { + static ref GRAPH_HANDLE_MAP: Mutex<HashMap<u32, Graph>> = Mutex::new(HashMap::new()); + static ref GRAPH_NAME_MAP: Mutex<HashMap<String, u32>> = Mutex::new(HashMap::new()); + static ref CONTEXT_HANDLE_MAP: Mutex<HashMap<u32, (u32, ExecutionContext)>> = + Mutex::new(HashMap::new()); + } + + fn parse_opts() { + fn process_nn_preload(nn_preload: String) { + let parts: Vec<&str> = nn_preload.split(':').collect(); + + if parts.len() < 4 { + eprintln!("[WASI_NN] Invalid nn-preload format. {:?} len < 4", parts); + process::exit(1); + } + + let graph_encoding = parts[1].to_string(); + if graph_encoding.to_lowercase() != "burn" { + eprintln!("[WASI_NN] Unsupported graph encoding. {:?}", graph_encoding); + process::exit(1); + } + + let name = parts[0].to_string(); + let mut graph_map = GRAPH_HANDLE_MAP.lock().unwrap(); + let graph_handle = graph_map.len() as u32; + let mut name_map = GRAPH_NAME_MAP.lock().unwrap(); + name_map.insert(name.clone(), graph_handle); + let target = parts[2].to_string().to_lowercase(); + if target == "gpu" { + let device = WgpuDevice::BestAvailable; + graph_map.insert( + graph_handle, + Graph::WithWgpuBackend(GraphInner::create(parts[3..].to_vec(), &device)), + ); + } else { + let device = Default::default(); + graph_map.insert( + graph_handle, + Graph::WithNdArrayBackend(GraphInner::create(parts[3..].to_vec(), &device)), + ); + }; + } + + unsafe { + if let Ok(nn_preload) = (*crate::nn_preload()).to_string() { + process_nn_preload(nn_preload); + } else if let Ok(env_nn_preload) = env::var("WASMEDGE_WASINN_PRELOAD") { + process_nn_preload(env_nn_preload); + } + } + } + + pub fn create_module() -> PluginModule<()> { + fn load<'a>( + _inst: &'a mut SyncInstanceRef, + _memory: &'a mut Memory, + _data: &'a mut (), + _args: Vec<WasmVal>, + ) -> Result<Vec<WasmVal>, CoreError> { + Ok(vec![WasmVal::I32(ErrNo::UnsupportedOperation as i32)]) + } + + fn load_by_name<'a>( + _inst: &'a mut SyncInstanceRef, + memory: &'a mut Memory, + _data: &'a mut (), + args: Vec<WasmVal>, + ) -> Result<Vec<WasmVal>, CoreError> { + if let [WasmVal::I32(data_ptr), WasmVal::I32(data_len), WasmVal::I32(graph_handle_ptr)] = + &args[..] + { + let bytes = memory + .data_pointer(*data_ptr as usize, *data_len as usize) + .unwrap(); + let name = String::from_utf8_lossy(&bytes); + let name_map = GRAPH_NAME_MAP.lock().unwrap(); + if let Some(handle) = name_map.get(name.as_ref()) { + memory.write_data((*graph_handle_ptr as usize).into(), *handle); + Ok(vec![WasmVal::I32(ErrNo::Success as i32)]) + } else { + Ok(vec![WasmVal::I32(ErrNo::NotFound as i32)]) + } + } else { + Ok(vec![WasmVal::I32(ErrNo::InvalidArgument as i32)]) + } + } + + fn init_execution_context<'a>( + _inst: &'a mut SyncInstanceRef, + memory: &'a mut Memory, + _data: &'a mut (), + args: Vec<WasmVal>, + ) -> Result<Vec<WasmVal>, CoreError> { + if let [WasmVal::I32(graph_handle), WasmVal::I32(context_handle_ptr)] = &args[..] { + let mut context_map = CONTEXT_HANDLE_MAP.lock().unwrap(); + let context_handle = context_map.len() as u32; + let graph_map = GRAPH_HANDLE_MAP.lock().unwrap(); + let graph = graph_map + .get(&(*graph_handle as u32)) + .unwrap_or_else(|| unreachable!()); + match graph { + Graph::WithNdArrayBackend(_) => { + context_map.insert( + context_handle, + ( + *graph_handle as u32, + ExecutionContext::WithNdArrayBackend(ContextInner::new()), + ), + ); + } + Graph::WithWgpuBackend(_) => { + context_map.insert( + context_handle, + ( + *graph_handle as u32, + ExecutionContext::WithWgpuBackend(ContextInner::new()), + ), + ); + } + } + memory.write_data((*context_handle_ptr as usize).into(), context_handle); + Ok(vec![WasmVal::I32(ErrNo::Success as i32)]) + } else { + Ok(vec![WasmVal::I32(ErrNo::InvalidArgument as i32)]) + } + } + + fn set_input<'a>( + _inst: &'a mut SyncInstanceRef, + memory: &'a mut Memory, + _data: &'a mut (), + args: Vec<WasmVal>, + ) -> Result<Vec<WasmVal>, CoreError> { + #[derive(Debug)] + #[repr(C)] + struct WasiTensorData { + dimens_ptr: u32, + dimens_length: u32, + tensor_type: TensorType, + tensor_ptr: u32, + tensor_length: u32, + } + if let [WasmVal::I32(context_handle), WasmVal::I32(input_index), WasmVal::I32(input_tensor_ptr)] = + &args[..] + { + match memory.get_data::<WasiTensorData>((*input_tensor_ptr as usize).into()) { + Some(input_tensor) => { + let raw_dimens = get_slice!( + memory, + input_tensor.dimens_ptr, + INPUT_DIM * mem::size_of::<u32>(), + u32 + ); + let dimens: [usize; INPUT_DIM] = raw_dimens + .iter() + .map(|&x| x as usize) + .collect::<Vec<usize>>() + .try_into() + .unwrap(); + + // FIXME: The type of f32 should be decided at runtime based on input_tensor.tensor_type. + let tensor = get_slice!( + memory, + input_tensor.tensor_ptr, + input_tensor.tensor_length, + f32 + ); + + let mut context_map = CONTEXT_HANDLE_MAP.lock().unwrap(); + let (_, context) = context_map + .get_mut(&(*context_handle as u32)) + .unwrap_or_else(|| unreachable!()); + + match context { + ExecutionContext::WithNdArrayBackend(inner) => { + inner.set_input(*input_index as u32, tensor, dimens); + } + ExecutionContext::WithWgpuBackend(inner) => { + inner.set_input(*input_index as u32, tensor, dimens); + } + } + Ok(vec![WasmVal::I32(ErrNo::Success as i32)]) + } + None => Ok(vec![WasmVal::I32(ErrNo::MissingMemory as i32)]), + } + } else { + Ok(vec![WasmVal::I32(ErrNo::InvalidArgument as i32)]) + } + } + + fn compute<'a>( + _inst: &'a mut SyncInstanceRef, + _memory: &'a mut Memory, + _data: &'a mut (), + args: Vec<WasmVal>, + ) -> Result<Vec<WasmVal>, CoreError> { + if let [WasmVal::I32(context_handle)] = &args[..] { + let mut context_map = CONTEXT_HANDLE_MAP.lock().unwrap(); + let (graph_handle, context) = context_map + .get_mut(&(*context_handle as u32)) + .unwrap_or_else(|| unreachable!()); + + let graph_map = GRAPH_HANDLE_MAP.lock().unwrap(); + let graph = graph_map + .get(graph_handle) + .unwrap_or_else(|| unreachable!()); + + match context { + ExecutionContext::WithNdArrayBackend(ctx_inner) => { + let Graph::WithNdArrayBackend(graph_inner) = graph else { + unreachable!() + }; + let output = + graph_inner.compute((*ctx_inner.inputs.get(&0).unwrap()).clone()); + ctx_inner.outputs.push(output); + } + ExecutionContext::WithWgpuBackend(ctx_inner) => { + let Graph::WithWgpuBackend(graph_inner) = graph else { + unreachable!() + }; + let output = + graph_inner.compute((*ctx_inner.inputs.get(&0).unwrap()).clone()); + ctx_inner.outputs.push(output); + } + }; + Ok(vec![WasmVal::I32(ErrNo::Success as i32)]) + } else { + Ok(vec![WasmVal::I32(ErrNo::InvalidArgument as i32)]) + } + } + + fn get_output<'a>( + _inst: &'a mut SyncInstanceRef, + memory: &'a mut Memory, + _data: &'a mut (), + args: Vec<WasmVal>, + ) -> Result<Vec<WasmVal>, CoreError> { + if let [WasmVal::I32(context_handle), WasmVal::I32(output_index), WasmVal::I32(output_ptr), WasmVal::I32(output_max_size), WasmVal::I32(written_length)] = + &args[..] + { + let mut context_map = CONTEXT_HANDLE_MAP.lock().unwrap(); + let (_, context) = context_map + .get_mut(&(*context_handle as u32)) + .unwrap_or_else(|| unreachable!()); + let raw_output = match context { + ExecutionContext::WithNdArrayBackend(ctx_inner) => { + ctx_inner.get_output(*output_index as usize) + } + ExecutionContext::WithWgpuBackend(ctx_inner) => { + ctx_inner.get_output(*output_index as usize) + } + }; + let output: &[u8] = bytemuck::cast_slice(&raw_output); + if output.len() > *output_max_size as usize { + return Ok(vec![WasmVal::I32(ErrNo::TooLarge as i32)]); + } + memory.write_bytes(output, *output_ptr as u32).unwrap(); + memory.write_data((*written_length as usize).into(), output.len()); + Ok(vec![WasmVal::I32(ErrNo::Success as i32)]) + } else { + Ok(vec![WasmVal::I32(ErrNo::InvalidArgument as i32)]) + } + } + + parse_opts(); + + let mut module = PluginModule::create("wasi_ephemeral_nn", ()).unwrap(); + module + .add_func("load", (vec![ValType::I32; 5], vec![ValType::I32]), load) + .unwrap(); + module + .add_func( + "load_by_name", + (vec![ValType::I32; 3], vec![ValType::I32]), + load_by_name, + ) + .unwrap(); + module + .add_func( + "init_execution_context", + (vec![ValType::I32; 2], vec![ValType::I32]), + init_execution_context, + ) + .unwrap(); + module + .add_func( + "set_input", + (vec![ValType::I32; 3], vec![ValType::I32]), + set_input, + ) + .unwrap(); + module + .add_func( + "compute", + (vec![ValType::I32; 1], vec![ValType::I32]), + compute, + ) + .unwrap(); + module + .add_func( + "get_output", + (vec![ValType::I32; 5], vec![ValType::I32]), + get_output, + ) + .unwrap(); + module + } +} + +use wasi_nn::create_module; +use wasmedge_plugin_sdk::plugin::{option_string, register_plugin, OptionString}; +register_plugin!( + plugin_name = "wasi_nn", + plugin_description = "burn framework adapter as wasi-nn plugin", + version = (0,0,0,1), + modules = [ + {"wasi_nn", "wasinn with burn backend module", create_module} + ], + options = [ + { + "nn-preload", + "Allow preload models from wasinn plugin. Each NN model can be specified as --nn-preload `COMMAND`.", + OptionString, + option_string!("none") + } + ] +); diff --git a/plugins/wasi_nn_burnrs/src/models/mod.rs b/plugins/wasi_nn_burnrs/src/models/mod.rs new file mode 100644 index 000000000000..f7f7aadfc5d0 --- /dev/null +++ b/plugins/wasi_nn_burnrs/src/models/mod.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "squeezenet")] +pub mod squeezenet; +#[cfg(feature = "whisper")] +pub mod whisper; diff --git a/plugins/wasi_nn_burnrs/src/models/squeezenet.rs b/plugins/wasi_nn_burnrs/src/models/squeezenet.rs new file mode 100644 index 000000000000..c4c7d0d14d41 --- /dev/null +++ b/plugins/wasi_nn_burnrs/src/models/squeezenet.rs @@ -0,0 +1,45 @@ +use burn::tensor::backend::Backend; +use burn::tensor::Tensor; +use squeezenet_burn::model::squeezenet1::Model; +use std::collections::HashMap; + +pub struct GraphInner<B: Backend> { + pub model: Model<B>, +} + +impl<B: Backend> GraphInner<B> { + pub fn create(args: Vec<&str>, device: &B::Device) -> Self { + let weights_path = args[0]; + Self { + model: Model::from_file(weights_path, device), + } + } + pub fn compute(&self, input: Tensor<B, INPUT_DIM>) -> Tensor<B, OUTPUT_DIM> { + self.model.forward(input) + } +} + +pub const INPUT_DIM: usize = 4; +pub const OUTPUT_DIM: usize = 2; + +pub struct ContextInner<B: Backend> { + pub inputs: HashMap<u32, Tensor<B, INPUT_DIM>>, + pub outputs: Vec<Tensor<B, OUTPUT_DIM>>, +} + +impl<B: Backend> ContextInner<B> { + pub fn new() -> Self { + Self { + inputs: HashMap::new(), + outputs: Vec::new(), + } + } + pub fn set_input(&mut self, key: u32, input: &[B::FloatElem], dimens: [usize; INPUT_DIM]) { + let device = Default::default(); + let tensor = Tensor::<B, 1>::from_data(&*input, &device).reshape(dimens); + self.inputs.insert(key, tensor); + } + pub fn get_output(&mut self, key: usize) -> Vec<<B as Backend>::FloatElem> { + self.outputs[key].clone().into_data().value + } +} diff --git a/plugins/wasi_nn_burnrs/src/models/whisper.rs b/plugins/wasi_nn_burnrs/src/models/whisper.rs new file mode 100644 index 000000000000..987f77ed0166 --- /dev/null +++ b/plugins/wasi_nn_burnrs/src/models/whisper.rs @@ -0,0 +1,96 @@ +use burn::config::Config; +use burn::module::Module; +use burn::record::{DefaultRecorder, Recorder}; +use burn::tensor::backend::Backend; +use std::collections::HashMap; +use std::marker::PhantomData; +use std::process; +use strum::IntoEnumIterator; +use whisper_burn::model::Whisper as Model; +use whisper_burn::model::WhisperConfig as ModelConfig; +use whisper_burn::token::{Gpt2Tokenizer, Language}; +use whisper_burn::transcribe::waveform_to_text; + +pub struct GraphInner<B: Backend> { + pub model: Model<B>, + pub metadata: Vec<String>, +} + +impl<B: Backend> GraphInner<B> { + pub fn create(args: Vec<&str>, device: &B::Device) -> Self { + if args.len() < 4 { + eprintln!( + "[WASI_NN] Invalid nn-preload model format. {:?} len < 4", + args + ); + process::exit(1); + } + let weights_path = args[0]; + let config_path = args[1]; + let config = match ModelConfig::load(config_path) { + Ok(config) => config, + Err(e) => { + eprintln!("Failed to load whisper config: {}", e); + process::exit(1); + } + }; + let recorder = DefaultRecorder::new().load(weights_path.into(), device); + let model = recorder + .map(|record| config.init(device).load_record(record)) + .unwrap(); + Self { + model: model, + metadata: args[2..].iter().map(|&s| s.to_string()).collect(), + } + } + pub fn compute(&self, input: Vec<f32>) -> Vec<u8> { + let tokenizer_path = &self.metadata[0].to_string(); + let lang_str = &self.metadata[1].to_string(); + let lang = match Language::iter().find(|lang| lang.as_str() == lang_str) { + Some(lang) => lang, + None => { + eprintln!("Invalid language abbreviation: {}", lang_str); + process::exit(1); + } + }; + let bpe = match Gpt2Tokenizer::new_with_path(tokenizer_path) { + Ok(bpe) => bpe, + Err(e) => { + eprintln!("Failed to load tokenizer: {}", e); + process::exit(1); + } + }; + let (text, _) = match waveform_to_text(&self.model, &bpe, lang, input, 16000) { + Ok((text, tokens)) => (text, tokens), + Err(e) => { + eprintln!("Error during transcription: {}", e); + process::exit(1); + } + }; + return text.into_bytes(); + } +} + +pub const INPUT_DIM: usize = 2; + +pub struct ContextInner<B: Backend> { + pub inputs: HashMap<u32, Vec<f32>>, + pub outputs: Vec<Vec<u8>>, + _marker: PhantomData<B>, +} + +impl<B: Backend> ContextInner<B> { + pub fn new() -> Self { + Self { + inputs: HashMap::new(), + outputs: Vec::new(), + _marker: PhantomData, + } + } + pub fn set_input(&mut self, key: u32, input: &[f32], _: [usize; INPUT_DIM]) { + self.inputs.insert(key, input.to_vec()); + } + pub fn get_output(&mut self, key: usize) -> &Vec<u8> { + &self.outputs[key] + } +} diff --git a/plugins/wasi_poll/CMakeLists.txt b/plugins/wasi_poll/CMakeLists.txt new file mode 100644 index 000000000000..0ffa67c6b15b --- /dev/null +++ b/plugins/wasi_poll/CMakeLists.txt @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +wasmedge_add_library(wasmedgePluginWasiPoll + SHARED + env.cpp + func.cpp + module.cpp +) + +target_compile_options(wasmedgePluginWasiPoll + PUBLIC + -DWASMEDGE_PLUGIN +) + +target_include_directories(wasmedgePluginWasiPoll + PUBLIC + $<TARGET_PROPERTY:wasmedgePlugin,INCLUDE_DIRECTORIES> + ${CMAKE_CURRENT_SOURCE_DIR} + ${PROJECT_SOURCE_DIR}/thirdparty +) + +target_link_libraries(wasmedgePluginWasiPoll + PUBLIC +) + +if(WASMEDGE_LINK_PLUGINS_STATIC) + target_link_libraries(wasmedgePluginWasiPoll + PRIVATE + wasmedgeCAPI + ) +else() + target_link_libraries(wasmedgePluginWasiPoll + PRIVATE + wasmedge_shared + ) +endif() + +install( + TARGETS wasmedgePluginWasiPoll + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) diff --git a/plugins/wasi_poll/README.md b/plugins/wasi_poll/README.md new file mode 100644 index 000000000000..4eae44f4ea24 --- /dev/null +++ b/plugins/wasi_poll/README.md @@ -0,0 +1,3 @@ +# wasi_poll + +This is corresponding to [wasi-poll preview2](https://github.com/WebAssembly/wasi-poll). diff --git a/plugins/wasi_poll/base.h b/plugins/wasi_poll/base.h new file mode 100644 index 000000000000..e1c50bb7969d --- /dev/null +++ b/plugins/wasi_poll/base.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "env.h" + +#include "common/errcode.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { + +template <typename T> class WasiPoll : public Runtime::HostFunction<T> { +public: + WasiPoll(WasiPollEnvironment &HostEnv) + : Runtime::HostFunction<T>(0), Env(HostEnv) {} + +protected: + WasiPollEnvironment &Env; +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_poll/env.cpp b/plugins/wasi_poll/env.cpp new file mode 100644 index 000000000000..90b5e6320dca --- /dev/null +++ b/plugins/wasi_poll/env.cpp @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "env.h" +#include "module.h" + +namespace WasmEdge { +namespace Host { + +WasiPollEnvironment::WasiPollEnvironment() noexcept {} + +namespace { + +Runtime::Instance::ComponentInstance * +create(const Plugin::PluginComponent::ComponentDescriptor *) noexcept { + return new WasiPollModule(); +} + +Plugin::Plugin::PluginDescriptor Descriptor{ + .Name = "wasi_poll", + .Description = "", + .APIVersion = Plugin::Plugin::CurrentAPIVersion, + .Version = {0, 1, 0, 0}, + .ModuleCount = 0, + .ModuleDescriptions = {}, + .ComponentCount = 1, + .ComponentDescriptions = + (Plugin::PluginComponent::ComponentDescriptor[]){ + { + .Name = "wasi:poll/poll", + .Description = "", + .Create = create, + }, + }, + .AddOptions = nullptr, +}; + +EXPORT_GET_DESCRIPTOR(Descriptor) + +} // namespace +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_poll/env.h b/plugins/wasi_poll/env.h new file mode 100644 index 000000000000..e7d8ab1d06f3 --- /dev/null +++ b/plugins/wasi_poll/env.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC +#pragma once + +#include "plugin/plugin.h" + +#include <cstdint> +#include <vector> + +namespace WasmEdge { +namespace Host { + +class WasiPollEnvironment { +public: + WasiPollEnvironment() noexcept; +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_poll/func.cpp b/plugins/wasi_poll/func.cpp new file mode 100644 index 000000000000..732208dd1744 --- /dev/null +++ b/plugins/wasi_poll/func.cpp @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "func.h" +#include "common/defines.h" +#include "common/errcode.h" + +namespace WasmEdge { +namespace Host { + +Expect<void> Drop::body(const Runtime::CallingFrame &, Pollable) { return {}; } + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_poll/func.h b/plugins/wasi_poll/func.h new file mode 100644 index 000000000000..4daa13bc7585 --- /dev/null +++ b/plugins/wasi_poll/func.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { + +using Pollable = uint32_t; + +class Drop : public WasiPoll<Drop> { +public: + Drop(WasiPollEnvironment &HostEnv) : WasiPoll(HostEnv) {} + Expect<void> body(const Runtime::CallingFrame &Frame, Pollable This); +}; + +// poll-oneoff: func(in: list<pollable>) -> list<bool> + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_poll/module.cpp b/plugins/wasi_poll/module.cpp new file mode 100644 index 000000000000..b523f8677d63 --- /dev/null +++ b/plugins/wasi_poll/module.cpp @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "module.h" +#include "func.h" + +#include <memory> + +namespace WasmEdge { +namespace Host { + +WasiPollModule::WasiPollModule() : ComponentInstance("wasi:poll/poll") { + addHostFunc("drop-pollable", std::make_unique<Drop>(Env)); +} + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_poll/module.h b/plugins/wasi_poll/module.h new file mode 100644 index 000000000000..5c26930ff388 --- /dev/null +++ b/plugins/wasi_poll/module.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "env.h" + +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { + +class WasiPollModule : public Runtime::Instance::ComponentInstance { +public: + WasiPollModule(); + + WasiPollEnvironment &getEnv() { return Env; } + +private: + WasiPollEnvironment Env; +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasm_bpf/CMakeLists.txt b/plugins/wasm_bpf/CMakeLists.txt index 0e4e81203ee0..924b898aa2b6 100644 --- a/plugins/wasm_bpf/CMakeLists.txt +++ b/plugins/wasm_bpf/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC # Try to get libbpf use the following order # - PkgConfig diff --git a/plugins/wasm_bpf/README.md b/plugins/wasm_bpf/README.md index 05a2755f13b8..824bd0622732 100644 --- a/plugins/wasm_bpf/README.md +++ b/plugins/wasm_bpf/README.md @@ -106,4 +106,4 @@ Set `WASMEDGE_PLUGIN_PATH=./build/plugins/wasm_bpf/` and run wasmedge: [289159] cpuUsage.sh -> cat /proc/289148/stat [289160] cpuUsage.sh -> sleep 1 ^C -``` \ No newline at end of file +``` diff --git a/plugins/wasm_bpf/bpf-api.h b/plugins/wasm_bpf/bpf-api.h index 3b2018fcc56b..1970fe69e282 100644 --- a/plugins/wasm_bpf/bpf-api.h +++ b/plugins/wasm_bpf/bpf-api.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasm_bpf/func-attach-bpf-program.cpp b/plugins/wasm_bpf/func-attach-bpf-program.cpp index be4d6adec617..27e2e0d83677 100644 --- a/plugins/wasm_bpf/func-attach-bpf-program.cpp +++ b/plugins/wasm_bpf/func-attach-bpf-program.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "func-attach-bpf-program.h" #include "util.h" diff --git a/plugins/wasm_bpf/func-attach-bpf-program.h b/plugins/wasm_bpf/func-attach-bpf-program.h index df5abedd5422..5eda908815da 100644 --- a/plugins/wasm_bpf/func-attach-bpf-program.h +++ b/plugins/wasm_bpf/func-attach-bpf-program.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasm_bpf/func-bpf-buffer-poll.cpp b/plugins/wasm_bpf/func-bpf-buffer-poll.cpp index 45b6e5ca316a..7fb8ce03405f 100644 --- a/plugins/wasm_bpf/func-bpf-buffer-poll.cpp +++ b/plugins/wasm_bpf/func-bpf-buffer-poll.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "func-bpf-buffer-poll.h" #include "wasmedge/wasmedge.h" @@ -12,6 +12,7 @@ namespace Host { inline const auto *toCallFrameCxt(const Runtime::CallingFrame *Cxt) noexcept { return reinterpret_cast<const WasmEdge_CallingFrameContext *>(Cxt); } + Expect<int32_t> BpfBufferPoll::body(const Runtime::CallingFrame &Frame, handle_t program, int32_t fd, int32_t sample_func, uint32_t ctx, diff --git a/plugins/wasm_bpf/func-bpf-buffer-poll.h b/plugins/wasm_bpf/func-bpf-buffer-poll.h index 2ece1588f5bd..ff33f82ef452 100644 --- a/plugins/wasm_bpf/func-bpf-buffer-poll.h +++ b/plugins/wasm_bpf/func-bpf-buffer-poll.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasm_bpf/func-bpf-map-fd-by-name.cpp b/plugins/wasm_bpf/func-bpf-map-fd-by-name.cpp index c7a98eef9a0c..6f6e717299ff 100644 --- a/plugins/wasm_bpf/func-bpf-map-fd-by-name.cpp +++ b/plugins/wasm_bpf/func-bpf-map-fd-by-name.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "func-bpf-map-fd-by-name.h" #include "util.h" diff --git a/plugins/wasm_bpf/func-bpf-map-fd-by-name.h b/plugins/wasm_bpf/func-bpf-map-fd-by-name.h index d15f67db84dd..f4d93e1e509b 100644 --- a/plugins/wasm_bpf/func-bpf-map-fd-by-name.h +++ b/plugins/wasm_bpf/func-bpf-map-fd-by-name.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasm_bpf/func-bpf-map-operate.cpp b/plugins/wasm_bpf/func-bpf-map-operate.cpp index e1dbc24234bd..73b1cd6f5a28 100644 --- a/plugins/wasm_bpf/func-bpf-map-operate.cpp +++ b/plugins/wasm_bpf/func-bpf-map-operate.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "func-bpf-map-operate.h" #include "bpf-api.h" @@ -16,6 +16,7 @@ namespace Host { if (var##_span.size() != expected_size) \ return Unexpect(ErrCode::Value::HostFuncError); \ const auto var = var##_span.data(); + Expect<int32_t> BpfMapOperate::body(const WasmEdge::Runtime::CallingFrame &Frame, int32_t fd, int32_t cmd, uint32_t key, uint32_t value, diff --git a/plugins/wasm_bpf/func-bpf-map-operate.h b/plugins/wasm_bpf/func-bpf-map-operate.h index 259f28deeeb5..486f7d9b64d1 100644 --- a/plugins/wasm_bpf/func-bpf-map-operate.h +++ b/plugins/wasm_bpf/func-bpf-map-operate.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "bpf-api.h" #include "plugin/plugin.h" diff --git a/plugins/wasm_bpf/func-close-bpf-object.cpp b/plugins/wasm_bpf/func-close-bpf-object.cpp index 909b4f0f1165..52b428fb5221 100644 --- a/plugins/wasm_bpf/func-close-bpf-object.cpp +++ b/plugins/wasm_bpf/func-close-bpf-object.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "func-close-bpf-object.h" #include <shared_mutex> diff --git a/plugins/wasm_bpf/func-close-bpf-object.h b/plugins/wasm_bpf/func-close-bpf-object.h index 3c4412381bc9..1d8d8c12c383 100644 --- a/plugins/wasm_bpf/func-close-bpf-object.h +++ b/plugins/wasm_bpf/func-close-bpf-object.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasm_bpf/func-load-bpf-object.cpp b/plugins/wasm_bpf/func-load-bpf-object.cpp index 99e5f72ee9be..c9c7b68238dd 100644 --- a/plugins/wasm_bpf/func-load-bpf-object.cpp +++ b/plugins/wasm_bpf/func-load-bpf-object.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "func-load-bpf-object.h" diff --git a/plugins/wasm_bpf/func-load-bpf-object.h b/plugins/wasm_bpf/func-load-bpf-object.h index 5a6226adc648..39516908df4d 100644 --- a/plugins/wasm_bpf/func-load-bpf-object.h +++ b/plugins/wasm_bpf/func-load-bpf-object.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasm_bpf/state.h b/plugins/wasm_bpf/state.h index 7ea995b84493..cd9d4720bb57 100644 --- a/plugins/wasm_bpf/state.h +++ b/plugins/wasm_bpf/state.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasm_bpf/util.cpp b/plugins/wasm_bpf/util.cpp index 9851c2ac922e..b3c45b7b6e96 100644 --- a/plugins/wasm_bpf/util.cpp +++ b/plugins/wasm_bpf/util.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "util.h" diff --git a/plugins/wasm_bpf/util.h b/plugins/wasm_bpf/util.h index 958290ff4a8b..4ac79e44cc65 100644 --- a/plugins/wasm_bpf/util.h +++ b/plugins/wasm_bpf/util.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasm_bpf/wasm-bpf-module.cpp b/plugins/wasm_bpf/wasm-bpf-module.cpp index 9ae739d41a2b..a240e6a42fce 100644 --- a/plugins/wasm_bpf/wasm-bpf-module.cpp +++ b/plugins/wasm_bpf/wasm-bpf-module.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "wasm-bpf-module.h" #include "func-attach-bpf-program.h" @@ -13,7 +13,6 @@ #include "runtime/callingframe.h" #include "state.h" #include <algorithm> -#include <iostream> namespace WasmEdge { namespace Host { @@ -53,7 +52,7 @@ Plugin::Plugin::PluginDescriptor Descriptor{ }, .AddOptions = nullptr}; -Plugin::PluginRegister Register(&Descriptor); +EXPORT_GET_DESCRIPTOR(Descriptor) } // namespace Host } // namespace WasmEdge diff --git a/plugins/wasm_bpf/wasm-bpf-module.h b/plugins/wasm_bpf/wasm-bpf-module.h index 8cbdd9dd6bbd..65eba2550cc0 100644 --- a/plugins/wasm_bpf/wasm-bpf-module.h +++ b/plugins/wasm_bpf/wasm-bpf-module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasm_bpf/wasm-bpf.cpp b/plugins/wasm_bpf/wasm-bpf.cpp index 9adb55eb19d4..3c60665ad54c 100644 --- a/plugins/wasm_bpf/wasm-bpf.cpp +++ b/plugins/wasm_bpf/wasm-bpf.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include <asm/unistd.h> #include <errno.h> diff --git a/plugins/wasmedge_ffmpeg/CMakeLists.txt b/plugins/wasmedge_ffmpeg/CMakeLists.txt new file mode 100644 index 000000000000..47e72cdd0fd0 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/CMakeLists.txt @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +find_package(PkgConfig REQUIRED) +pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET + libavdevice + libavfilter + libavformat + libavcodec + libswresample + libswscale + libavutil +) + +wasmedge_add_library(wasmedgePluginWasmEdgeFFmpeg + SHARED + + avcodec/avCodecContext.cpp + avcodec/avCodec.cpp + avcodec/avCodecParameters.cpp + avcodec/avPacket.cpp + avcodec/avcodec_func.cpp + avcodec/module.cpp + + avdevice/avDevice_func.cpp + avdevice/module.cpp + + avfilter/buffer_source_sink.cpp + avfilter/avFilter.cpp + avfilter/avfilter_func.cpp + avfilter/module.cpp + + avformat/avformatContext.cpp + avformat/avInputOutputFormat.cpp + avformat/avStream.cpp + avformat/avChapter.cpp + avformat/avformat_func.cpp + avformat/module.cpp + + avutil/error.cpp + avutil/avRational.cpp + avutil/avFrame.cpp + avutil/pixfmt.cpp + avutil/samplefmt.cpp + avutil/avDictionary.cpp + avutil/avTime.cpp + avutil/avutil_func.cpp + avutil/module.cpp + + swresample/swresample_func.cpp + swresample/module.cpp + + swscale/swscale_func.cpp + swscale/module.cpp + + ffmpeg_env.cpp +) + +target_compile_options(wasmedgePluginWasmEdgeFFmpeg + PUBLIC + -DWASMEDGE_PLUGIN + -Wno-deprecated-declarations +) + +target_include_directories(wasmedgePluginWasmEdgeFFmpeg + PUBLIC + $<TARGET_PROPERTY:wasmedgePlugin,INCLUDE_DIRECTORIES> + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(wasmedgePluginWasmEdgeFFmpeg + PUBLIC + PkgConfig::LIBAV +) + +if(WASMEDGE_LINK_PLUGINS_STATIC) + target_link_libraries(wasmedgePluginWasmEdgeFFmpeg + PRIVATE + wasmedgeCAPI + ) +else() + target_link_libraries(wasmedgePluginWasmEdgeFFmpeg + PRIVATE + wasmedge_shared + ) +endif() + +install( + TARGETS wasmedgePluginWasmEdgeFFmpeg + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) diff --git a/plugins/wasmedge_ffmpeg/avcodec/avCodec.cpp b/plugins/wasmedge_ffmpeg/avcodec/avCodec.cpp new file mode 100644 index 000000000000..3ba24d476cac --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avCodec.cpp @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avCodec.h" + +extern "C" { +#include "libavcodec/avcodec.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +Expect<uint32_t> AVCodecID::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return FFmpegUtils::CodecID::fromAVCodecID(AvCodec->id); +} + +Expect<int32_t> AVCodecType::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return FFmpegUtils::MediaType::fromMediaType(AvCodec->type); +} + +Expect<int32_t> AVCodecMaxLowres::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return AvCodec->max_lowres; +} + +Expect<int32_t> AVCodecCapabilities::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return AvCodec->capabilities; +} + +Expect<int32_t> AVCodecGetNameLen::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return strlen(AvCodec->name); +} + +Expect<int32_t> AVCodecGetName::body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecId, uint32_t NamePtr, + uint32_t NameLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(NameBuf, MemInst, char, NamePtr, NameLen, ""); + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + + const char *Name = AvCodec->name; + std::copy_n(Name, NameLen, NameBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecGetLongNameLen::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return strlen(AvCodec->long_name); +} + +Expect<int32_t> AVCodecGetLongName::body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecId, + uint32_t LongNamePtr, + uint32_t LongNameLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(LongNameBuf, MemInst, char, LongNamePtr, LongNameLen, ""); + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + + const char *LongName = AvCodec->long_name; + std::copy_n(LongName, LongNameLen, LongNameBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecProfiles::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + if (AvCodec->profiles) { + return 1; + } + return 0; +} + +Expect<int32_t> AVCodecPixFmtsIsNull::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + if (AvCodec->pix_fmts == nullptr) { + return 1; + } + return 0; +} + +Expect<uint32_t> AVCodecPixFmtsIter::body(const Runtime::CallingFrame &, + uint32_t AvCodecId, uint32_t Idx) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + AVPixelFormat const *PixelFormat = AvCodec->pix_fmts; + if (PixelFormat == nullptr) { + return 0; + } + + uint32_t Curr = 0; + while (Curr < Idx) { + PixelFormat++; + Curr++; + } + + return FFmpegUtils::PixFmt::fromAVPixFmt(*PixelFormat); +} + +Expect<int32_t> +AVCodecSupportedFrameratesIsNull::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + if (AvCodec->supported_framerates == nullptr) { + return 1; + } + return 0; +} + +Expect<int32_t> +AVCodecSupportedFrameratesIter::body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecId, uint32_t Idx, + uint32_t NumPtr, uint32_t DenPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(NumId, MemInst, int32_t, NumPtr, + "Failed when accessing the return NumPtr Memory"sv); + MEM_PTR_CHECK(DenId, MemInst, int32_t, DenPtr, + "Failed when accessing the return DenPtr Memory"sv); + + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + AVRational const *Rational = AvCodec->supported_framerates; + + if (Rational == nullptr) { + *NumId = 0; + *DenId = 0; + return static_cast<int32_t>(ErrNo::Success); + } + + uint32_t Curr = 0; + while (Curr < Idx) { + Rational++; + Curr++; + } + + *NumId = Rational->num; + *DenId = Rational->den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecSupportedSampleRatesIsNull::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + if (AvCodec->supported_samplerates == nullptr) { + return 1; + } + return 0; +} + +Expect<int32_t> +AVCodecSupportedSampleRatesIter::body(const Runtime::CallingFrame &, + uint32_t AvCodecId, uint32_t Idx) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + const int32_t *SampleRates = AvCodec->supported_samplerates; + if (SampleRates == nullptr) { + return 0; + } + + uint32_t Curr = 0; + while (Curr < Idx) { + SampleRates++; + Curr++; + } + + return *SampleRates; +} + +Expect<int32_t> AVCodecChannelLayoutIsNull::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + if (AvCodec->channel_layouts == nullptr) { + return 1; + } + return 0; +} + +Expect<uint64_t> AVCodecChannelLayoutIter::body(const Runtime::CallingFrame &, + uint32_t AvCodecId, + uint32_t Idx) { + + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + const uint64_t *ChannelLayout = AvCodec->channel_layouts; + if (ChannelLayout == nullptr) { + return 0; + } + + uint32_t Curr = 0; + while (Curr < Idx) { + ChannelLayout++; + Curr++; + } + + return FFmpegUtils::ChannelLayout::intoChannelLayoutID(*ChannelLayout); +} + +Expect<int32_t> AVCodecSampleFmtsIsNull::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + if (AvCodec->sample_fmts == nullptr) { + return 1; + } + return 0; +} + +Expect<uint32_t> AVCodecSampleFmtsIter::body(const Runtime::CallingFrame &, + uint32_t AvCodecId, uint32_t Idx) { + + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + AVSampleFormat const *SampleFormat = AvCodec->sample_fmts; + if (SampleFormat == nullptr) { + return 0; + } + + uint32_t Curr = 0; + while (Curr < Idx) { + SampleFormat++; + Curr++; + } + + return FFmpegUtils::SampleFmt::toSampleID(*SampleFormat); +} + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avcodec/avCodec.h b/plugins/wasmedge_ffmpeg/avcodec/avCodec.h new file mode 100644 index 000000000000..70676c2f6267 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avCodec.h @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +class AVCodecID : public HostFunction<AVCodecID> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecType : public HostFunction<AVCodecType> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecMaxLowres : public HostFunction<AVCodecMaxLowres> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecCapabilities : public HostFunction<AVCodecCapabilities> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecGetNameLen : public HostFunction<AVCodecGetNameLen> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecGetName : public HostFunction<AVCodecGetName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t NamePtr, uint32_t NameLen); +}; + +class AVCodecGetLongNameLen : public HostFunction<AVCodecGetLongNameLen> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecGetLongName : public HostFunction<AVCodecGetLongName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t LongNamePtr, uint32_t LongNameLen); +}; + +class AVCodecProfiles : public HostFunction<AVCodecProfiles> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecPixFmtsIsNull : public HostFunction<AVCodecPixFmtsIsNull> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecPixFmtsIter : public HostFunction<AVCodecPixFmtsIter> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t Idx); +}; + +class AVCodecSupportedFrameratesIsNull + : public HostFunction<AVCodecSupportedFrameratesIsNull> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecSupportedFrameratesIter + : public HostFunction<AVCodecSupportedFrameratesIter> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t Idx, uint32_t NumPtr, uint32_t DenPtr); +}; + +class AVCodecSupportedSampleRatesIsNull + : public HostFunction<AVCodecSupportedSampleRatesIsNull> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecSupportedSampleRatesIter + : public HostFunction<AVCodecSupportedSampleRatesIter> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t Idx); +}; + +class AVCodecChannelLayoutIsNull + : public HostFunction<AVCodecChannelLayoutIsNull> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecChannelLayoutIter : public HostFunction<AVCodecChannelLayoutIter> { +public: + using HostFunction::HostFunction; + Expect<uint64_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t Idx); +}; + +class AVCodecSampleFmtsIsNull : public HostFunction<AVCodecSampleFmtsIsNull> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecSampleFmtsIter : public HostFunction<AVCodecSampleFmtsIter> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t Idx); +}; + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avcodec/avCodecContext.cpp b/plugins/wasmedge_ffmpeg/avcodec/avCodecContext.cpp new file mode 100644 index 000000000000..ad6de1033665 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avCodecContext.cpp @@ -0,0 +1,771 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avCodecContext.h" + +extern "C" { +#include "libavcodec/avcodec.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +Expect<uint32_t> AVCodecCtxCodecID::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVCodecID const AvCodecId = AvCodecCtx->codec_id; + return FFmpegUtils::CodecID::fromAVCodecID(AvCodecId); +} + +Expect<int32_t> AVCodecCtxCodecType::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVMediaType const AvMediaType = AvCodecCtx->codec_type; + return FFmpegUtils::MediaType::fromMediaType(AvMediaType); +} + +Expect<int32_t> AVCodecCtxSetCodecType::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t CodecTypeId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVMediaType const AvMediaType = + FFmpegUtils::MediaType::intoMediaType(CodecTypeId); + + AvCodecCtx->codec_type = AvMediaType; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetTimebase::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t Num, + int32_t Den) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVRational const Rational = av_make_q(Num, Den); + AvCodecCtx->time_base = Rational; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxTimeBase::body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t NumPtr, + uint32_t DenPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(Num, MemInst, int32_t, NumPtr, + "Failed to access Numerator Ptr for AVRational"sv); + MEM_PTR_CHECK(Den, MemInst, int32_t, DenPtr, + "Failed to access Denominator Ptr for AVRational"sv); + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVRational const AvRational = AvCodecCtx->time_base; + *Num = AvRational.num; + *Den = AvRational.den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxWidth::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->width; +} + +Expect<int32_t> AVCodecCtxSetWidth::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t Width) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->width = Width; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxHeight::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->height; +} + +Expect<int32_t> AVCodecCtxSetHeight::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Height) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->height = Height; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecCtxSampleAspectRatio::body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t NumPtr, + uint32_t DenPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(Num, MemInst, int32_t, NumPtr, + "Failed to access Numerator Ptr for AVRational"sv); + MEM_PTR_CHECK(Den, MemInst, int32_t, DenPtr, + "Failed to access Denominator Ptr for AVRational"sv); + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + + const AVRational AvRational = AvCodecCtx->sample_aspect_ratio; + *Num = AvRational.num; + *Den = AvRational.den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecCtxSetSampleAspectRatio::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t Num, + int32_t Den) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + const AVRational AspectRatio = av_make_q(Num, Den); + AvCodecCtx->sample_aspect_ratio = AspectRatio; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<uint64_t> AVCodecCtxChannelLayout::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + // Deprecated method + uint64_t const AvChannel = AvCodecCtx->channel_layout; + return FFmpegUtils::ChannelLayout::intoChannelLayoutID(AvChannel); +} + +Expect<int32_t> AVCodecCtxSetChannelLayout::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + uint64_t ChannelLayoutId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + uint64_t const AvChannel = + FFmpegUtils::ChannelLayout::fromChannelLayoutID(ChannelLayoutId); + AvCodecCtx->channel_layout = AvChannel; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<uint32_t> AVCodecCtxPixFormat::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVPixelFormat const PixFmt = AvCodecCtx->pix_fmt; + return FFmpegUtils::PixFmt::fromAVPixFmt(PixFmt); +} + +Expect<int32_t> AVCodecCtxSetPixFormat::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + uint32_t PixFmtId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVPixelFormat const PixFmt = FFmpegUtils::PixFmt::intoAVPixFmt(PixFmtId); + AvCodecCtx->pix_fmt = PixFmt; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<uint32_t> AVCodecCtxSampleFormat::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVSampleFormat const AvSampleFormat = AvCodecCtx->sample_fmt; + return FFmpegUtils::SampleFmt::toSampleID(AvSampleFormat); +} + +Expect<int32_t> AVCodecCtxSetSampleFormat::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + uint32_t SampleFmtId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVSampleFormat const SampleFormat = + FFmpegUtils::SampleFmt::fromSampleID(SampleFmtId); + AvCodecCtx->sample_fmt = SampleFormat; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSampleRate::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->sample_rate; +} + +Expect<int32_t> AVCodecCtxSetSampleRate::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t SampleRate) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->sample_rate = SampleRate; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetGopSize::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t GopSize) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->gop_size = GopSize; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetMaxBFrames::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t MaxBFrames) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->max_b_frames = MaxBFrames; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetBQuantFactor::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float BQuantFactor) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->b_quant_factor = BQuantFactor; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetBQuantOffset::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float BQuantOffset) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->b_quant_offset = BQuantOffset; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetIQuantFactor::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float IQuantFactor) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->i_quant_factor = IQuantFactor; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetIQuantOffset::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float IQuantOffset) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->i_quant_offset = IQuantOffset; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetLumiMasking::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float LumiMasking) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->lumi_masking = LumiMasking; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecCtxSetTemporalCplxMasking::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float TemporalCplxMasking) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->temporal_cplx_masking = TemporalCplxMasking; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecCtxSetSpatialCplxMasking::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float SpatialCplxMasking) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->spatial_cplx_masking = SpatialCplxMasking; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetPMasking::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float PMasking) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->p_masking = PMasking; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetDarkMasking::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float DarkMasking) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->dark_masking = DarkMasking; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetMeCmp::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t MeCmp) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->me_cmp = MeCmp; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetMeSubCmp::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t MeSubCmp) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->me_sub_cmp = MeSubCmp; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetMbCmp::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t MbCmp) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->mb_cmp = MbCmp; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetIldctCmp::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t IldctCmp) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->ildct_cmp = IldctCmp; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetDiaSize::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t DiaSize) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->dia_size = DiaSize; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecCtxSetLastPredictorsCount::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t LastPredictorCount) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->last_predictor_count = LastPredictorCount; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetMePreCmp::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t MePreCmp) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->me_pre_cmp = MePreCmp; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetPreDiaSize::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t PreDiaSize) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->pre_dia_size = PreDiaSize; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecCtxSetMeSubpelQuality::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t MeSubpelQuality) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->me_subpel_quality = MeSubpelQuality; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetMeRange::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t MeRange) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->me_range = MeRange; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetMbDecision::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t MbDecision) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->mb_decision = MbDecision; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetMbLMin::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t MbLMin) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->mb_lmin = MbLMin; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetMbLMax::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t MbLMax) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->mb_lmax = MbLMax; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxIntraDcPrecision::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->intra_dc_precision; +} + +Expect<int32_t> +AVCodecCtxSetIntraDcPrecision::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t IntraDcPrecision) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->intra_dc_precision = IntraDcPrecision; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetQMin::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t QMin) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->qmin = QMin; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetQMax::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t QMax) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->qmax = QMax; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetGlobalQuality::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t GlobalQuality) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->global_quality = GlobalQuality; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetColorspace::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t ColorspaceId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVColorSpace const ColorSpace = + FFmpegUtils::ColorSpace::intoAVColorSpace(ColorspaceId); + AvCodecCtx->colorspace = ColorSpace; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxColorspace::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVColorSpace const Colorspace = AvCodecCtx->colorspace; + return FFmpegUtils::ColorSpace::fromAVColorSpace(Colorspace); +} + +Expect<int32_t> AVCodecCtxSetColorRange::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t ColorRangeId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->color_range = static_cast<AVColorRange>(ColorRangeId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxColorRange::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVColorRange const ColorRange = AvCodecCtx->color_range; + return static_cast<int32_t>(ColorRange); +} + +Expect<int32_t> AVCodecCtxFrameSize::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->frame_size; +} + +Expect<int64_t> AVCodecCtxBitRate::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->bit_rate; +} + +Expect<int32_t> AVCodecCtxSetBitRate::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int64_t BitRate) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->bit_rate = BitRate; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int64_t> AVCodecCtxRcMaxRate::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->rc_max_rate; +} + +Expect<int32_t> AVCodecCtxSetRcMaxRate::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int64_t RcMaxRate) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->rc_max_rate = RcMaxRate; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecCtxSetBitRateTolerance::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t BitRateTolerance) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->bit_rate_tolerance = BitRateTolerance; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecCtxSetCompressionLevel::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t CompressionLevel) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->compression_level = CompressionLevel; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxFrameRate::body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, + uint32_t NumPtr, uint32_t DenPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(Num, MemInst, int32_t, NumPtr, + "Failed to access Numerator Ptr for AVRational"sv); + MEM_PTR_CHECK(Den, MemInst, int32_t, DenPtr, + "Failed to access Denominator Ptr for AVRational"sv); + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + + AVRational const FrameRate = AvCodecCtx->framerate; + *Num = FrameRate.num; + *Den = FrameRate.den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetFrameRate::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t Num, + int32_t Den) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVRational const Rational = av_make_q(Num, Den); + AvCodecCtx->framerate = Rational; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetFlags::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t Flags) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->flags = Flags; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecCtxSetStrictStdCompliance::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t ComplianceId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->strict_std_compliance = ComplianceId; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetDebug::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t Debug) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->debug = Debug; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxCodec::body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, + uint32_t AvCodecPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(AVCodecId, MemInst, uint32_t, AvCodecPtr, + "Failed to access Ptr for AvCodecPtr"sv); + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + FFMPEG_PTR_FETCH(AvCodec, *AVCodecId, const AVCodec); + + AvCodec = AvCodecCtx->codec; + if (AvCodec == nullptr) + return -1; + + FFMPEG_PTR_STORE(const_cast<AVCodec *>(AvCodec), AVCodecId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxChannels::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->channels; +} + +Expect<int32_t> AVCodecCtxSetChannels::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Channels) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->channels = Channels; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetSkipLoopFilter::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t AVDiscardId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->skip_loop_filter = static_cast<AVDiscard>(AVDiscardId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetSkipFrame::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t AVDiscardId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->skip_frame = static_cast<AVDiscard>(AVDiscardId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetSkipIdct::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t AVDiscardId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->skip_idct = static_cast<AVDiscard>(AVDiscardId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecCtxSetErrorConcealment::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t ErrorConcealment) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->error_concealment = ErrorConcealment; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecCtxSetErrorRecognition::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t ErrRecognition) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->err_recognition = ErrRecognition; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxDelay::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->delay; +} + +Expect<int32_t> AVCodecCtxSetSkipTop::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Value) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->skip_top = Value; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetSkipBottom::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Value) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->skip_bottom = Value; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxRefs::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->refs; +} + +Expect<int32_t> AVCodecCtxSetSliceFlags::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Value) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->slice_flags = Value; + return static_cast<int32_t>(ErrNo::Success); +} +Expect<int32_t> AVCodecCtxSetSliceCount::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Value) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->slice_count = Value; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxSetFieldOrder::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Value) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->field_order = static_cast<AVFieldOrder>(Value); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxColorTrc::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return static_cast<int32_t>(AvCodecCtx->color_trc); +} + +Expect<int32_t> +AVCodecCtxChromaSampleLocation::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVChromaLocation const Chroma = AvCodecCtx->chroma_sample_location; + return FFmpegUtils::ChromaLocation::fromAVChromaLocation(Chroma); +} + +Expect<int32_t> AVCodecCtxFrameNumber::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->frame_number; +} + +Expect<int32_t> AVCodecCtxBlockAlign::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->block_align; +} + +Expect<int32_t> +AVCodecCtxSetRequestSampleFmt::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + uint32_t SampleFmtId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVSampleFormat const SampleFmt = + FFmpegUtils::SampleFmt::fromSampleID(SampleFmtId); + AvCodecCtx->request_sample_fmt = SampleFmt; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxAudioServiceType::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVAudioServiceType const AudioServiceType = AvCodecCtx->audio_service_type; + return static_cast<int32_t>(AudioServiceType); +} + +Expect<int32_t> AVCodecCtxHasBFrames::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->has_b_frames; +} + +Expect<int32_t> +AVCodecCtxSetRequestChannelLayout::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + uint64_t ChannelLayoutId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->request_channel_layout = + FFmpegUtils::ChannelLayout::fromChannelLayoutID(ChannelLayoutId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxActiveThreadType::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->active_thread_type; +} + +Expect<int32_t> AVCodecCtxSetThreadType::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t ThreadType) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->thread_type = ThreadType; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxThreadCount::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->thread_count; +} + +Expect<int32_t> AVCodecCtxSetThreadCount::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t ThreadCount) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->thread_count = ThreadCount; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecCtxColorPrimaries::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVColorPrimaries const ColorPrimaries = AvCodecCtx->color_primaries; + return FFmpegUtils::ColorPrimaries::fromAVColorPrimaries(ColorPrimaries); +} + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avcodec/avCodecContext.h b/plugins/wasmedge_ffmpeg/avcodec/avCodecContext.h new file mode 100644 index 000000000000..88d86558e496 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avCodecContext.h @@ -0,0 +1,686 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +class AVCodecCtxCodecID : public HostFunction<AVCodecCtxCodecID> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxCodecType : public HostFunction<AVCodecCtxCodecType> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetCodecType : public HostFunction<AVCodecCtxSetCodecType> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t CodecTypeId); +}; + +class AVCodecCtxSetTimebase : public HostFunction<AVCodecCtxSetTimebase> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Num, int32_t Den); +}; + +class AVCodecCtxTimeBase : public HostFunction<AVCodecCtxTimeBase> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t NumPtr, uint32_t DenPtr); +}; + +class AVCodecCtxWidth : public HostFunction<AVCodecCtxWidth> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetWidth : public HostFunction<AVCodecCtxSetWidth> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Width); +}; + +class AVCodecCtxHeight : public HostFunction<AVCodecCtxHeight> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetHeight : public HostFunction<AVCodecCtxSetHeight> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Height); +}; + +class AVCodecCtxSampleAspectRatio + : public HostFunction<AVCodecCtxSampleAspectRatio> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t NumPtr, uint32_t DenPtr); +}; + +class AVCodecCtxSetSampleAspectRatio + : public HostFunction<AVCodecCtxSetSampleAspectRatio> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Num, int32_t Den); +}; + +class AVCodecCtxChannelLayout : public HostFunction<AVCodecCtxChannelLayout> { +public: + using HostFunction::HostFunction; + Expect<uint64_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetChannelLayout + : public HostFunction<AVCodecCtxSetChannelLayout> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint64_t ChannelLayoutId); +}; + +class AVCodecCtxPixFormat : public HostFunction<AVCodecCtxPixFormat> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetPixFormat : public HostFunction<AVCodecCtxSetPixFormat> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t PixFmtId); +}; + +class AVCodecCtxSampleFormat : public HostFunction<AVCodecCtxSampleFormat> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetSampleFormat + : public HostFunction<AVCodecCtxSetSampleFormat> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t SampleFmtId); +}; + +class AVCodecCtxSampleRate : public HostFunction<AVCodecCtxSampleRate> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetSampleRate : public HostFunction<AVCodecCtxSetSampleRate> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t SampleRate); +}; + +class AVCodecCtxSetGopSize : public HostFunction<AVCodecCtxSetGopSize> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t GopSize); +}; + +class AVCodecCtxSetMaxBFrames : public HostFunction<AVCodecCtxSetMaxBFrames> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MaxBFrames); +}; + +class AVCodecCtxSetBQuantFactor + : public HostFunction<AVCodecCtxSetBQuantFactor> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float BQuantFactor); +}; + +class AVCodecCtxSetBQuantOffset + : public HostFunction<AVCodecCtxSetBQuantOffset> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float BQuantOffset); +}; + +class AVCodecCtxSetIQuantFactor + : public HostFunction<AVCodecCtxSetIQuantFactor> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float IQuantFactor); +}; + +class AVCodecCtxSetIQuantOffset + : public HostFunction<AVCodecCtxSetIQuantOffset> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float IQuantOffset); +}; + +class AVCodecCtxSetLumiMasking : public HostFunction<AVCodecCtxSetLumiMasking> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float LumiMasking); +}; + +class AVCodecCtxSetTemporalCplxMasking + : public HostFunction<AVCodecCtxSetTemporalCplxMasking> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float TemporalCplxMasking); +}; + +class AVCodecCtxSetSpatialCplxMasking + : public HostFunction<AVCodecCtxSetSpatialCplxMasking> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float SpatialCplxMasking); +}; + +class AVCodecCtxSetPMasking : public HostFunction<AVCodecCtxSetPMasking> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float PMasking); +}; + +class AVCodecCtxSetDarkMasking : public HostFunction<AVCodecCtxSetDarkMasking> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float DarkMasking); +}; + +class AVCodecCtxSetMeCmp : public HostFunction<AVCodecCtxSetMeCmp> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MeCmp); +}; + +class AVCodecCtxSetMeSubCmp : public HostFunction<AVCodecCtxSetMeSubCmp> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MeSubCmp); +}; + +class AVCodecCtxSetMbCmp : public HostFunction<AVCodecCtxSetMbCmp> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MbCmp); +}; + +class AVCodecCtxSetIldctCmp : public HostFunction<AVCodecCtxSetIldctCmp> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t IldctCmp); +}; + +class AVCodecCtxSetDiaSize : public HostFunction<AVCodecCtxSetDiaSize> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t DiaSize); +}; + +class AVCodecCtxSetLastPredictorsCount + : public HostFunction<AVCodecCtxSetLastPredictorsCount> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t LastPredictorCount); +}; + +class AVCodecCtxSetMePreCmp : public HostFunction<AVCodecCtxSetMePreCmp> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MePreCmp); +}; + +class AVCodecCtxSetPreDiaSize : public HostFunction<AVCodecCtxSetPreDiaSize> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t PreDiaSize); +}; + +class AVCodecCtxSetMeSubpelQuality + : public HostFunction<AVCodecCtxSetMeSubpelQuality> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MeSubpelQuality); +}; + +class AVCodecCtxSetMeRange : public HostFunction<AVCodecCtxSetMeRange> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MeRange); +}; + +class AVCodecCtxSetMbDecision : public HostFunction<AVCodecCtxSetMbDecision> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MbDecision); +}; + +class AVCodecCtxSetMbLMin : public HostFunction<AVCodecCtxSetMbLMin> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MbLMin); +}; + +class AVCodecCtxSetMbLMax : public HostFunction<AVCodecCtxSetMbLMax> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MbLMax); +}; + +class AVCodecCtxIntraDcPrecision + : public HostFunction<AVCodecCtxIntraDcPrecision> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetIntraDcPrecision + : public HostFunction<AVCodecCtxSetIntraDcPrecision> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t IntraDcPrecision); +}; + +class AVCodecCtxSetQMin : public HostFunction<AVCodecCtxSetQMin> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t QMin); +}; + +class AVCodecCtxSetQMax : public HostFunction<AVCodecCtxSetQMax> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t QMax); +}; + +class AVCodecCtxSetGlobalQuality + : public HostFunction<AVCodecCtxSetGlobalQuality> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t GlobalQuality); +}; + +class AVCodecCtxSetColorspace : public HostFunction<AVCodecCtxSetColorspace> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ColorspaceId); +}; + +class AVCodecCtxColorspace : public HostFunction<AVCodecCtxColorspace> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetColorRange : public HostFunction<AVCodecCtxSetColorRange> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ColorRange); +}; + +class AVCodecCtxColorRange : public HostFunction<AVCodecCtxColorRange> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxFrameSize : public HostFunction<AVCodecCtxFrameSize> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxBitRate : public HostFunction<AVCodecCtxBitRate> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetBitRate : public HostFunction<AVCodecCtxSetBitRate> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int64_t BitRate); +}; + +class AVCodecCtxRcMaxRate : public HostFunction<AVCodecCtxRcMaxRate> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetRcMaxRate : public HostFunction<AVCodecCtxSetRcMaxRate> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int64_t RcMaxRate); +}; + +class AVCodecCtxSetBitRateTolerance + : public HostFunction<AVCodecCtxSetBitRateTolerance> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t BitRateTolerance); +}; + +class AVCodecCtxSetCompressionLevel + : public HostFunction<AVCodecCtxSetCompressionLevel> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t CompressionLevel); +}; + +class AVCodecCtxFrameRate : public HostFunction<AVCodecCtxFrameRate> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t NumPtr, uint32_t DenPtr); +}; + +class AVCodecCtxSetFrameRate : public HostFunction<AVCodecCtxSetFrameRate> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Num, int32_t Den); +}; + +class AVCodecCtxSetFlags : public HostFunction<AVCodecCtxSetFlags> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Flags); +}; + +class AVCodecCtxSetStrictStdCompliance + : public HostFunction<AVCodecCtxSetStrictStdCompliance> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ComplianceId); +}; + +class AVCodecCtxSetDebug : public HostFunction<AVCodecCtxSetDebug> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Debug); +}; + +class AVCodecCtxCodec : public HostFunction<AVCodecCtxCodec> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t AvCodecPtr); +}; + +class AVCodecCtxChannels : public HostFunction<AVCodecCtxChannels> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetChannels : public HostFunction<AVCodecCtxSetChannels> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Channels); +}; + +class AVCodecCtxSetSkipLoopFilter + : public HostFunction<AVCodecCtxSetSkipLoopFilter> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t AVDicardId); +}; + +class AVCodecCtxSetSkipFrame : public HostFunction<AVCodecCtxSetSkipFrame> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t AVDiscardId); +}; + +class AVCodecCtxSetSkipIdct : public HostFunction<AVCodecCtxSetSkipIdct> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t AVDicardId); +}; + +class AVCodecCtxSetErrorConcealment + : public HostFunction<AVCodecCtxSetErrorConcealment> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ErrorConcealment); +}; + +class AVCodecCtxSetErrorRecognition + : public HostFunction<AVCodecCtxSetErrorRecognition> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ErrorRecognition); +}; + +class AVCodecCtxDelay : public HostFunction<AVCodecCtxDelay> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetSkipTop : public HostFunction<AVCodecCtxSetSkipTop> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Value); +}; + +class AVCodecCtxSetSkipBottom : public HostFunction<AVCodecCtxSetSkipBottom> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Value); +}; + +class AVCodecCtxRefs : public HostFunction<AVCodecCtxRefs> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetSliceFlags : public HostFunction<AVCodecCtxSetSliceFlags> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Flags); +}; + +class AVCodecCtxSetSliceCount : public HostFunction<AVCodecCtxSetSliceCount> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Value); +}; + +class AVCodecCtxSetFieldOrder : public HostFunction<AVCodecCtxSetFieldOrder> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Value); +}; + +class AVCodecCtxColorTrc : public HostFunction<AVCodecCtxColorTrc> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxChromaSampleLocation + : public HostFunction<AVCodecCtxChromaSampleLocation> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxFrameNumber : public HostFunction<AVCodecCtxFrameNumber> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxBlockAlign : public HostFunction<AVCodecCtxBlockAlign> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetRequestSampleFmt + : public HostFunction<AVCodecCtxSetRequestSampleFmt> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t SampleFmtId); +}; + +class AVCodecCtxAudioServiceType + : public HostFunction<AVCodecCtxAudioServiceType> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxHasBFrames : public HostFunction<AVCodecCtxHasBFrames> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetRequestChannelLayout + : public HostFunction<AVCodecCtxSetRequestChannelLayout> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint64_t ChannelLayoutId); +}; + +class AVCodecCtxActiveThreadType + : public HostFunction<AVCodecCtxActiveThreadType> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetThreadType : public HostFunction<AVCodecCtxSetThreadType> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ThreadType); +}; + +class AVCodecCtxThreadCount : public HostFunction<AVCodecCtxThreadCount> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetThreadCount : public HostFunction<AVCodecCtxSetThreadCount> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ThreadCount); +}; + +class AVCodecCtxColorPrimaries : public HostFunction<AVCodecCtxColorPrimaries> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.cpp b/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.cpp new file mode 100644 index 000000000000..3724aa6eb3bc --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.cpp @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avCodecParameters.h" + +extern "C" { +#include "libavcodec/avcodec.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +Expect<uint32_t> AVCodecParamCodecId::body(const Runtime::CallingFrame &, + uint32_t AvCodecParamId) { + FFMPEG_PTR_FETCH(AvCodecParams, AvCodecParamId, AVCodecParameters); + return FFmpegUtils::CodecID::fromAVCodecID(AvCodecParams->codec_id); +} + +Expect<int32_t> AVCodecParamCodecType::body(const Runtime::CallingFrame &, + uint32_t AvCodecParamId) { + FFMPEG_PTR_FETCH(AvCodecParams, AvCodecParamId, AVCodecParameters); + return FFmpegUtils::MediaType::fromMediaType(AvCodecParams->codec_type); +} + +Expect<int32_t> AVCodecParamSetCodecTag::body(const Runtime::CallingFrame &, + uint32_t AvCodecParamId, + uint32_t CodecTag) { + FFMPEG_PTR_FETCH(AvCodecParams, AvCodecParamId, AVCodecParameters); + AvCodecParams->codec_tag = CodecTag; + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.h b/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.h new file mode 100644 index 000000000000..fc6557d36fef --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +class AVCodecParamCodecId : public HostFunction<AVCodecParamCodecId> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecParamId); +}; + +class AVCodecParamCodecType : public HostFunction<AVCodecParamCodecType> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecParamId); +}; + +class AVCodecParamSetCodecTag : public HostFunction<AVCodecParamSetCodecTag> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecParamId, uint32_t CodecTag); +}; + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avcodec/avPacket.cpp b/plugins/wasmedge_ffmpeg/avcodec/avPacket.cpp new file mode 100644 index 000000000000..2510f9781d8e --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avPacket.cpp @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avPacket.h" + +extern "C" { +#include "libavcodec/packet.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +Expect<int32_t> AVPacketAlloc::body(const Runtime::CallingFrame &Frame, + uint32_t AvPacketPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(AvPacketId, MemInst, uint32_t, AvPacketPtr, + "Failed when accessing the return AVCodecContext Memory"sv); + + FFMPEG_PTR_FETCH(AvPacket, *AvPacketId, AVPacket); // Initialize the packet. + AvPacket = av_packet_alloc(); + FFMPEG_PTR_STORE(AvPacket, AvPacketId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVNewPacket::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int32_t Size) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return av_new_packet(AvPacket, Size); +} + +Expect<int32_t> AVPacketRef::body(const Runtime::CallingFrame &, + uint32_t DestPacketId, uint32_t SrcPacketId) { + FFMPEG_PTR_FETCH(DestAvPacket, DestPacketId, AVPacket); + FFMPEG_PTR_FETCH(SrcAvPacket, SrcPacketId, AVPacket); + + return av_packet_ref(DestAvPacket, SrcAvPacket); +} + +Expect<int32_t> AVPacketUnref::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); // Free packet. + av_packet_unref(AvPacket); + FFMPEG_PTR_DELETE(AvPacketId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVGrowPacket::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int32_t Size) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return av_grow_packet(AvPacket, Size); +} + +Expect<int32_t> AVShrinkPacket::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int32_t Size) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + av_shrink_packet(AvPacket, Size); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVPacketStreamIndex::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->stream_index; +} + +Expect<int32_t> AVPacketSetStreamIndex::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, + int32_t StreamIdx) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + AvPacket->stream_index = StreamIdx; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVPacketSize::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->size; +} + +Expect<int32_t> AVPacketFlags::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->flags; +} + +Expect<int32_t> AVPacketSetFlags::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int32_t Flags) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + AvPacket->flags = Flags; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int64_t> AVPacketPos::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->pos; +} + +Expect<int32_t> AVPacketSetPos::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int64_t Pos) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + AvPacket->pos = Pos; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int64_t> AVPacketDuration::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->duration; +} + +Expect<int32_t> AVPacketSetDuration::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, + int64_t Duration) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + AvPacket->duration = Duration; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int64_t> AVPacketDts::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->dts; +} + +Expect<int32_t> AVPacketSetDts::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int64_t Dts) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + AvPacket->dts = Dts; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int64_t> AVPacketPts::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->pts; +} + +Expect<int32_t> AVPacketSetPts::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int64_t Pts) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + AvPacket->pts = Pts; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVPacketIsDataNull::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + if (AvPacket->data == nullptr) + return 1; + return 0; +} + +Expect<int32_t> AVPacketData::body(const Runtime::CallingFrame &Frame, + uint32_t AvPacketId, uint32_t DataPtr, + uint32_t DataLen) { + MEMINST_CHECK(MemInst, Frame, 0) + MEM_SPAN_CHECK(Buffer, MemInst, uint8_t, DataPtr, DataLen, ""); + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + uint8_t *Data = AvPacket->data; + std::copy_n(Data, DataLen, Buffer.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avcodec/avPacket.h b/plugins/wasmedge_ffmpeg/avcodec/avPacket.h new file mode 100644 index 000000000000..403d55a24e68 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avPacket.h @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +class AVPacketAlloc : public HostFunction<AVPacketAlloc> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvPacketPtr); +}; + +class AVNewPacket : public HostFunction<AVNewPacket> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int32_t Size); +}; + +class AVPacketRef : public HostFunction<AVPacketRef> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t DestPacketId, uint32_t SrcPacketId); +}; + +class AVPacketUnref : public HostFunction<AVPacketUnref> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVGrowPacket : public HostFunction<AVGrowPacket> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int32_t Size); +}; + +class AVShrinkPacket : public HostFunction<AVShrinkPacket> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int32_t Size); +}; + +class AVPacketStreamIndex : public HostFunction<AVPacketStreamIndex> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketSetStreamIndex : public HostFunction<AVPacketSetStreamIndex> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int32_t StreamIdx); +}; + +class AVPacketSize : public HostFunction<AVPacketSize> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketFlags : public HostFunction<AVPacketFlags> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketSetFlags : public HostFunction<AVPacketSetFlags> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int32_t Flags); +}; + +class AVPacketPos : public HostFunction<AVPacketPos> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketSetPos : public HostFunction<AVPacketSetPos> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int64_t Pos); +}; + +class AVPacketDuration : public HostFunction<AVPacketDuration> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketSetDuration : public HostFunction<AVPacketSetDuration> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int64_t Duration); +}; + +class AVPacketDts : public HostFunction<AVPacketDts> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketSetDts : public HostFunction<AVPacketSetDts> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int64_t Dts); +}; + +class AVPacketPts : public HostFunction<AVPacketPts> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketSetPts : public HostFunction<AVPacketSetPts> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int64_t Pts); +}; + +class AVPacketIsDataNull : public HostFunction<AVPacketIsDataNull> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketData : public HostFunction<AVPacketData> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + uint32_t DataPtr, uint32_t DataLen); +}; + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avcodec/avcodec_func.cpp b/plugins/wasmedge_ffmpeg/avcodec/avcodec_func.cpp new file mode 100644 index 000000000000..5158f4b31136 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avcodec_func.cpp @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avcodec_func.h" + +extern "C" { +#include "libavcodec/avcodec.h" +#include "libavformat/avformat.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +Expect<int32_t> AVCodecAllocContext3::body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecId, + uint32_t AvCodecCtxPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(AvCodecCtxId, MemInst, uint32_t, AvCodecCtxPtr, + "Failed when accessing the return AVCodecContext Memory"sv); + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, AVCodec); + + AVCodecContext *AvCodecCtx = avcodec_alloc_context3(AvCodec); + FFMPEG_PTR_STORE(AvCodecCtx, AvCodecCtxId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecParametersFromContext::body(const Runtime::CallingFrame &, + uint32_t AvCodecParamId, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecParam, AvCodecParamId, AVCodecParameters); + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return avcodec_parameters_from_context(AvCodecParam, AvCodecCtx); +} + +Expect<int32_t> AVCodecParametersFree::body(const Runtime::CallingFrame &, + uint32_t AvCodecParamId) { + FFMPEG_PTR_FETCH(AvCodecParam, AvCodecParamId, AVCodecParameters); + + avcodec_parameters_free(&AvCodecParam); + FFMPEG_PTR_DELETE(AvCodecParamId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecFreeContext::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + + avcodec_free_context(&AvCodecCtx); + FFMPEG_PTR_DELETE(AvCodecCtxId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecParametersAlloc::body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecParamPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(AvCodecParamId, MemInst, uint32_t, AvCodecParamPtr, + "Failed when accessing the return AVCodecParameters Memory"sv); + + FFMPEG_PTR_FETCH(AvCodecParam, *AvCodecParamId, AVCodecParameters); + AvCodecParam = avcodec_parameters_alloc(); + FFMPEG_PTR_STORE(AvCodecParam, AvCodecParamId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecGetType::body(const Runtime::CallingFrame &, + uint32_t AvCodecIdIndex) { + AVCodecID const AvCodecId = + FFmpegUtils::CodecID::intoAVCodecID(AvCodecIdIndex); + AVMediaType const MediaType = avcodec_get_type(AvCodecId); + return FFmpegUtils::MediaType::fromMediaType(MediaType); +} + +Expect<int32_t> AVCodecOpen2::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, uint32_t AvCodecId, + uint32_t AvDictionaryId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + FFMPEG_PTR_FETCH(AvDictionary, AvDictionaryId, AVDictionary *); + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, AVCodec); + return avcodec_open2(AvCodecCtx, AvCodec, AvDictionary); +} + +Expect<int32_t> AVCodecFindDecoder::body(const Runtime::CallingFrame &Frame, + uint32_t ID, uint32_t AvCodecPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(AVCodecId, MemInst, uint32_t, AvCodecPtr, + "Failed when accessing the return AVCodec Memory"sv); + + AVCodecID const Id = FFmpegUtils::CodecID::intoAVCodecID(ID); + + const AVCodec *AvCodec = avcodec_find_decoder(Id); + + // Setting AvCodec value as NULL. + if (AvCodec == nullptr) { + *AVCodecId = 0; + return static_cast<int32_t>(ErrNo::Success); + } + + FFMPEG_PTR_STORE(const_cast<AVCodec *>(AvCodec), AVCodecId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecIsEncoder::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return av_codec_is_encoder(AvCodec); +} + +Expect<int32_t> AVCodecIsDecoder::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return av_codec_is_decoder(AvCodec); +} + +Expect<int32_t> AVCodecClose::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + int Res = avcodec_close(AvCodecCtx); + FFMPEG_PTR_DELETE(AvCodecCtxId); + return Res; +} + +Expect<int32_t> AVCodecParametersToContext::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + uint32_t AvCodecParamId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + FFMPEG_PTR_FETCH(AvCodecParam, AvCodecParamId, AVCodecParameters); + + return avcodec_parameters_to_context(AvCodecCtx, AvCodecParam); +} + +Expect<int32_t> AVCodecReceiveFrame::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return avcodec_receive_frame(AvCodecCtx, AvFrame); +} + +Expect<int32_t> AVCodecSendPacket::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + uint32_t PacketId) { + FFMPEG_PTR_FETCH(AVCodecCtx, AvCodecCtxId, AVCodecContext); + FFMPEG_PTR_FETCH(AvPacket, PacketId, + AVPacket); // Can send Null AVPacket, to close the stream. + return avcodec_send_packet(AVCodecCtx, AvPacket); +} + +Expect<int32_t> AVCodecFindEncoder::body(const Runtime::CallingFrame &Frame, + uint32_t ID, uint32_t AVCodecPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(AVCodecId, MemInst, uint32_t, AVCodecPtr, + "Failed when accessing the return AVCodec Memory"sv); + + AVCodecID const Id = FFmpegUtils::CodecID::intoAVCodecID(ID); + + const AVCodec *AvCodec = avcodec_find_encoder(Id); + + // Setting AvCodec value as NULL. + if (AvCodec == nullptr) { + *AVCodecId = 0; + return static_cast<int32_t>(ErrNo::Success); + } + + FFMPEG_PTR_STORE(const_cast<AVCodec *>(AvCodec), AVCodecId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecReceivePacket::body(const Runtime::CallingFrame &, + uint32_t AVCodecCtxId, + uint32_t PacketId) { + FFMPEG_PTR_FETCH(AVCodecCtx, AVCodecCtxId, AVCodecContext); + FFMPEG_PTR_FETCH(AvPacket, PacketId, AVPacket); + return avcodec_receive_packet(AVCodecCtx, AvPacket); +} + +Expect<int32_t> AVCodecSendFrame::body(const Runtime::CallingFrame &, + uint32_t AVCodecCtxId, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AVCodecCtx, AVCodecCtxId, AVCodecContext); + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return avcodec_send_frame(AVCodecCtx, AvFrame); +} + +Expect<int32_t> +AVCodecFindDecoderByName::body(const Runtime::CallingFrame &Frame, + uint32_t AVCodecPtr, uint32_t NamePtr, + uint32_t NameLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(AVCodecId, MemInst, uint32_t, AVCodecPtr, + "Failed when accessing the return AVCodec Memory"sv); + MEM_PTR_CHECK(NameId, MemInst, char, NamePtr, + "Failed when accessing the return URL memory"sv); + + std::string Name; + std::copy_n(NameId, NameLen, std::back_inserter(Name)); + + AVCodec const *AvCodec = avcodec_find_decoder_by_name(Name.c_str()); + + if (AvCodec == nullptr) { + *AVCodecId = 0; + return static_cast<int32_t>(ErrNo::Success); + } + + FFMPEG_PTR_STORE(const_cast<AVCodec *>(AvCodec), AVCodecId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecFindEncoderByName::body(const Runtime::CallingFrame &Frame, + uint32_t AVCodecPtr, uint32_t NamePtr, + uint32_t NameLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(AVCodecId, MemInst, uint32_t, AVCodecPtr, + "Failed when accessing the return AVCodec Memory"sv); + MEM_PTR_CHECK(NameId, MemInst, char, NamePtr, + "Failed when accessing the return URL memory"sv); + + std::string Name; + std::copy_n(NameId, NameLen, std::back_inserter(Name)); + + AVCodec const *AvCodec = avcodec_find_encoder_by_name(Name.c_str()); + + if (AvCodec == nullptr) { + *AVCodecId = 0; + return static_cast<int32_t>(ErrNo::Success); + } + + FFMPEG_PTR_STORE(const_cast<AVCodec *>(AvCodec), AVCodecId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVPacketRescaleTs::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int32_t SrcNum, + int32_t SrcDen, int32_t DestNum, + int32_t DestDen) { + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + AVRational const Src = av_make_q(SrcNum, SrcDen); + AVRational const Dest = av_make_q(DestNum, DestDen); + + av_packet_rescale_ts(AvPacket, Src, Dest); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVPacketMakeWritable::body(const Runtime::CallingFrame &, + uint32_t AVPacketId) { + FFMPEG_PTR_FETCH(AvPacket, AVPacketId, AVPacket); + return av_packet_make_writable(AvPacket); +} + +Expect<int32_t> AVCodecParametersCopy::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t AVCodecParamId, + uint32_t StreamIdx) { + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + FFMPEG_PTR_FETCH(AvCodecParam, AVCodecParamId, AVCodecParameters); + + AVStream **AvStream = AvFormatCtx->streams; + + // No check here (Check) + // Raw Pointer Iteration. + for (unsigned int I = 1; I <= StreamIdx; I++) + AvStream++; + + return avcodec_parameters_copy((*AvStream)->codecpar, AvCodecParam); +} + +Expect<uint32_t> AVCodecVersion::body(const Runtime::CallingFrame &) { + return avcodec_version(); +} + +Expect<int32_t> AVCodecFlushBuffers::body(const Runtime::CallingFrame &, + uint32_t AVCodecCtxId) { + FFMPEG_PTR_FETCH(AvCodecCtx, AVCodecCtxId, AVCodecContext); + avcodec_flush_buffers(AvCodecCtx); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVCodecConfigurationLength::body(const Runtime::CallingFrame &) { + const char *Config = avcodec_configuration(); + return strlen(Config); +} + +Expect<int32_t> AVCodecConfiguration::body(const Runtime::CallingFrame &Frame, + uint32_t ConfigPtr, + uint32_t ConfigLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(ConfigBuf, MemInst, char, ConfigPtr, ConfigLen, ""); + + const char *Config = avcodec_configuration(); + std::copy_n(Config, ConfigLen, ConfigBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCodecLicenseLength::body(const Runtime::CallingFrame &) { + const char *License = avcodec_license(); + return strlen(License); +} + +Expect<int32_t> AVCodecLicense::body(const Runtime::CallingFrame &Frame, + uint32_t LicensePtr, uint32_t LicenseLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(LicenseBuf, MemInst, char, LicensePtr, LicenseLen, ""); + + const char *License = avcodec_license(); + std::copy_n(License, LicenseLen, LicenseBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avcodec/avcodec_func.h b/plugins/wasmedge_ffmpeg/avcodec/avcodec_func.h new file mode 100644 index 000000000000..c560e0659f83 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avcodec_func.h @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +class AVCodecAllocContext3 : public HostFunction<AVCodecAllocContext3> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t AvCodecCtxPtr); +}; + +class AVCodecParametersFromContext + : public HostFunction<AVCodecParametersFromContext> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecParamId, uint32_t AvCodecCtxId); +}; + +class AVCodecParametersFree : public HostFunction<AVCodecParametersFree> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecParamId); +}; + +class AVCodecFreeContext : public HostFunction<AVCodecFreeContext> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecParametersAlloc : public HostFunction<AVCodecParametersAlloc> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecParamPtr); +}; + +class AVCodecGetType : public HostFunction<AVCodecGetType> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecOpen2 : public HostFunction<AVCodecOpen2> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t AvCodecId, + uint32_t AvDictionaryId); +}; + +class AVCodecFindDecoder : public HostFunction<AVCodecFindDecoder> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t ID, + uint32_t AvCodecId); +}; + +class AVCodecIsEncoder : public HostFunction<AVCodecIsEncoder> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecIsDecoder : public HostFunction<AVCodecIsDecoder> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecClose : public HostFunction<AVCodecClose> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecParametersToContext + : public HostFunction<AVCodecParametersToContext> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t AvCodecParamId); +}; + +class AVCodecReceiveFrame : public HostFunction<AVCodecReceiveFrame> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t FrameId); +}; + +class AVCodecSendPacket : public HostFunction<AVCodecSendPacket> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t PacketId); +}; + +class AVCodecFindEncoder : public HostFunction<AVCodecFindEncoder> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t ID, + uint32_t AVCodecPtr); +}; + +class AVCodecReceivePacket : public HostFunction<AVCodecReceivePacket> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVCodecCtxId, uint32_t PacketId); +}; + +class AVCodecSendFrame : public HostFunction<AVCodecSendFrame> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVCodecCtxId, uint32_t FrameId); +}; + +class AVCodecFindDecoderByName : public HostFunction<AVCodecFindDecoderByName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AVCodecPtr, + uint32_t NamePtr, uint32_t NameLen); +}; + +class AVCodecFindEncoderByName : public HostFunction<AVCodecFindEncoderByName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AVCodecPtr, + uint32_t NamePtr, uint32_t NameLen); +}; + +class AVPacketRescaleTs : public HostFunction<AVPacketRescaleTs> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AVPacketId, + int32_t SrcNum, int32_t SrcDen, int32_t DestNum, + int32_t DestDen); +}; + +class AVPacketMakeWritable : public HostFunction<AVPacketMakeWritable> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t AVPacketId); +}; + +class AVCodecParametersCopy : public HostFunction<AVCodecParametersCopy> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVFormatCtxId, uint32_t AVCodecParamId, + uint32_t StreamIdx); +}; + +class AVCodecVersion : public HostFunction<AVCodecVersion> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVCodecFlushBuffers : public HostFunction<AVCodecFlushBuffers> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVCodecCtxId); +}; + +class AVCodecConfigurationLength + : public HostFunction<AVCodecConfigurationLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVCodecConfiguration : public HostFunction<AVCodecConfiguration> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class AVCodecLicenseLength : public HostFunction<AVCodecLicenseLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVCodecLicense : public HostFunction<AVCodecLicense> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t LicensePtr, + uint32_t LicenseLen); +}; + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avcodec/module.cpp b/plugins/wasmedge_ffmpeg/avcodec/module.cpp new file mode 100644 index 000000000000..5f082ba81d23 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/module.cpp @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "module.h" +#include "avCodec.h" +#include "avCodecContext.h" +#include "avCodecParameters.h" +#include "avPacket.h" +#include "avcodec_func.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +WasmEdgeFFmpegAVCodecModule::WasmEdgeFFmpegAVCodecModule( + std::shared_ptr<WasmEdgeFFmpegEnv> Env) + : ModuleInstance("wasmedge_ffmpeg_avcodec") { + // avcodec_func.h + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_alloc_context3", + std::make_unique<AVCodecAllocContext3>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_parameters_from_context", + std::make_unique<AVCodecParametersFromContext>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_parameters_free", + std::make_unique<AVCodecParametersFree>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_free_context", + std::make_unique<AVCodecFreeContext>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_parameters_alloc", + std::make_unique<AVCodecParametersAlloc>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_get_type", + std::make_unique<AVCodecGetType>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_open2", + std::make_unique<AVCodecOpen2>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_find_decoder", + std::make_unique<AVCodecFindDecoder>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_codec_is_encoder", + std::make_unique<AVCodecIsEncoder>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_codec_is_decoder", + std::make_unique<AVCodecIsDecoder>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_close", + std::make_unique<AVCodecClose>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_parameters_to_context", + std::make_unique<AVCodecParametersToContext>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_receive_frame", + std::make_unique<AVCodecReceiveFrame>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_send_packet", + std::make_unique<AVCodecSendPacket>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_find_encoder", + std::make_unique<AVCodecFindEncoder>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_receive_packet", + std::make_unique<AVCodecReceivePacket>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_send_frame", + std::make_unique<AVCodecSendFrame>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_find_decoder_by_name", + std::make_unique<AVCodecFindDecoderByName>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_find_encoder_by_name", + std::make_unique<AVCodecFindEncoderByName>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_rescale_ts", + std::make_unique<AVPacketRescaleTs>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_make_writable", + std::make_unique<AVPacketMakeWritable>(Env)); + addHostFunc( + "wasmedge_ffmpeg_avcodec_avcodec_parameters_copy", + std::make_unique<AVCodecParametersCopy>(Env)); // TODO: Write Test. + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_version", + std::make_unique<AVCodecVersion>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_flush_buffers", + std::make_unique<AVCodecFlushBuffers>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_configuration_length", + std::make_unique<AVCodecConfigurationLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_configuration", + std::make_unique<AVCodecConfiguration>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_license_length", + std::make_unique<AVCodecLicenseLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_license", + std::make_unique<AVCodecLicense>(Env)); + + // avCodecContext Struct fields access + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_codec_id", + std::make_unique<AVCodecCtxCodecID>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_codec_type", + std::make_unique<AVCodecCtxCodecType>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_codec_type", + std::make_unique<AVCodecCtxSetCodecType>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_time_base", + std::make_unique<AVCodecCtxSetTimebase>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_time_base", + std::make_unique<AVCodecCtxTimeBase>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_width", + std::make_unique<AVCodecCtxWidth>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_width", + std::make_unique<AVCodecCtxSetWidth>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_height", + std::make_unique<AVCodecCtxHeight>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_height", + std::make_unique<AVCodecCtxSetHeight>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_sample_aspect_ratio", + std::make_unique<AVCodecCtxSampleAspectRatio>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_sample_aspect_ratio", + std::make_unique<AVCodecCtxSetSampleAspectRatio>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_channel_layout", + std::make_unique<AVCodecCtxChannelLayout>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_channel_layout", + std::make_unique<AVCodecCtxSetChannelLayout>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_pix_fmt", + std::make_unique<AVCodecCtxPixFormat>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_pix_fmt", + std::make_unique<AVCodecCtxSetPixFormat>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_sample_format", + std::make_unique<AVCodecCtxSampleFormat>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_sample_format", + std::make_unique<AVCodecCtxSetSampleFormat>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_sample_rate", + std::make_unique<AVCodecCtxSampleRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_sample_rate", + std::make_unique<AVCodecCtxSetSampleRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_gop_size", + std::make_unique<AVCodecCtxSetGopSize>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_max_b_frames", + std::make_unique<AVCodecCtxSetMaxBFrames>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_b_quant_factor", + std::make_unique<AVCodecCtxSetBQuantFactor>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_b_quant_offset", + std::make_unique<AVCodecCtxSetBQuantOffset>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_i_quant_factor", + std::make_unique<AVCodecCtxSetIQuantFactor>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_i_quant_offset", + std::make_unique<AVCodecCtxSetIQuantOffset>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_lumi_masking", + std::make_unique<AVCodecCtxSetLumiMasking>(Env)); + addHostFunc( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_temporal_cplx_masking", + std::make_unique<AVCodecCtxSetTemporalCplxMasking>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_spatial_cplx_masking", + std::make_unique<AVCodecCtxSetSpatialCplxMasking>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_p_masking", + std::make_unique<AVCodecCtxSetPMasking>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_dark_masking", + std::make_unique<AVCodecCtxSetDarkMasking>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_cmp", + std::make_unique<AVCodecCtxSetMeCmp>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_sub_cmp", + std::make_unique<AVCodecCtxSetMeSubCmp>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_mb_cmp", + std::make_unique<AVCodecCtxSetMbCmp>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_ildct_cmp", + std::make_unique<AVCodecCtxSetIldctCmp>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_dia_size", + std::make_unique<AVCodecCtxSetDiaSize>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_last_predictor_count", + std::make_unique<AVCodecCtxSetLastPredictorsCount>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_pre_cmp", + std::make_unique<AVCodecCtxSetMePreCmp>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_pre_dia_size", + std::make_unique<AVCodecCtxSetPreDiaSize>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_subpel_quality", + std::make_unique<AVCodecCtxSetMeSubpelQuality>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_range", + std::make_unique<AVCodecCtxSetMeRange>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_mb_decision", + std::make_unique<AVCodecCtxSetMbDecision>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_mb_lmin", + std::make_unique<AVCodecCtxSetMbLMin>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_mb_lmax", + std::make_unique<AVCodecCtxSetMbLMax>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_intra_dc_precision", + std::make_unique<AVCodecCtxIntraDcPrecision>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_intra_dc_precision", + std::make_unique<AVCodecCtxSetIntraDcPrecision>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_qmin", + std::make_unique<AVCodecCtxSetQMin>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_qmax", + std::make_unique<AVCodecCtxSetQMax>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_global_quality", + std::make_unique<AVCodecCtxSetGlobalQuality>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_colorspace", + std::make_unique<AVCodecCtxSetColorspace>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_colorspace", + std::make_unique<AVCodecCtxColorspace>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_color_range", + std::make_unique<AVCodecCtxSetColorRange>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_color_range", + std::make_unique<AVCodecCtxColorRange>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_frame_size", + std::make_unique<AVCodecCtxFrameSize>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_bit_rate", + std::make_unique<AVCodecCtxBitRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_bit_rate", + std::make_unique<AVCodecCtxSetBitRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_rc_max_rate", + std::make_unique<AVCodecCtxRcMaxRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_rc_max_rate", + std::make_unique<AVCodecCtxSetRcMaxRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_bit_rate_tolerance", + std::make_unique<AVCodecCtxSetBitRateTolerance>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_compression_level", + std::make_unique<AVCodecCtxSetCompressionLevel>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_framerate", + std::make_unique<AVCodecCtxFrameRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_framerate", + std::make_unique<AVCodecCtxSetFrameRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_flags", + std::make_unique<AVCodecCtxSetFlags>(Env)); + addHostFunc( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_strict_std_compliance", + std::make_unique<AVCodecCtxSetStrictStdCompliance>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_debug", + std::make_unique<AVCodecCtxSetDebug>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_codec", + std::make_unique<AVCodecCtxCodec>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_channels", + std::make_unique<AVCodecCtxChannels>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_channels", + std::make_unique<AVCodecCtxSetChannels>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_loop_filter", + std::make_unique<AVCodecCtxSetSkipLoopFilter>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_frame", + std::make_unique<AVCodecCtxSetSkipFrame>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_idct", + std::make_unique<AVCodecCtxSetSkipIdct>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_error_concealment", + std::make_unique<AVCodecCtxSetErrorConcealment>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_err_recognition", + std::make_unique<AVCodecCtxSetErrorRecognition>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_delay", + std::make_unique<AVCodecCtxDelay>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_top", + std::make_unique<AVCodecCtxSetSkipTop>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_bottom", + std::make_unique<AVCodecCtxSetSkipBottom>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_refs", + std::make_unique<AVCodecCtxRefs>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_slice_flags", + std::make_unique<AVCodecCtxSetSliceFlags>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_slice_count", + std::make_unique<AVCodecCtxSetSliceCount>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_field_order", + std::make_unique<AVCodecCtxSetFieldOrder>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_color_trc", + std::make_unique<AVCodecCtxColorTrc>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_chroma_sample_location", + std::make_unique<AVCodecCtxChromaSampleLocation>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_frame_number", + std::make_unique<AVCodecCtxFrameNumber>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_block_align", + std::make_unique<AVCodecCtxBlockAlign>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_request_sample_fmt", + std::make_unique<AVCodecCtxSetRequestSampleFmt>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_audio_service_type", + std::make_unique<AVCodecCtxAudioServiceType>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_has_b_frames", + std::make_unique<AVCodecCtxHasBFrames>(Env)); + addHostFunc( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_request_channel_layout", + std::make_unique<AVCodecCtxSetRequestChannelLayout>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_active_thread_type", + std::make_unique<AVCodecCtxActiveThreadType>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_thread_type", + std::make_unique<AVCodecCtxSetThreadType>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_thread_count", + std::make_unique<AVCodecCtxThreadCount>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_thread_count", + std::make_unique<AVCodecCtxSetThreadCount>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_color_primaries", + std::make_unique<AVCodecCtxColorPrimaries>(Env)); + + // avCodec Struct fields access + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_id", + std::make_unique<AVCodecID>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_type", + std::make_unique<AVCodecType>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_max_lowres", + std::make_unique<AVCodecMaxLowres>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_capabilities", + std::make_unique<AVCodecCapabilities>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_get_name_len", + std::make_unique<AVCodecGetNameLen>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_get_name", + std::make_unique<AVCodecGetName>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_get_long_name_len", + std::make_unique<AVCodecGetLongNameLen>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_get_long_name", + std::make_unique<AVCodecGetLongName>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_profiles", + std::make_unique<AVCodecProfiles>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_pix_fmts_is_null", + std::make_unique<AVCodecPixFmtsIsNull>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_pix_fmts_iter", + std::make_unique<AVCodecPixFmtsIter>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_supported_framerate_is_null", + std::make_unique<AVCodecSupportedFrameratesIsNull>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_supported_framerate_iter", + std::make_unique<AVCodecSupportedFrameratesIter>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_supported_samplerates_is_null", + std::make_unique<AVCodecSupportedSampleRatesIsNull>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_supported_samplerates_iter", + std::make_unique<AVCodecSupportedSampleRatesIter>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_channel_layouts_is_null", + std::make_unique<AVCodecChannelLayoutIsNull>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_channel_layouts_iter", + std::make_unique<AVCodecChannelLayoutIter>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_sample_fmts_is_null", + std::make_unique<AVCodecSampleFmtsIsNull>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_sample_fmts_iter", + std::make_unique<AVCodecSampleFmtsIter>(Env)); + + // AVCodecParam Struct fields access. + addHostFunc("wasmedge_ffmpeg_avcodec_avcodecparam_codec_id", + std::make_unique<AVCodecParamCodecId>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodecparam_codec_type", + std::make_unique<AVCodecParamCodecType>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodecparam_set_codec_tag", + std::make_unique<AVCodecParamSetCodecTag>(Env)); + + // AVPacket functions. + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_alloc", + std::make_unique<AVPacketAlloc>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_new_packet", + std::make_unique<AVNewPacket>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_ref", + std::make_unique<AVPacketRef>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_unref", + std::make_unique<AVPacketUnref>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_grow_packet", + std::make_unique<AVGrowPacket>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_shrink_packet", + std::make_unique<AVShrinkPacket>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_stream_index", + std::make_unique<AVPacketStreamIndex>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_set_stream_index", + std::make_unique<AVPacketSetStreamIndex>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_size", + std::make_unique<AVPacketSize>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_flags", + std::make_unique<AVPacketFlags>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_set_flags", + std::make_unique<AVPacketSetFlags>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_pos", + std::make_unique<AVPacketPos>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_set_pos", + std::make_unique<AVPacketSetPos>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_duration", + std::make_unique<AVPacketDuration>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_set_duration", + std::make_unique<AVPacketSetDuration>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_dts", + std::make_unique<AVPacketDts>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_set_dts", + std::make_unique<AVPacketSetDts>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_pts", + std::make_unique<AVPacketPts>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_set_pts", + std::make_unique<AVPacketSetPts>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_is_data_null", + std::make_unique<AVPacketIsDataNull>(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_data", + std::make_unique<AVPacketData>(Env)); +} + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avcodec/module.h b/plugins/wasmedge_ffmpeg/avcodec/module.h new file mode 100644 index 000000000000..b7e639472852 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/module.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_env.h" + +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +class WasmEdgeFFmpegAVCodecModule : public Runtime::Instance::ModuleInstance { +public: + WasmEdgeFFmpegAVCodecModule(std::shared_ptr<WasmEdgeFFmpegEnv> Env); +}; + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avdevice/avDevice_func.cpp b/plugins/wasmedge_ffmpeg/avdevice/avDevice_func.cpp new file mode 100644 index 000000000000..0e19d8aa8f8a --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avdevice/avDevice_func.cpp @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avDevice_func.h" + +extern "C" { +#include "libavdevice/avdevice.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVDevice { + +Expect<void> AVDeviceRegisterAll::body(const Runtime::CallingFrame &) { + avdevice_register_all(); + return {}; +} + +Expect<uint32_t> AVDeviceVersion::body(const Runtime::CallingFrame &) { + return avdevice_version(); +} + +Expect<int32_t> AVDeviceListDevices::body(const Runtime::CallingFrame &Frame, + uint32_t AVFormatCtxId, + uint32_t AVDeviceInfoListPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(AVDeviceInfoListId, MemInst, uint32_t, AVDeviceInfoListPtr, "") + + FFMPEG_PTR_FETCH(AvFormatCtx, AVFormatCtxId, AVFormatContext); + + AVDeviceInfoList **AvDeviceInfoList = + static_cast<AVDeviceInfoList **>(av_malloc(sizeof(AVDeviceInfoList *))); + + int Res = avdevice_list_devices(AvFormatCtx, AvDeviceInfoList); + FFMPEG_PTR_STORE(AvDeviceInfoList, AVDeviceInfoListId); + return Res; +} + +Expect<int32_t> AVInputAudioDeviceNext::body(const Runtime::CallingFrame &) { + spdlog::error("[WasmEdge-FFmpeg] AVInputAudioDeviceNext unimplemented"sv); + // av_input_audio_device_next(); + return static_cast<int32_t>(ErrNo::UnImplemented); +} + +Expect<int32_t> AVInputVideoDeviceNext::body(const Runtime::CallingFrame &) { + spdlog::error("[WasmEdge-FFmpeg] AVInputVideoDeviceNext unimplemented"sv); + // av_input_video_device_next(); + return static_cast<int32_t>(ErrNo::UnImplemented); +} + +Expect<int32_t> AVOutputAudioDeviceNext::body(const Runtime::CallingFrame &) { + spdlog::error("[WasmEdge-FFmpeg] AVOutputAudioDeviceNext unimplemented"sv); + // av_output_audio_device_next(); + return static_cast<int32_t>(ErrNo::UnImplemented); +} + +Expect<int32_t> AVOutputVideoDeviceNext::body(const Runtime::CallingFrame &) { + spdlog::error("[WasmEdge-FFmpeg] AVOutputVideoDeviceNext unimplemented"sv); + // av_output_video_device_next(); + return static_cast<int32_t>(ErrNo::UnImplemented); +} + +Expect<int32_t> AVDeviceFreeListDevices::body(const Runtime::CallingFrame &, + uint32_t AVDeviceInfoListId) { + FFMPEG_PTR_FETCH(AvDeviceInfoList, AVDeviceInfoListId, AVDeviceInfoList *); + avdevice_free_list_devices(AvDeviceInfoList); + FFMPEG_PTR_DELETE(AVDeviceInfoListId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVDeviceNbDevices::body(const Runtime::CallingFrame &, + uint32_t AVDeviceInfoListId) { + FFMPEG_PTR_FETCH(AvDeviceInfoList, AVDeviceInfoListId, AVDeviceInfoList *); + return (*AvDeviceInfoList)->nb_devices; +} + +Expect<int32_t> AVDeviceDefaultDevice::body(const Runtime::CallingFrame &, + uint32_t AVDeviceInfoListId) { + FFMPEG_PTR_FETCH(AvDeviceInfoList, AVDeviceInfoListId, AVDeviceInfoList *); + return (*AvDeviceInfoList)->default_device; +} + +Expect<int32_t> +AVDeviceConfigurationLength::body(const Runtime::CallingFrame &) { + const char *Config = avdevice_configuration(); + return strlen(Config); +} + +Expect<int32_t> AVDeviceConfiguration::body(const Runtime::CallingFrame &Frame, + uint32_t ConfigPtr, + uint32_t ConfigLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(ConfigBuf, MemInst, char, ConfigPtr, ConfigLen, ""); + + const char *Config = avdevice_configuration(); + std::copy_n(Config, ConfigLen, ConfigBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVDeviceLicenseLength::body(const Runtime::CallingFrame &) { + const char *License = avdevice_license(); + return strlen(License); +} + +Expect<int32_t> AVDeviceLicense::body(const Runtime::CallingFrame &Frame, + uint32_t LicensePtr, + uint32_t LicenseLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(LicenseBuf, MemInst, char, LicensePtr, LicenseLen, ""); + + const char *License = avdevice_license(); + std::copy_n(License, LicenseLen, LicenseBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVDevice +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avdevice/avDevice_func.h b/plugins/wasmedge_ffmpeg/avdevice/avDevice_func.h new file mode 100644 index 000000000000..6b5832f52827 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avdevice/avDevice_func.h @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVDevice { + +class AVDeviceRegisterAll : public HostFunction<AVDeviceRegisterAll> { +public: + using HostFunction::HostFunction; + Expect<void> body(const Runtime::CallingFrame &Frame); +}; + +class AVDeviceVersion : public HostFunction<AVDeviceVersion> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVDeviceListDevices : public HostFunction<AVDeviceListDevices> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVFormatCtxId, uint32_t AVDeviceInfoListPtr); +}; + +class AVInputAudioDeviceNext : public HostFunction<AVInputAudioDeviceNext> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &); +}; + +class AVInputVideoDeviceNext : public HostFunction<AVInputVideoDeviceNext> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &); +}; + +class AVOutputAudioDeviceNext : public HostFunction<AVOutputAudioDeviceNext> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &); +}; + +class AVOutputVideoDeviceNext : public HostFunction<AVOutputVideoDeviceNext> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &); +}; + +class AVDeviceFreeListDevices : public HostFunction<AVDeviceFreeListDevices> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVDeviceInfoListId); +}; + +class AVDeviceNbDevices : public HostFunction<AVDeviceNbDevices> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVDeviceInfoListId); +}; + +class AVDeviceDefaultDevice : public HostFunction<AVDeviceDefaultDevice> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVDeviceInfoListId); +}; + +class AVDeviceConfigurationLength + : public HostFunction<AVDeviceConfigurationLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVDeviceConfiguration : public HostFunction<AVDeviceConfiguration> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class AVDeviceLicenseLength : public HostFunction<AVDeviceLicenseLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVDeviceLicense : public HostFunction<AVDeviceLicense> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t LicensePtr, + uint32_t LicenseLen); +}; + +} // namespace AVDevice +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avdevice/module.cpp b/plugins/wasmedge_ffmpeg/avdevice/module.cpp new file mode 100644 index 000000000000..0e58d7886efe --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avdevice/module.cpp @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "module.h" +#include "avDevice_func.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVDevice { + +WasmEdgeFFmpegAVDeviceModule::WasmEdgeFFmpegAVDeviceModule( + std::shared_ptr<WasmEdgeFFmpegEnv> Env) + : ModuleInstance("wasmedge_ffmpeg_avdevice") { + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_register_all", + std::make_unique<AVDeviceRegisterAll>(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_version", + std::make_unique<AVDeviceVersion>(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_list_devices", + std::make_unique<AVDeviceListDevices>(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_free_list_devices", + std::make_unique<AVDeviceFreeListDevices>(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_nb_devices", + std::make_unique<AVDeviceNbDevices>(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_default_device", + std::make_unique<AVDeviceDefaultDevice>(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_configuration_length", + std::make_unique<AVDeviceConfigurationLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_configuration", + std::make_unique<AVDeviceConfiguration>(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_license_length", + std::make_unique<AVDeviceLicenseLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_license", + std::make_unique<AVDeviceLicense>(Env)); +} + +} // namespace AVDevice +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avdevice/module.h b/plugins/wasmedge_ffmpeg/avdevice/module.h new file mode 100644 index 000000000000..26ed72df5ff2 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avdevice/module.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_env.h" + +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVDevice { + +class WasmEdgeFFmpegAVDeviceModule : public Runtime::Instance::ModuleInstance { +public: + WasmEdgeFFmpegAVDeviceModule(std::shared_ptr<WasmEdgeFFmpegEnv> Env); +}; + +} // namespace AVDevice +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avfilter/avFilter.cpp b/plugins/wasmedge_ffmpeg/avfilter/avFilter.cpp new file mode 100644 index 000000000000..9020b7590c4f --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/avFilter.cpp @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avFilter.h" + +extern "C" { +#include "libavfilter/avfilter.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +Expect<int32_t> AVFilterNameLength::body(const Runtime::CallingFrame &, + uint32_t FilterId) { + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + return strlen(Filter->name); +} + +Expect<int32_t> AVFilterName::body(const Runtime::CallingFrame &Frame, + uint32_t FilterId, uint32_t NamePtr, + uint32_t NameLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(NameBuf, MemInst, char, NamePtr, NameLen, ""); + + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + const char *Name = Filter->name; + std::copy_n(Name, NameLen, NameBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterDescriptionLength::body(const Runtime::CallingFrame &, + uint32_t FilterId) { + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + return strlen(Filter->description); +} + +Expect<int32_t> AVFilterDescription::body(const Runtime::CallingFrame &Frame, + uint32_t FilterId, uint32_t DescPtr, + uint32_t DescLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(DescBuf, MemInst, char, DescPtr, DescLen, ""); + + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + const char *Desc = Filter->description; + std::copy_n(Desc, DescLen, DescBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<uint32_t> AVFilterNbInputs::body(const Runtime::CallingFrame &, + uint32_t FilterId) { + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + return Filter->nb_inputs; +} + +Expect<uint32_t> AVFilterNbOutputs::body(const Runtime::CallingFrame &, + uint32_t FilterId) { + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + return Filter->nb_outputs; +} + +Expect<int32_t> AVFilterFlags::body(const Runtime::CallingFrame &, + uint32_t FilterId) { + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + return Filter->flags; +} + +Expect<int32_t> AVFilterInOutSetName::body(const Runtime::CallingFrame &Frame, + uint32_t InOutId, uint32_t NamePtr, + uint32_t NameLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(NameBuf, MemInst, char, NamePtr, NameLen, ""); + + FFMPEG_PTR_FETCH(InOut, InOutId, AVFilterInOut); + + std::string Name; + std::copy_n(NameBuf.data(), NameLen, std::back_inserter(Name)); + char *CName = av_strdup(Name.c_str()); + if (CName == nullptr) { + return static_cast<int32_t>(ErrNo::Success); + } + InOut->name = CName; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterInOutSetFilterCtx::body(const Runtime::CallingFrame &, + uint32_t InOutId, + uint32_t FilterCtxId) { + FFMPEG_PTR_FETCH(InOut, InOutId, AVFilterInOut); + FFMPEG_PTR_FETCH(FilterCtx, FilterCtxId, AVFilterContext); + + InOut->filter_ctx = FilterCtx; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterInOutSetPadIdx::body(const Runtime::CallingFrame &, + uint32_t InOutId, int32_t PadIdx) { + FFMPEG_PTR_FETCH(InOut, InOutId, AVFilterInOut); + InOut->pad_idx = PadIdx; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterInOutSetNext::body(const Runtime::CallingFrame &, + uint32_t InOutId, + uint32_t NextInOutId) { + FFMPEG_PTR_FETCH(InOut, InOutId, AVFilterInOut); + FFMPEG_PTR_FETCH(NextInOut, NextInOutId, AVFilterInOut); + InOut->next = NextInOut; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVFilterGetInputsFilterPad::body(const Runtime::CallingFrame &Frame, + uint32_t FilterId, uint32_t FilterPadPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(FilterPadId, MemInst, uint32_t, FilterPadPtr, "") + + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + const AVFilterPad *FilterPad = Filter->inputs; + if (FilterPad == nullptr) { + return static_cast<int32_t>(ErrNo::Success); + } + FFMPEG_PTR_STORE(const_cast<AVFilterPad *>(FilterPad), FilterPadId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVFilterGetOutputsFilterPad::body(const Runtime::CallingFrame &Frame, + uint32_t FilterId, uint32_t FilterPadPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(FilterPadId, MemInst, uint32_t, FilterPadPtr, "") + + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + const AVFilterPad *FilterPad = Filter->outputs; + if (FilterPad == nullptr) { + return static_cast<int32_t>(ErrNo::Success); + } + FFMPEG_PTR_STORE(const_cast<AVFilterPad *>(FilterPad), FilterPadId); + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVFilter +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avfilter/avFilter.h b/plugins/wasmedge_ffmpeg/avfilter/avFilter.h new file mode 100644 index 000000000000..8141d3d77a93 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/avFilter.h @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +class AVFilterNameLength : public HostFunction<AVFilterNameLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterId); +}; + +class AVFilterName : public HostFunction<AVFilterName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterId, + uint32_t NamePtr, uint32_t NameLen); +}; + +class AVFilterDescriptionLength + : public HostFunction<AVFilterDescriptionLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterId); +}; + +class AVFilterDescription : public HostFunction<AVFilterDescription> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterId, + uint32_t DescPtr, uint32_t DescLen); +}; + +class AVFilterNbInputs : public HostFunction<AVFilterNbInputs> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterId); +}; + +class AVFilterNbOutputs : public HostFunction<AVFilterNbOutputs> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterId); +}; + +class AVFilterFlags : public HostFunction<AVFilterFlags> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterId); +}; + +class AVFilterInOutSetName : public HostFunction<AVFilterInOutSetName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t InOutId, + uint32_t NamePtr, uint32_t NameLen); +}; + +class AVFilterInOutSetFilterCtx + : public HostFunction<AVFilterInOutSetFilterCtx> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t InOutId, + uint32_t FilterCtxId); +}; + +class AVFilterInOutSetPadIdx : public HostFunction<AVFilterInOutSetPadIdx> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t InOutId, + int32_t PadIdx); +}; + +class AVFilterInOutSetNext : public HostFunction<AVFilterInOutSetNext> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t InOutId, + uint32_t NextInOutId); +}; + +class AVFilterGetInputsFilterPad + : public HostFunction<AVFilterGetInputsFilterPad> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterId, + uint32_t FilterPadPtr); +}; + +class AVFilterGetOutputsFilterPad + : public HostFunction<AVFilterGetOutputsFilterPad> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterId, + uint32_t FilterPadPtr); +}; + +} // namespace AVFilter +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avfilter/avfilter_func.cpp b/plugins/wasmedge_ffmpeg/avfilter/avfilter_func.cpp new file mode 100644 index 000000000000..73ad99cace6b --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/avfilter_func.cpp @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avfilter_func.h" + +extern "C" { +#include "libavfilter/avfilter.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +Expect<int32_t> AVFilterGraphAlloc::body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(FilterGraphId, MemInst, uint32_t, FilterGraphPtr, "") + + FFMPEG_PTR_FETCH(FilterGraph, *FilterGraphId, AVFilterGraph); + + FilterGraph = avfilter_graph_alloc(); + if (FilterGraph == nullptr) { + return static_cast<int32_t>(ErrNo::Success); + } + FFMPEG_PTR_STORE(FilterGraph, FilterGraphId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterGraphConfig::body(const Runtime::CallingFrame &, + uint32_t FilterGraphId) { + FFMPEG_PTR_FETCH(FilterGraph, FilterGraphId, AVFilterGraph); + return avfilter_graph_config(FilterGraph, + nullptr); // log_ctx always NULL on Rust SDK. +} + +Expect<int32_t> AVFilterGraphFree::body(const Runtime::CallingFrame &, + uint32_t FilterGraphId) { + FFMPEG_PTR_FETCH(FilterGraph, FilterGraphId, AVFilterGraph); + avfilter_graph_free(&FilterGraph); + FFMPEG_PTR_DELETE(FilterGraphId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterGraphGetFilter::body(const Runtime::CallingFrame &Frame, + uint32_t FilterCtxPtr, + uint32_t FilterGraphId, + uint32_t NamePtr, + uint32_t NameSize) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(NameId, MemInst, char, NamePtr, + "Failed when accessing the return Name memory"sv); + MEM_PTR_CHECK(FilterCtxId, MemInst, uint32_t, FilterCtxPtr, ""); + + FFMPEG_PTR_FETCH(FilterGraph, FilterGraphId, AVFilterGraph); + FFMPEG_PTR_FETCH(FilterCtx, *FilterCtxId, AVFilterContext); + + std::string Name; + std::copy_n(NameId, NameSize, std::back_inserter(Name)); + + FilterCtx = avfilter_graph_get_filter(FilterGraph, Name.c_str()); + if (FilterCtx == nullptr) { + return static_cast<int32_t>(ErrNo::Success); + } + FFMPEG_PTR_STORE(FilterCtx, FilterCtxId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterGraphParsePtr::body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId, + uint32_t FiltersString, + uint32_t FiltersSize, + uint32_t InputsId, + uint32_t OutputsId) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(FiltersId, MemInst, char, FiltersString, ""); + + FFMPEG_PTR_FETCH(Inputs, InputsId, AVFilterInOut); + FFMPEG_PTR_FETCH(Outputs, OutputsId, AVFilterInOut); + FFMPEG_PTR_FETCH(FiltersGraph, FilterGraphId, AVFilterGraph); + + std::string Filters; + std::copy_n(FiltersId, FiltersSize, std::back_inserter(Filters)); + return avfilter_graph_parse_ptr(FiltersGraph, Filters.c_str(), &Inputs, + &Outputs, nullptr); +} + +Expect<int32_t> AVFilterInOutFree::body(const Runtime::CallingFrame &, + uint32_t InOutId) { + FFMPEG_PTR_FETCH(InOut, InOutId, AVFilterInOut); + avfilter_inout_free(&InOut); + FFMPEG_PTR_DELETE(InOutId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<uint32_t> AVFilterVersion::body(const Runtime::CallingFrame &) { + return avfilter_version(); +} + +Expect<int32_t> AVFilterGetByName::body(const Runtime::CallingFrame &Frame, + uint32_t FilterPtr, uint32_t StrPtr, + uint32_t StrLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(StrId, MemInst, char, StrPtr, + "Failed when accessing the return Str memory"sv); + MEM_PTR_CHECK(FilterId, MemInst, uint32_t, FilterPtr, + "Failed when accessing the return Filter memory"sv); + + FFMPEG_PTR_FETCH(Filter, *FilterId, const struct AVFilter); + std::string Name; + std::copy_n(StrId, StrLen, std::back_inserter(Name)); + + Filter = avfilter_get_by_name(Name.c_str()); + if (Filter == nullptr) { + return static_cast<int32_t>(ErrNo::Success); + } + + FFMPEG_PTR_STORE(const_cast<struct AVFilter *>(Filter), FilterId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVFilterConfigurationLength::body(const Runtime::CallingFrame &) { + const char *Config = avfilter_configuration(); + return strlen(Config); +} + +Expect<int32_t> AVFilterConfiguration::body(const Runtime::CallingFrame &Frame, + uint32_t ConfigPtr, + uint32_t ConfigLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(ConfigBuf, MemInst, char, ConfigPtr, ConfigLen, ""); + + const char *Config = avfilter_configuration(); + std::copy_n(Config, ConfigLen, ConfigBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterLicenseLength::body(const Runtime::CallingFrame &) { + const char *License = avfilter_license(); + return strlen(License); +} + +Expect<int32_t> AVFilterLicense::body(const Runtime::CallingFrame &Frame, + uint32_t LicensePtr, + uint32_t LicenseLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(LicenseBuf, MemInst, char, LicensePtr, LicenseLen, ""); + + const char *License = avfilter_license(); + std::copy_n(License, LicenseLen, LicenseBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterGraphCreateFilter::body( + const Runtime::CallingFrame &Frame, uint32_t FilterCtxPtr, + uint32_t FilterId, uint32_t NamePtr, uint32_t NameLen, uint32_t ArgsPtr, + uint32_t ArgsLen, uint32_t FilterGraphId) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(NameBuf, MemInst, char, NamePtr, NameLen, ""); + MEM_SPAN_CHECK(ArgsBuf, MemInst, char, ArgsPtr, ArgsLen, ""); + MEM_PTR_CHECK(FilterCtxId, MemInst, uint32_t, FilterCtxPtr, "") + + FFMPEG_PTR_FETCH(FilterCtx, *FilterCtxId, AVFilterContext); + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + FFMPEG_PTR_FETCH(FilterGraph, FilterGraphId, AVFilterGraph); + + std::string Name; + std::string Args; + std::copy_n(NameBuf.data(), NameLen, std::back_inserter(Name)); + std::copy_n(ArgsBuf.data(), ArgsLen, std::back_inserter(Args)); + + int Res = avfilter_graph_create_filter(&FilterCtx, Filter, Name.c_str(), + Args.c_str(), nullptr, FilterGraph); + if (Res < 0) { + return Res; + } + + FFMPEG_PTR_STORE(FilterCtx, FilterCtxId); + return Res; +} + +Expect<int32_t> AVFilterInOutAlloc::body(const Runtime::CallingFrame &Frame, + uint32_t InOutPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(InOutId, MemInst, uint32_t, InOutPtr, "") + + FFMPEG_PTR_FETCH(InOut, *InOutId, AVFilterInOut); + InOut = avfilter_inout_alloc(); + if (InOut == nullptr) { + return static_cast<int32_t>(ErrNo::Success); + } + FFMPEG_PTR_STORE(InOut, InOutId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterPadGetNameLength::body(const Runtime::CallingFrame &, + uint32_t FilterPadId, + int32_t Idx) { + FFMPEG_PTR_FETCH(FilterPad, FilterPadId, AVFilterPad); + + const char *Name = avfilter_pad_get_name(FilterPad, Idx); + return strlen(Name); +} + +Expect<int32_t> AVFilterPadGetName::body(const Runtime::CallingFrame &Frame, + uint32_t FilterPadId, int32_t Idx, + uint32_t NamePtr, uint32_t NameLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(NameBuf, MemInst, char, NamePtr, NameLen, ""); + + FFMPEG_PTR_FETCH(FilterPad, FilterPadId, AVFilterPad); + + const char *Name = avfilter_pad_get_name(FilterPad, Idx); + std::copy_n(Name, NameLen, NameBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterPadGetType::body(const Runtime::CallingFrame &, + uint32_t FilterPadId, int32_t Idx) { + FFMPEG_PTR_FETCH(FilterPad, FilterPadId, AVFilterPad); + AVMediaType const MediaType = avfilter_pad_get_type(FilterPad, Idx); + return FFmpegUtils::MediaType::fromMediaType(MediaType); +} + +Expect<int32_t> AVFilterGraphDumpLength::body(const Runtime::CallingFrame &, + uint32_t FilterGraphId) { + FFMPEG_PTR_FETCH(FilterGraph, FilterGraphId, AVFilterGraph); + char *Graph = avfilter_graph_dump(FilterGraph, nullptr); + return strlen(Graph); +} + +Expect<int32_t> AVFilterGraphDump::body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId, + uint32_t GraphStrPtr, + uint32_t GraphStrLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(GraphStr, MemInst, char, GraphStrPtr, GraphStrLen, ""); + + FFMPEG_PTR_FETCH(FilterGraph, FilterGraphId, AVFilterGraph); + + char *Graph = avfilter_graph_dump(FilterGraph, nullptr); + std::copy_n(Graph, GraphStrLen, GraphStr.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterFreeGraphStr::body(const Runtime::CallingFrame &, + uint32_t FilterGraphId) { + FFMPEG_PTR_FETCH(FilterGraph, FilterGraphId, AVFilterGraph); + + char *Graph = avfilter_graph_dump(FilterGraph, nullptr); + av_free(Graph); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterDrop::body(const Runtime::CallingFrame &, + uint32_t FilterId) { + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + if (Filter == nullptr) { + return static_cast<int32_t>(ErrNo::Success); + } + FFMPEG_PTR_DELETE(FilterId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterPadDrop::body(const Runtime::CallingFrame &, + uint32_t FilterPadId) { + FFMPEG_PTR_FETCH(FilterPad, FilterPadId, AVFilterPad); + if (FilterPad == nullptr) { + return static_cast<int32_t>(ErrNo::Success); + } + FFMPEG_PTR_DELETE(FilterPadId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFilterContextDrop::body(const Runtime::CallingFrame &, + uint32_t FilterCtxId) { + FFMPEG_PTR_FETCH(FilterCtx, FilterCtxId, AVFilterContext); + if (FilterCtx == nullptr) { + return static_cast<int32_t>(ErrNo::Success); + } + FFMPEG_PTR_DELETE(FilterCtxId); + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVFilter +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avfilter/avfilter_func.h b/plugins/wasmedge_ffmpeg/avfilter/avfilter_func.h new file mode 100644 index 000000000000..6f8b486d03a1 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/avfilter_func.h @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +class AVFilterGraphAlloc : public HostFunction<AVFilterGraphAlloc> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphPtr); +}; + +class AVFilterGraphConfig : public HostFunction<AVFilterGraphConfig> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId); +}; + +class AVFilterGraphFree : public HostFunction<AVFilterGraphFree> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId); +}; + +class AVFilterGraphGetFilter : public HostFunction<AVFilterGraphGetFilter> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterCtxPtr, uint32_t FilterGraphId, + uint32_t NamePtr, uint32_t NameSize); +}; + +class AVFilterGraphParsePtr : public HostFunction<AVFilterGraphParsePtr> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId, uint32_t FiltersString, + uint32_t FiltersSize, uint32_t InputsId, + uint32_t OutputsId); +}; + +class AVFilterInOutFree : public HostFunction<AVFilterInOutFree> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t InOutId); +}; + +class AVFilterVersion : public HostFunction<AVFilterVersion> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVFilterGetByName : public HostFunction<AVFilterGetByName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterPtr, + uint32_t StrPtr, uint32_t StrLen); +}; + +class AVFilterConfigurationLength + : public HostFunction<AVFilterConfigurationLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVFilterConfiguration : public HostFunction<AVFilterConfiguration> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class AVFilterLicenseLength : public HostFunction<AVFilterLicenseLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVFilterLicense : public HostFunction<AVFilterLicense> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t LicensePtr, + uint32_t LicenseLen); +}; + +class AVFilterGraphCreateFilter + : public HostFunction<AVFilterGraphCreateFilter> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterCtxPtr, uint32_t FilterId, + uint32_t NamePtr, uint32_t NameLen, uint32_t ArgsPtr, + uint32_t ArgsLen, uint32_t FilterGraphId); +}; + +class AVFilterInOutAlloc : public HostFunction<AVFilterInOutAlloc> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t InOutPtr); +}; + +class AVFilterPadGetNameLength : public HostFunction<AVFilterPadGetNameLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterPadId, + int32_t Idx); +}; + +class AVFilterPadGetName : public HostFunction<AVFilterPadGetName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterPadId, + int32_t Idx, uint32_t NamePtr, uint32_t NameLen); +}; + +class AVFilterPadGetType : public HostFunction<AVFilterPadGetType> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterPadId, + int32_t Idx); +}; + +class AVFilterGraphDumpLength : public HostFunction<AVFilterGraphDumpLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId); +}; + +class AVFilterGraphDump : public HostFunction<AVFilterGraphDump> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId, uint32_t GraphStrPtr, + uint32_t GraphStrLen); +}; + +class AVFilterFreeGraphStr : public HostFunction<AVFilterFreeGraphStr> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId); +}; + +class AVFilterDrop : public HostFunction<AVFilterDrop> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilterId); +}; + +class AVFilterPadDrop : public HostFunction<AVFilterPadDrop> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterPadId); +}; + +class AVFilterContextDrop : public HostFunction<AVFilterContextDrop> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterCtxId); +}; + +} // namespace AVFilter +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avfilter/buffer_source_sink.cpp b/plugins/wasmedge_ffmpeg/avfilter/buffer_source_sink.cpp new file mode 100644 index 000000000000..5753477de711 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/buffer_source_sink.cpp @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "buffer_source_sink.h" + +extern "C" { +#include "libavfilter/buffersink.h" +#include "libavfilter/buffersrc.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +Expect<int32_t> AVBufferSinkGetFrame::body(const Runtime::CallingFrame &, + uint32_t FilterContextId, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(FilterCtx, FilterContextId, AVFilterContext); + FFMPEG_PTR_FETCH(Frame, FrameId, AVFrame); + return av_buffersink_get_frame(FilterCtx, Frame); +} + +Expect<int32_t> AVBufferSinkGetSamples::body(const Runtime::CallingFrame &, + uint32_t FilterContextId, + uint32_t FrameId, + int32_t Samples) { + FFMPEG_PTR_FETCH(FilterCtx, FilterContextId, AVFilterContext); + FFMPEG_PTR_FETCH(Frame, FrameId, AVFrame); + return av_buffersink_get_samples(FilterCtx, Frame, Samples); +} + +Expect<int32_t> AvBufferSinkSetFrameSize::body(const Runtime::CallingFrame &, + uint32_t FilterContextId, + int32_t Value) { + FFMPEG_PTR_FETCH(FilterCtx, FilterContextId, AVFilterContext); + av_buffersink_set_frame_size(FilterCtx, Value); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVBufferSrcGetNbFailedRequests::body(const Runtime::CallingFrame &, + uint32_t FilterContextId) { + FFMPEG_PTR_FETCH(FilterCtx, FilterContextId, AVFilterContext); + return av_buffersrc_get_nb_failed_requests(FilterCtx); +} + +Expect<int32_t> AVBufferSrcAddFrame::body(const Runtime::CallingFrame &, + uint32_t FilterContextId, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(FilterCtx, FilterContextId, AVFilterContext); + FFMPEG_PTR_FETCH(Frame, FrameId, AVFrame); + return av_buffersrc_add_frame(FilterCtx, Frame); +} + +Expect<int32_t> AVBufferSrcClose::body(const Runtime::CallingFrame &, + uint32_t FilterContextId, int64_t Pts, + uint32_t Flags) { + FFMPEG_PTR_FETCH(FilterCtx, FilterContextId, AVFilterContext); + return av_buffersrc_close(FilterCtx, Pts, Flags); +} + +} // namespace AVFilter +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avfilter/buffer_source_sink.h b/plugins/wasmedge_ffmpeg/avfilter/buffer_source_sink.h new file mode 100644 index 000000000000..40db402b8bbd --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/buffer_source_sink.h @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +class AVBufferSinkGetFrame : public HostFunction<AVBufferSinkGetFrame> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterContextId, uint32_t FrameId); +}; + +class AVBufferSinkGetSamples : public HostFunction<AVBufferSinkGetSamples> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterContextId, uint32_t FrameId, + int32_t Samples); +}; + +class AvBufferSinkSetFrameSize : public HostFunction<AvBufferSinkSetFrameSize> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterContextId, int32_t Value); +}; + +class AVBufferSrcGetNbFailedRequests + : public HostFunction<AVBufferSrcGetNbFailedRequests> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterContextId); +}; + +class AVBufferSrcAddFrame : public HostFunction<AVBufferSrcAddFrame> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterContextId, uint32_t FrameId); +}; + +class AVBufferSrcClose : public HostFunction<AVBufferSrcClose> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t FilterContextId, int64_t Pts, uint32_t Flags); +}; + +} // namespace AVFilter +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avfilter/module.cpp b/plugins/wasmedge_ffmpeg/avfilter/module.cpp new file mode 100644 index 000000000000..761d5fba07f1 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/module.cpp @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "module.h" +#include "avFilter.h" +#include "avfilter_func.h" +#include "buffer_source_sink.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +WasmEdgeFFmpegAVFilterModule::WasmEdgeFFmpegAVFilterModule( + std::shared_ptr<WasmEdgeFFmpegEnv> Env) + : ModuleInstance("wasmedge_ffmpeg_avfilter") { + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_alloc", + std::make_unique<AVFilterGraphAlloc>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_config", + std::make_unique<AVFilterGraphConfig>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_free", + std::make_unique<AVFilterGraphFree>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_get_filter", + std::make_unique<AVFilterGraphGetFilter>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_parse_ptr", + std::make_unique<AVFilterGraphParsePtr>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_inout_free", + std::make_unique<AVFilterInOutFree>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_version", + std::make_unique<AVFilterVersion>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_get_by_name", + std::make_unique<AVFilterGetByName>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_configuration_length", + std::make_unique<AVFilterConfigurationLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_configuration", + std::make_unique<AVFilterConfiguration>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_license_length", + std::make_unique<AVFilterLicenseLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_license", + std::make_unique<AVFilterLicense>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_create_filter", + std::make_unique<AVFilterGraphCreateFilter>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_inout_alloc", + std::make_unique<AVFilterInOutAlloc>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_pad_get_name_length", + std::make_unique<AVFilterPadGetNameLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_pad_get_name", + std::make_unique<AVFilterPadGetName>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_pad_get_type", + std::make_unique<AVFilterPadGetType>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_dump_length", + std::make_unique<AVFilterGraphDumpLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_dump", + std::make_unique<AVFilterGraphDump>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_free_graph_str", + std::make_unique<AVFilterFreeGraphStr>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_drop", + std::make_unique<AVFilterDrop>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_pad_drop", + std::make_unique<AVFilterPadDrop>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_context_drop", + std::make_unique<AVFilterContextDrop>(Env)); + + // buffersrc.h && buffersink.h + addHostFunc("wasmedge_ffmpeg_avfilter_av_buffersink_get_frame", + std::make_unique<AVBufferSinkGetFrame>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_av_buffersink_get_samples", + std::make_unique<AVBufferSinkGetSamples>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_av_buffersink_set_frame_size", + std::make_unique<AvBufferSinkSetFrameSize>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_av_buffersrc_get_nb_failed_requests", + std::make_unique<AVBufferSrcGetNbFailedRequests>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_av_buffersrc_add_frame", + std::make_unique<AVBufferSrcAddFrame>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_av_buffersrc_close", + std::make_unique<AVBufferSrcClose>(Env)); + + // avfilter.h + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_name_length", + std::make_unique<AVFilterNameLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_name", + std::make_unique<AVFilterName>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_description_length", + std::make_unique<AVFilterDescriptionLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_description", + std::make_unique<AVFilterDescription>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_nb_inputs", + std::make_unique<AVFilterNbInputs>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_nb_outputs", + std::make_unique<AVFilterNbOutputs>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_flags", + std::make_unique<AVFilterFlags>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_inout_set_name", + std::make_unique<AVFilterInOutSetName>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_inout_set_filter_ctx", + std::make_unique<AVFilterInOutSetFilterCtx>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_inout_set_pad_idx", + std::make_unique<AVFilterInOutSetPadIdx>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_inout_set_next", + std::make_unique<AVFilterInOutSetNext>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_get_inputs_filter_pad", + std::make_unique<AVFilterGetInputsFilterPad>(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_get_outputs_filter_pad", + std::make_unique<AVFilterGetOutputsFilterPad>(Env)); +} + +} // namespace AVFilter +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avfilter/module.h b/plugins/wasmedge_ffmpeg/avfilter/module.h new file mode 100644 index 000000000000..176704fa84be --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/module.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_env.h" + +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +class WasmEdgeFFmpegAVFilterModule : public Runtime::Instance::ModuleInstance { +public: + WasmEdgeFFmpegAVFilterModule(std::shared_ptr<WasmEdgeFFmpegEnv> Env); +}; + +} // namespace AVFilter +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avformat/avChapter.cpp b/plugins/wasmedge_ffmpeg/avformat/avChapter.cpp new file mode 100644 index 000000000000..f0657a52a9de --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avChapter.cpp @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avChapter.h" + +extern "C" { +#include "libavformat/avformat.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +Expect<int64_t> AVChapterId::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, uint32_t ChapterIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVChapter **AvChapter = AvFormatContext->chapters; + + // No check here (Check) + // Raw Pointer Iteration. + for (unsigned int I = 1; I <= ChapterIdx; I++) { + AvChapter++; + } + + return static_cast<AVChapter *>(*AvChapter)->id; +} + +Expect<int32_t> AVChapterSetId::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t ChapterIdx, int64_t ChapterId) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVChapter **AvChapter = AvFormatContext->chapters; + + // No check here (Check) + // Raw Pointer Iteration. + for (unsigned int I = 1; I <= ChapterIdx; I++) { + AvChapter++; + } + + (*AvChapter)->id = ChapterId; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVChapterTimebase::body(const Runtime::CallingFrame &Frame, + uint32_t NumPtr, uint32_t DenPtr, + uint32_t AvFormatCtxId, + uint32_t ChapterIdx) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(Num, MemInst, int32_t, NumPtr, ""); + MEM_PTR_CHECK(Den, MemInst, int32_t, DenPtr, ""); + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVChapter **AvChapter = AvFormatContext->chapters; + + // No check here (Check) + // Raw Pointer Iteration. + for (unsigned int I = 1; I <= ChapterIdx; I++) { + AvChapter++; + } + + AVRational const AvRational = static_cast<AVChapter *>(*AvChapter)->time_base; + *Num = AvRational.num; + *Den = AvRational.den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVChapterSetTimebase::body(const Runtime::CallingFrame &, + int32_t Num, int32_t Den, + uint32_t AvFormatCtxId, + uint32_t ChapterIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVRational const Timebase = av_make_q(Num, Den); + + AVChapter **AvChapter = AvFormatContext->chapters; + + // No check here (Check) + // Raw Pointer Iteration. + for (unsigned int I = 1; I <= ChapterIdx; I++) { + AvChapter++; + } + + (*AvChapter)->time_base = Timebase; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int64_t> AVChapterStart::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t ChapterIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVChapter **AvChapter = AvFormatContext->chapters; + + // No check here (Check) + // Raw Pointer Iteration. + for (unsigned int I = 1; I <= ChapterIdx; I++) { + AvChapter++; + } + + return static_cast<AVChapter *>(*AvChapter)->start; +} + +Expect<int32_t> AVChapterSetStart::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t ChapterIdx, + int64_t StartValue) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVChapter **AvChapter = AvFormatContext->chapters; + + // No check here (Check) + // Raw Pointer Iteration. + for (unsigned int I = 1; I <= ChapterIdx; I++) { + AvChapter++; + } + + (*AvChapter)->start = StartValue; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int64_t> AVChapterEnd::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t ChapterIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVChapter **AvChapter = AvFormatContext->chapters; + + // No check here (Check) + // Raw Pointer Iteration. + for (unsigned int I = 1; I <= ChapterIdx; I++) { + AvChapter++; + } + + return static_cast<AVChapter *>(*AvChapter)->end; +} + +Expect<int32_t> AVChapterSetEnd::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t ChapterIdx, int64_t EndValue) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVChapter **AvChapter = AvFormatContext->chapters; + + // No check here (Check) + // Raw Pointer Iteration. + for (unsigned int I = 1; I <= ChapterIdx; I++) { + AvChapter++; + } + + (*AvChapter)->end = EndValue; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVChapterMetadata::body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, + uint32_t ChapterIdx, uint32_t DictPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(DictId, MemInst, uint32_t, DictPtr, + "Failed when accessing the return AVDictionary memory"sv); + + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + + AVDictionary **AvDictionary = + static_cast<AVDictionary **>(av_malloc(sizeof(AVDictionary *))); + AVChapter **AvChapter = AvFormatCtx->chapters; + + // No check here (Check) + // Raw Pointer Iteration. + for (unsigned int I = 1; I <= ChapterIdx; I++) { + AvChapter++; + } + + *AvDictionary = (*AvChapter)->metadata; + FFMPEG_PTR_STORE(AvDictionary, DictId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVChapterSetMetadata::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t ChapterIdx, + uint32_t DictId) { + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + FFMPEG_PTR_FETCH(AvDictionary, DictId, AVDictionary *); + + AVChapter **AvChapter = AvFormatCtx->chapters; + + // No check here (Check) + // Raw Pointer Iteration. + for (unsigned int I = 1; I <= ChapterIdx; I++) { + AvChapter++; + } + + if (AvDictionary == nullptr) { + (*AvChapter)->metadata = nullptr; + } else { + (*AvChapter)->metadata = *AvDictionary; + } + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avformat/avChapter.h b/plugins/wasmedge_ffmpeg/avformat/avChapter.h new file mode 100644 index 000000000000..822c736763d8 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avChapter.h @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +class AVChapterId : public HostFunction<AVChapterId> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx); +}; + +class AVChapterSetId : public HostFunction<AVChapterSetId> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx, + int64_t ChapterId); +}; + +class AVChapterTimebase : public HostFunction<AVChapterTimebase> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t NumPtr, + uint32_t DenPtr, uint32_t AvFormatCtxId, + uint32_t ChapterIdx); +}; + +class AVChapterSetTimebase : public HostFunction<AVChapterSetTimebase> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t Num, + int32_t Den, uint32_t AvFormatCtxId, + uint32_t ChapterIdx); +}; + +class AVChapterStart : public HostFunction<AVChapterStart> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx); +}; + +class AVChapterSetStart : public HostFunction<AVChapterSetStart> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx, + int64_t StartValue); +}; + +class AVChapterEnd : public HostFunction<AVChapterEnd> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx); +}; + +class AVChapterSetEnd : public HostFunction<AVChapterSetEnd> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx, + int64_t EndValue); +}; + +class AVChapterMetadata : public HostFunction<AVChapterMetadata> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx, + uint32_t DictPtr); +}; + +class AVChapterSetMetadata : public HostFunction<AVChapterSetMetadata> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx, + uint32_t DictId); +}; + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avformat/avInputOutputFormat.cpp b/plugins/wasmedge_ffmpeg/avformat/avInputOutputFormat.cpp new file mode 100644 index 000000000000..826da2016143 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avInputOutputFormat.cpp @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avInputOutputFormat.h" + +extern "C" { +#include "libavformat/avformat.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +Expect<int32_t> AVIOFormatNameLength::body(const Runtime::CallingFrame &, + uint32_t AVIOFormatId, + uint32_t FormatType) { + const char *Name; + + if (FormatType == 0) { + FFMPEG_PTR_FETCH(AvInputFormat, AVIOFormatId, AVInputFormat); + Name = AvInputFormat->name; + } else { + FFMPEG_PTR_FETCH(AvOutputFormat, AVIOFormatId, AVOutputFormat); + Name = AvOutputFormat->name; + } + + if (Name == nullptr) { + return 0; + } + return strlen(Name); +} + +Expect<int32_t> AVInputFormatName::body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, + uint32_t NamePtr, uint32_t NameLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(NameBuf, MemInst, char, NamePtr, NameLen, ""); + FFMPEG_PTR_FETCH(AvInputFormat, AVInputFormatId, AVInputFormat); + + const char *Name = AvInputFormat->name; + std::copy_n(Name, NameLen, NameBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVOutputFormatName::body(const Runtime::CallingFrame &Frame, + uint32_t AVOutputFormatId, + uint32_t NamePtr, uint32_t NameLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(NameBuf, MemInst, char, NamePtr, NameLen, ""); + FFMPEG_PTR_FETCH(AvOutputFormat, AVOutputFormatId, AVOutputFormat); + + const char *Name = AvOutputFormat->name; + std::copy_n(Name, NameLen, NameBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVIOFormatLongNameLength::body(const Runtime::CallingFrame &, + uint32_t AVIOFormatId, + uint32_t FormatType) { + const char *LongName; + + if (FormatType == 0) { + FFMPEG_PTR_FETCH(AvInputFormat, AVIOFormatId, AVInputFormat); + LongName = AvInputFormat->long_name; + } else { + FFMPEG_PTR_FETCH(AvOutputFormat, AVIOFormatId, AVOutputFormat); + LongName = AvOutputFormat->long_name; + } + + if (LongName == nullptr) { + return 0; + } + return strlen(LongName); +} + +Expect<int32_t> AVInputFormatLongName::body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, + uint32_t LongNamePtr, + uint32_t LongNameLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(LongNameBuf, MemInst, char, LongNamePtr, LongNameLen, ""); + FFMPEG_PTR_FETCH(AvInputFormat, AVInputFormatId, AVInputFormat); + + const char *LongName = AvInputFormat->long_name; + std::copy_n(LongName, LongNameLen, LongNameBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVOutputFormatLongName::body(const Runtime::CallingFrame &Frame, + uint32_t AVOutputFormatId, + uint32_t LongNamePtr, + uint32_t LongNameLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(LongNameBuf, MemInst, char, LongNamePtr, LongNameLen, ""); + FFMPEG_PTR_FETCH(AvOutputFormat, AVOutputFormatId, AVOutputFormat); + + const char *LongName = AvOutputFormat->long_name; + std::copy_n(LongName, LongNameLen, LongNameBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVIOFormatExtensionsLength::body(const Runtime::CallingFrame &, + uint32_t AVIOFormatId, + uint32_t FormatType) { + const char *Extensions; + + if (FormatType == 0) { + FFMPEG_PTR_FETCH(AvInputFormat, AVIOFormatId, AVInputFormat); + Extensions = AvInputFormat->extensions; + } else { + FFMPEG_PTR_FETCH(AvOutputFormat, AVIOFormatId, AVOutputFormat); + Extensions = AvOutputFormat->extensions; + } + + if (Extensions == nullptr) { + return 0; + } + return strlen(Extensions); +} + +Expect<int32_t> +AVInputFormatExtensions::body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t ExtensionsPtr, + uint32_t ExtensionsLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(ExtensionsBuf, MemInst, char, ExtensionsPtr, ExtensionsLen, + ""); + FFMPEG_PTR_FETCH(AvInputFormat, AVInputFormatId, AVInputFormat); + + const char *Extensions = AvInputFormat->extensions; + std::copy_n(Extensions, ExtensionsLen, ExtensionsBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVOutputFormatExtensions::body(const Runtime::CallingFrame &Frame, + uint32_t AVOutputFormatId, + uint32_t ExtensionsPtr, uint32_t ExtensionsLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(ExtensionsBuf, MemInst, char, ExtensionsPtr, ExtensionsLen, + ""); + FFMPEG_PTR_FETCH(AvOutputFormat, AVOutputFormatId, AVOutputFormat); + + const char *Extensions = AvOutputFormat->extensions; + std::copy_n(Extensions, ExtensionsLen, ExtensionsBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVIOFormatMimeTypeLength::body(const Runtime::CallingFrame &, + uint32_t AVIOFormatId, + uint32_t FormatType) { + const char *MimeType; + + if (FormatType == 0) { + FFMPEG_PTR_FETCH(AvInputFormat, AVIOFormatId, AVInputFormat); + MimeType = AvInputFormat->mime_type; + } else { + FFMPEG_PTR_FETCH(AvOutputFormat, AVIOFormatId, AVOutputFormat); + MimeType = AvOutputFormat->mime_type; + } + + if (MimeType == nullptr) { + return 0; + } + return strlen(MimeType); +} + +Expect<int32_t> AVInputFormatMimeType::body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, + uint32_t MimeTypePtr, + uint32_t MimeTypeLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(MimeTypeBuf, MemInst, char, MimeTypePtr, MimeTypeLen, ""); + FFMPEG_PTR_FETCH(AvInputFormat, AVInputFormatId, AVInputFormat); + + const char *MimeType = AvInputFormat->mime_type; + std::copy_n(MimeType, MimeTypeLen, MimeTypeBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVOutputFormatMimeType::body(const Runtime::CallingFrame &Frame, + uint32_t AVOutputFormatId, + uint32_t MimeTypePtr, + uint32_t MimeTypeLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(MimeTypeBuf, MemInst, char, MimeTypePtr, MimeTypeLen, ""); + FFMPEG_PTR_FETCH(AvOutputFormat, AVOutputFormatId, AVOutputFormat); + + const char *MimeType = AvOutputFormat->mime_type; + std::copy_n(MimeType, MimeTypeLen, MimeTypeBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVOutputFormatFlags::body(const Runtime::CallingFrame &, + uint32_t AVOutputFormatId) { + FFMPEG_PTR_FETCH(AvOutputFormat, AVOutputFormatId, AVOutputFormat); + return AvOutputFormat->flags; +} + +Expect<int32_t> AVInputOutputFormatFree::body(const Runtime::CallingFrame &, + uint32_t AVInputOutputId) { + FFMPEG_PTR_DELETE(AVInputOutputId); + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avformat/avInputOutputFormat.h b/plugins/wasmedge_ffmpeg/avformat/avInputOutputFormat.h new file mode 100644 index 000000000000..8f01ba9d8943 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avInputOutputFormat.h @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +class AVIOFormatNameLength : public HostFunction<AVIOFormatNameLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AVIOFormatId, + uint32_t FormatType); +}; + +class AVInputFormatName : public HostFunction<AVInputFormatName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t NamePtr, + uint32_t NameLen); +}; + +class AVOutputFormatName : public HostFunction<AVOutputFormatName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t NamePtr, + uint32_t NameLen); +}; + +class AVIOFormatLongNameLength : public HostFunction<AVIOFormatLongNameLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AVIOFormatId, + uint32_t FormatType); +}; + +class AVInputFormatLongName : public HostFunction<AVInputFormatLongName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t LongNamePtr, + uint32_t LongNameLen); +}; + +class AVOutputFormatLongName : public HostFunction<AVOutputFormatLongName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t LongNamePtr, + uint32_t LongNameLen); +}; + +class AVIOFormatExtensionsLength + : public HostFunction<AVIOFormatExtensionsLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AVIOFormatId, + uint32_t FormatType); +}; + +class AVInputFormatExtensions : public HostFunction<AVInputFormatExtensions> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t Extensions, + uint32_t ExtensionsLen); +}; + +class AVOutputFormatExtensions : public HostFunction<AVOutputFormatExtensions> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t Extensions, + uint32_t ExtensionsLen); +}; + +class AVIOFormatMimeTypeLength : public HostFunction<AVIOFormatMimeTypeLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AVIOFormatId, + uint32_t FormatType); +}; + +class AVInputFormatMimeType : public HostFunction<AVInputFormatMimeType> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t MimeTypePtr, + uint32_t MimeTypeLen); +}; + +class AVOutputFormatMimeType : public HostFunction<AVOutputFormatMimeType> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t MimeTypePtr, + uint32_t MimeTypeLen); +}; + +class AVOutputFormatFlags : public HostFunction<AVOutputFormatFlags> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId); +}; + +class AVInputOutputFormatFree : public HostFunction<AVInputOutputFormatFree> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVInputOutputId); +}; + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avformat/avStream.cpp b/plugins/wasmedge_ffmpeg/avformat/avStream.cpp new file mode 100644 index 000000000000..6f1c60ce79aa --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avStream.cpp @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avStream.h" + +extern "C" { +#include "libavformat/avformat.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +Expect<int32_t> AVStreamId::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, uint32_t StreamIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVStream **AvStream = AvFormatContext->streams; + + // No check here (Check) + // Raw Pointer Iteration. + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + return static_cast<AVStream *>(*AvStream)->id; +} + +Expect<int32_t> AVStreamIndex::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t StreamIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVStream **AvStream = AvFormatContext->streams; + + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + return static_cast<AVStream *>(*AvStream)->index; +} + +Expect<int32_t> AVStreamCodecPar::body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, + uint32_t StreamIdx, + uint32_t CodecParameterPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(CodecParamId, MemInst, uint32_t, CodecParameterPtr, + "Failed when accessing the return CodecParameter Memory"sv); + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVStream **AvStream = AvFormatContext->streams; + + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + AVCodecParameters *CodecParam = + (static_cast<AVStream *>(*AvStream))->codecpar; + FFMPEG_PTR_STORE(CodecParam, CodecParamId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVStreamTimebase::body(const Runtime::CallingFrame &Frame, + uint32_t NumPtr, uint32_t DenPtr, + uint32_t AvFormatCtxId, + uint32_t StreamIdx) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(Num, MemInst, int32_t, NumPtr, ""); + MEM_PTR_CHECK(Den, MemInst, int32_t, DenPtr, ""); + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVStream **AvStream = AvFormatContext->streams; + + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + AVRational const AvRational = static_cast<AVStream *>(*AvStream)->time_base; + *Num = AvRational.num; + *Den = AvRational.den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVStreamSetTimebase::body(const Runtime::CallingFrame &, + uint32_t Num, uint32_t Den, + uint32_t AvFormatCtxId, + uint32_t StreamIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + + AVStream **AvStream = AvFormatContext->streams; + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + AVRational const Timebase = av_make_q(Num, Den); + (*AvStream)->time_base = Timebase; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int64_t> AVStreamDuration::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t StreamIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVStream **AvStream = AvFormatContext->streams; + + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + return static_cast<AVStream *>(*AvStream)->duration; +} + +Expect<int64_t> AVStreamStartTime::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t StreamIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVStream **AvStream = AvFormatContext->streams; + + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + return static_cast<AVStream *>(*AvStream)->start_time; +} + +Expect<int64_t> AVStreamNbFrames::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t StreamIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVStream **AvStream = AvFormatContext->streams; + + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + return static_cast<AVStream *>(*AvStream)->nb_frames; +} + +Expect<int32_t> AVStreamDisposition::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t StreamIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + + AVStream **AvStream = AvFormatContext->streams; + + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + return static_cast<AVStream *>(*AvStream)->disposition; +} + +Expect<int32_t> AVStreamRFrameRate::body(const Runtime::CallingFrame &Frame, + uint32_t NumPtr, uint32_t DenPtr, + uint32_t AvFormatCtxId, + uint32_t StreamIdx) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(Num, MemInst, int32_t, NumPtr, ""); + MEM_PTR_CHECK(Den, MemInst, int32_t, DenPtr, ""); + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVStream **AvStream = AvFormatContext->streams; + + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + AVRational const AvRational = + static_cast<AVStream *>(*AvStream)->r_frame_rate; + *Num = AvRational.num; + *Den = AvRational.den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVStreamSetRFrameRate::body(const Runtime::CallingFrame &, + int32_t Num, int32_t Den, + uint32_t AvFormatCtxId, + uint32_t StreamIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + + AVStream **AvStream = AvFormatContext->streams; + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + AVRational const RFrameRate = av_make_q(Num, Den); + (*AvStream)->r_frame_rate = RFrameRate; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVStreamAvgFrameRate::body(const Runtime::CallingFrame &Frame, + uint32_t NumPtr, uint32_t DenPtr, + uint32_t AvFormatCtxId, + uint32_t StreamIdx) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(Num, MemInst, int32_t, NumPtr, ""); + MEM_PTR_CHECK(Den, MemInst, int32_t, DenPtr, ""); + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVStream **AvStream = AvFormatContext->streams; + + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + AVRational const AvRational = + static_cast<AVStream *>(*AvStream)->avg_frame_rate; + *Num = AvRational.num; + *Den = AvRational.den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVStreamSetAvgFrameRate::body(const Runtime::CallingFrame &, + int32_t Num, int32_t Den, + uint32_t AvFormatCtxId, + uint32_t StreamIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + + AVStream **AvStream = AvFormatContext->streams; + + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + AVRational const AvgFrameRate = av_make_q(Num, Den); + (*AvStream)->avg_frame_rate = AvgFrameRate; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVStreamMetadata::body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, + uint32_t StreamIdx, uint32_t DictPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(DictId, MemInst, uint32_t, DictPtr, + "Failed when accessing the return AVDictPtr Memory"sv); + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + + AVStream **AvStream = AvFormatContext->streams; + + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + AVDictionary **AvDictionary = + static_cast<AVDictionary **>(av_malloc(sizeof(AVDictionary *))); + + *AvDictionary = (*AvStream)->metadata; + FFMPEG_PTR_STORE(AvDictionary, DictId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVStreamSetMetadata::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t StreamIdx, uint32_t DictId) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + FFMPEG_PTR_FETCH(AvDictionary, DictId, AVDictionary *); + + AVStream **AvStream = AvFormatContext->streams; + + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + if (AvDictionary == nullptr) { + (*AvStream)->metadata = nullptr; + } else { + (*AvStream)->metadata = *AvDictionary; + } + + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVStreamDiscard::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t StreamIdx) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AVStream **AvStream = AvFormatContext->streams; + + for (unsigned int I = 1; I <= StreamIdx; I++) { + AvStream++; + } + + return static_cast<int32_t>((*AvStream)->discard); +} + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avformat/avStream.h b/plugins/wasmedge_ffmpeg/avformat/avStream.h new file mode 100644 index 000000000000..282d23b04529 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avStream.h @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +class AVStreamId : public HostFunction<AVStreamId> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamIndex : public HostFunction<AVStreamIndex> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamCodecPar : public HostFunction<AVStreamCodecPar> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx, + uint32_t CodecParameterPtr); +}; + +class AVStreamTimebase : public HostFunction<AVStreamTimebase> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t NumPtr, + uint32_t DenPtr, uint32_t AvFormatCtxId, + uint32_t StreamIdx); +}; + +class AVStreamSetTimebase : public HostFunction<AVStreamSetTimebase> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t Num, + uint32_t Den, uint32_t AvFormatCtxId, + uint32_t StreamIdx); +}; + +class AVStreamDuration : public HostFunction<AVStreamDuration> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamStartTime : public HostFunction<AVStreamStartTime> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamNbFrames : public HostFunction<AVStreamNbFrames> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamDisposition : public HostFunction<AVStreamDisposition> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamRFrameRate : public HostFunction<AVStreamRFrameRate> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t NumPtr, + uint32_t DenPtr, uint32_t AvFormatCtxId, + uint32_t StreamIdx); +}; + +class AVStreamSetRFrameRate : public HostFunction<AVStreamSetRFrameRate> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t Num, + int32_t Den, uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamAvgFrameRate : public HostFunction<AVStreamAvgFrameRate> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t NumPtr, + uint32_t DenPtr, uint32_t AvFormatCtxId, + uint32_t StreamIdx); +}; + +class AVStreamSetAvgFrameRate : public HostFunction<AVStreamSetAvgFrameRate> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t Num, + int32_t Den, uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamMetadata : public HostFunction<AVStreamMetadata> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx, + uint32_t DictPtr); +}; + +class AVStreamSetMetadata : public HostFunction<AVStreamSetMetadata> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx, + uint32_t DictId); +}; + +class AVStreamDiscard : public HostFunction<AVStreamDiscard> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avformat/avformatContext.cpp b/plugins/wasmedge_ffmpeg/avformat/avformatContext.cpp new file mode 100644 index 000000000000..6ab0e259a7db --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avformatContext.cpp @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avformatContext.h" + +extern "C" { +#include "libavformat/avformat.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +Expect<int32_t> AVFormatCtxIFormat::body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, + uint32_t AvInputFormatPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(AvInputFormatId, MemInst, uint32_t, AvInputFormatPtr, + "Failed when accessing the return AVInputFormat Memory"sv); + + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + + AVInputFormat const *AvInputFormat = AvFormatCtx->iformat; + FFMPEG_PTR_STORE(const_cast<AVInputFormat *>(AvInputFormat), AvInputFormatId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFormatCtxOFormat::body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, + uint32_t AvOutputFormatPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(AvOutputFormatId, MemInst, uint32_t, AvOutputFormatPtr, + "Failed when accessing the return AVOutputFormat Memory"sv); + + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + + AVOutputFormat const *AvOutputFormat = AvFormatCtx->oformat; + FFMPEG_PTR_STORE(const_cast<AVOutputFormat *>(AvOutputFormat), + AvOutputFormatId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFormatCtxProbeScore::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return AvFormatContext->probe_score; +} + +Expect<uint32_t> AVFormatCtxNbStreams::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return AvFormatContext->nb_streams; +}; + +Expect<int64_t> AVFormatCtxBitRate::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return AvFormatContext->bit_rate; +} + +Expect<int64_t> AVFormatCtxDuration::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return AvFormatContext->duration; +} + +Expect<uint32_t> AVFormatCtxNbChapters::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return AvFormatContext->nb_chapters; +} + +Expect<int32_t> AVFormatCtxSetNbChapters::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t NbChapters) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AvFormatContext->nb_chapters = NbChapters; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFormatCtxMetadata::body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, + uint32_t DictPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(DictId, MemInst, uint32_t, DictPtr, + "Failed when accessing the return AVDictionary memory"sv); + + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + + AVDictionary **AvDictionary = + static_cast<AVDictionary **>(av_malloc(sizeof(AVDictionary *))); + + *AvDictionary = AvFormatCtx->metadata; + FFMPEG_PTR_STORE(AvDictionary, DictId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFormatCtxSetMetadata::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t DictId) { + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + FFMPEG_PTR_FETCH(AvDictionary, DictId, AVDictionary *); + + if (AvDictionary == nullptr) { + AvFormatCtx->metadata = nullptr; + } else { + AvFormatCtx->metadata = *AvDictionary; + } + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avformat/avformatContext.h b/plugins/wasmedge_ffmpeg/avformat/avformatContext.h new file mode 100644 index 000000000000..a0d3b1b202b5 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avformatContext.h @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +class AVFormatCtxIFormat : public HostFunction<AVFormatCtxIFormat> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t AvInputFormatPtr); +}; + +class AVFormatCtxOFormat : public HostFunction<AVFormatCtxOFormat> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t AvOutputFormatPtr); +}; + +class AVFormatCtxProbeScore : public HostFunction<AVFormatCtxProbeScore> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatCtxNbStreams : public HostFunction<AVFormatCtxNbStreams> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatCtxBitRate : public HostFunction<AVFormatCtxBitRate> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatCtxDuration : public HostFunction<AVFormatCtxDuration> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatCtxNbChapters : public HostFunction<AVFormatCtxNbChapters> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatCtxSetNbChapters : public HostFunction<AVFormatCtxSetNbChapters> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t NbChapters); +}; + +class AVFormatCtxMetadata : public HostFunction<AVFormatCtxMetadata> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t DictPtr); +}; + +class AVFormatCtxSetMetadata : public HostFunction<AVFormatCtxSetMetadata> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t DictId); +}; + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avformat/avformat_func.cpp b/plugins/wasmedge_ffmpeg/avformat/avformat_func.cpp new file mode 100644 index 000000000000..3563708784dc --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avformat_func.cpp @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avformat_func.h" + +extern "C" { +#include "libavcodec/packet.h" +#include "libavformat/avformat.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +Expect<int32_t> AVFormatOpenInput::body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxPtr, + uint32_t UrlPtr, uint32_t UrlSize, + uint32_t AvInputFormatId, + uint32_t AvDictionaryId) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(urlId, MemInst, char, UrlPtr, + "Failed when accessing the return URL memory"sv); + MEM_PTR_CHECK(AvFormatCtxId, MemInst, uint32_t, AvFormatCtxPtr, + "Failed when accessing the return AVFormatContext Memory"sv); + + std::string TargetUrl; + std::copy_n(urlId, UrlSize, std::back_inserter(TargetUrl)); + + AVFormatContext *AvFormatContext = nullptr; + FFMPEG_PTR_FETCH(AvDictionary, AvDictionaryId, AVDictionary *); + FFMPEG_PTR_FETCH(AvInputFormat, AvInputFormatId, AVInputFormat); + + int const Res = avformat_open_input(&AvFormatContext, TargetUrl.c_str(), + AvInputFormat, AvDictionary); + FFMPEG_PTR_STORE(AvFormatContext, AvFormatCtxId); + return Res; +} + +Expect<int32_t> AVFormatFindStreamInfo::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t AvDictionaryId) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + FFMPEG_PTR_FETCH(AvDictionary, AvDictionaryId, AVDictionary *); + return avformat_find_stream_info(AvFormatContext, AvDictionary); +} + +Expect<int32_t> AVFormatCloseInput::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + avformat_close_input(&AvFormatCtx); + FFMPEG_PTR_DELETE(AvFormatCtxId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVReadPause::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return av_read_pause(AvFormatContext); +} + +Expect<int32_t> AVReadPlay::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return av_read_play(AvFormatContext); +} + +Expect<int32_t> AVFormatSeekFile::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t StreamIdx, int64_t MinTs, + int64_t Ts, int64_t MaxTs, + int32_t Flags) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return avformat_seek_file(AvFormatContext, StreamIdx, MinTs, Ts, MaxTs, + Flags); +} + +Expect<int32_t> AVDumpFormat::body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, int32_t Idx, + uint32_t UrlPtr, uint32_t UrlSize, + int32_t IsOutput) { + std::string TargetUrl; + + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(UrlBuf, MemInst, char, UrlPtr, ""); + + std::copy_n(UrlBuf, UrlSize, std::back_inserter(TargetUrl)); + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + + av_dump_format(AvFormatCtx, Idx, TargetUrl.c_str(), IsOutput); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFormatFreeContext::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + avformat_free_context(AvFormatCtx); + FFMPEG_PTR_DELETE(AvFormatCtxId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFindBestStream::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + int32_t MediaTypeId, + int32_t WantedStream, + int32_t RelatedStream, + uint32_t DecoderRetId, int32_t Flags) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + FFMPEG_PTR_FETCH(DecoderRet, DecoderRetId, const AVCodec *); + + AVMediaType const AvMediaType = + FFmpegUtils::MediaType::intoMediaType(MediaTypeId); + return av_find_best_stream(AvFormatContext, AvMediaType, WantedStream, + RelatedStream, DecoderRet, Flags); +} + +Expect<int32_t> AVReadFrame::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, uint32_t PacketId) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + FFMPEG_PTR_FETCH(AvPacket, PacketId, AVPacket); + + return av_read_frame(AvFormatContext, AvPacket); +} + +Expect<int32_t> AVIOClose::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + avio_close(AvFormatCtx->pb); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFormatNetworkInit::body(const Runtime::CallingFrame &) { + return avformat_network_init(); +} + +Expect<int32_t> AVFormatNetworkDeInit::body(const Runtime::CallingFrame &) { + return avformat_network_deinit(); +} + +Expect<int32_t> AVFormatWriteHeader::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t DictId) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + FFMPEG_PTR_FETCH(AvDict, DictId, AVDictionary *); + return avformat_write_header(AvFormatContext, AvDict); +} + +Expect<int32_t> AVFormatWriteTrailer::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return av_write_trailer(AvFormatContext); +} + +Expect<int32_t> AVFormatAllocOutputContext2::body( + const Runtime::CallingFrame &Frame, uint32_t AvFormatCtxPtr, + uint32_t AVOutputFormatId, uint32_t FormatNamePtr, uint32_t FormatLen, + uint32_t FileNamePtr, uint32_t FileNameLen) { + std::string Format; + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(FileId, MemInst, char, FileNamePtr, + "Failed when accessing the return FileName memory"sv); + if (FormatLen > 0) { + MEM_PTR_CHECK(FormatId, MemInst, char, FormatNamePtr, + "Failed when accessing the return FormatName memory"sv); + + std::copy_n(FormatId, FormatLen, std::back_inserter(Format)); + } + MEM_PTR_CHECK(AvFormatCtxId, MemInst, uint32_t, AvFormatCtxPtr, + "Failed when accessing the return AVFormatContext Memory"sv); + + std::string File; + std::copy_n(FileId, FileNameLen, std::back_inserter(File)); + + AVFormatContext *AvFormatContext = nullptr; + FFMPEG_PTR_FETCH(AvOutputFormat, AVOutputFormatId, AVOutputFormat); + + int Res = 0; + if (FormatLen == 0) { + Res = avformat_alloc_output_context2(&AvFormatContext, AvOutputFormat, + nullptr, File.c_str()); + } else { + Res = avformat_alloc_output_context2(&AvFormatContext, AvOutputFormat, + Format.c_str(), File.c_str()); + } + FFMPEG_PTR_STORE(AvFormatContext, AvFormatCtxId); + return Res; +} + +Expect<int32_t> AVIOOpen::body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t FileNamePtr, + uint32_t FileNameLen, int32_t Flags) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(FileId, MemInst, char, FileNamePtr, + "Failed when accessing the return FileName memory"sv); + + std::string File; + std::copy_n(FileId, FileNameLen, std::back_inserter(File)); + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + + return avio_open(&(AvFormatContext->pb), File.c_str(), Flags); +} + +Expect<int32_t> AVIOOpen2::body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxtId, uint32_t UrlPtr, + uint32_t UrlLen, int32_t Flags, + uint32_t AVIOInterruptCBId, + uint32_t AVDictionaryId) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(UrlId, MemInst, char, UrlPtr, + "Failed when accessing the return Url memory"sv); + + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxtId, AVFormatContext); + FFMPEG_PTR_FETCH(AvDictionary, AVDictionaryId, AVDictionary *); + FFMPEG_PTR_FETCH(AvIOInterruptCB, AVIOInterruptCBId, AVIOInterruptCB); + + std::string TargetUrl; + std::copy_n(UrlId, UrlLen, std::back_inserter(TargetUrl)); + + return avio_open2(&(AvFormatCtx->pb), TargetUrl.c_str(), Flags, + AvIOInterruptCB, AvDictionary); +} + +Expect<uint32_t> AVFormatVersion::body(const Runtime::CallingFrame &) { + return avformat_version(); +} + +Expect<int32_t> AVChapterMallocz::body(const Runtime::CallingFrame &Frame, + uint32_t AVChapterPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(AvChapterId, MemInst, uint32_t, AVChapterPtr, + "Failed to access Memory for AVChapterPtr"sv) + + AVChapter *AvChapter = + static_cast<AVChapter *>(av_mallocz(sizeof(AVChapter))); + FFMPEG_PTR_STORE(AvChapter, AvChapterId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVChapterDynarrayAdd::body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, + int32_t NbChaptersPtr, + uint32_t AvChapterId) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(NbChapters, MemInst, int32_t, NbChaptersPtr, + "Failed to access Memory for NbChaptersPtr"sv) + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + FFMPEG_PTR_FETCH(AvChapter, AvChapterId, AVChapter); + + av_dynarray_add(&(AvFormatContext->chapters), NbChapters, AvChapter); + if (*(AvFormatContext->chapters) == nullptr && *(NbChapters) == 0) { + return static_cast<int32_t>(ErrNo::InternalError); + } + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFreeP::body(const Runtime::CallingFrame &, + uint32_t AvChapterId) { + FFMPEG_PTR_FETCH(AvChapter, AvChapterId, AVChapter); + av_freep(AvChapter); + FFMPEG_PTR_DELETE(AvChapterId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVInterleavedWriteFrame::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t AvPacketId) { + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + + return av_interleaved_write_frame(AvFormatCtx, AvPacket); +} + +Expect<int32_t> AVWriteFrame::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t AvPacketId) { + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + + return av_write_frame(AvFormatCtx, AvPacket); +} + +Expect<int32_t> AVFormatNewStream::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t AvCodecId) { + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + AVStream *Stream = avformat_new_stream(AvFormatCtx, AvCodec); + if (Stream == nullptr) { + return 0; + } + return 1; +} + +Expect<uint32_t> AVGuessCodec::body(const Runtime::CallingFrame &Frame, + uint32_t AVIOFormatId, + uint32_t ShortNamePtr, + uint32_t ShortNameLen, uint32_t FileNamePtr, + uint32_t FileNameLen, uint32_t MimeTypePtr, + uint32_t MimeTypeLen, int32_t MediaTypeId) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(ShortNameBuf, MemInst, char, ShortNamePtr, + "Failed when accessing the return ShortName memory"sv); + MEM_PTR_CHECK(FileNameBuf, MemInst, char, FileNamePtr, + "Failed when accessing the return FileName memory"sv); + MEM_PTR_CHECK(MimeTypeBuf, MemInst, char, MimeTypePtr, + "Failed when accessing the return MimeType memory"sv); + FFMPEG_PTR_FETCH(AvOutputFormat, AVIOFormatId, AVOutputFormat); + + std::string ShortName; + std::string FileName; + std::string MimeType; + std::copy_n(ShortNameBuf, ShortNameLen, std::back_inserter(ShortName)); + std::copy_n(FileNameBuf, FileNameLen, std::back_inserter(FileName)); + std::copy_n(MimeTypeBuf, MimeTypeLen, std::back_inserter(MimeType)); + + AVMediaType const MediaType = + FFmpegUtils::MediaType::intoMediaType(MediaTypeId); + AVCodecID const Id = + av_guess_codec(AvOutputFormat, ShortName.c_str(), FileName.c_str(), + MimeType.c_str(), MediaType); + + return FFmpegUtils::CodecID::fromAVCodecID(Id); +} + +Expect<int32_t> +AVFormatConfigurationLength::body(const Runtime::CallingFrame &) { + const char *Config = avformat_configuration(); + return strlen(Config); +} + +Expect<int32_t> AVFormatConfiguration::body(const Runtime::CallingFrame &Frame, + uint32_t ConfigPtr, + uint32_t ConfigLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(ConfigBuf, MemInst, char, ConfigPtr, ConfigLen, ""); + + const char *Config = avformat_configuration(); + std::copy_n(Config, ConfigLen, ConfigBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFormatLicenseLength::body(const Runtime::CallingFrame &) { + const char *License = avformat_license(); + return strlen(License); +} + +Expect<int32_t> AVFormatLicense::body(const Runtime::CallingFrame &Frame, + uint32_t LicensePtr, + uint32_t LicenseLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(LicenseBuf, MemInst, char, LicensePtr, LicenseLen, ""); + + const char *License = avformat_license(); + std::copy_n(License, LicenseLen, LicenseBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avformat/avformat_func.h b/plugins/wasmedge_ffmpeg/avformat/avformat_func.h new file mode 100644 index 000000000000..533017b6b572 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avformat_func.h @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +class AVFormatOpenInput : public HostFunction<AVFormatOpenInput> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxPtr, uint32_t UrlPtr, + uint32_t UrlSize, uint32_t AvInputFormatId, + uint32_t AvDictionaryId); +}; + +class AVFormatFindStreamInfo : public HostFunction<AVFormatFindStreamInfo> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId, + uint32_t AvDictionaryId); +}; + +class AVFormatCloseInput : public HostFunction<AVFormatCloseInput> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVReadPause : public HostFunction<AVReadPause> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId); +}; + +class AVReadPlay : public HostFunction<AVReadPlay> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId); +}; + +class AVFormatSeekFile : public HostFunction<AVFormatSeekFile> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId, + uint32_t StreamIdx, int64_t MinTs, int64_t Ts, + int64_t MaxTs, int32_t Flags); +}; + +class AVDumpFormat : public HostFunction<AVDumpFormat> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, int32_t Idx, uint32_t UrlPtr, + uint32_t UrlSize, int32_t IsOutput); +}; + +class AVFormatFreeContext : public HostFunction<AVFormatFreeContext> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxPtr); +}; + +class AVFindBestStream : public HostFunction<AVFindBestStream> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId, + int32_t MediaTypeId, int32_t WantedStream, + int32_t RelatedStream, uint32_t DecoderRetId, + int32_t Flags); +}; + +class AVReadFrame : public HostFunction<AVReadFrame> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId, + uint32_t PacketId); +}; + +class AVIOClose : public HostFunction<AVIOClose> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatNetworkInit : public HostFunction<AVFormatNetworkInit> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVFormatNetworkDeInit : public HostFunction<AVFormatNetworkDeInit> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVFormatWriteHeader : public HostFunction<AVFormatWriteHeader> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t DictId); +}; + +class AVFormatWriteTrailer : public HostFunction<AVFormatWriteTrailer> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatAllocOutputContext2 + : public HostFunction<AVFormatAllocOutputContext2> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxPtr, uint32_t AVOutputFormatId, + uint32_t FormatNamePtr, uint32_t FormatLen, + uint32_t FileNamePtr, uint32_t FileNameLen); +}; + +class AVIOOpen : public HostFunction<AVIOOpen> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t FileNamePtr, + uint32_t FileNameLen, int32_t Flags); +}; + +class AVIOOpen2 : public HostFunction<AVIOOpen2> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxtId, uint32_t UrlPtr, + uint32_t UrlLen, int32_t Flags, + uint32_t AVIOInterruptCBId, uint32_t AVDictionaryId); +}; + +class AVFormatVersion : public HostFunction<AVFormatVersion> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVChapterMallocz : public HostFunction<AVChapterMallocz> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVChapterPtr); +}; + +class AVChapterDynarrayAdd : public HostFunction<AVChapterDynarrayAdd> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId, + int32_t NbChaptersPtr, uint32_t AvChapterId); +}; + +class AVFreeP : public HostFunction<AVFreeP> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AvChapterId); +}; + +class AVInterleavedWriteFrame : public HostFunction<AVInterleavedWriteFrame> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId, + uint32_t AvPacketId); +}; + +class AVWriteFrame : public HostFunction<AVWriteFrame> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId, + uint32_t AvPacketId); +}; + +class AVFormatNewStream : public HostFunction<AVFormatNewStream> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVFormatCtxId, uint32_t AVCodecId); +}; + +class AVGuessCodec : public HostFunction<AVGuessCodec> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AVInputOutputId, uint32_t ShortNamePtr, + uint32_t ShortNameLen, uint32_t FileNamePtr, + uint32_t FileNameLen, uint32_t MimeTypePtr, + uint32_t MimeTypeLen, int32_t MediaTypeId); +}; + +class AVFormatConfigurationLength + : public HostFunction<AVFormatConfigurationLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVFormatConfiguration : public HostFunction<AVFormatConfiguration> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class AVFormatLicenseLength : public HostFunction<AVFormatLicenseLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVFormatLicense : public HostFunction<AVFormatLicense> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t LicensePtr, + uint32_t LicenseLen); +}; + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avformat/module.cpp b/plugins/wasmedge_ffmpeg/avformat/module.cpp new file mode 100644 index 000000000000..1246beff9add --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/module.cpp @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "module.h" +#include "avChapter.h" +#include "avInputOutputFormat.h" +#include "avStream.h" +#include "avformatContext.h" +#include "avformat_func.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +WasmEdgeFFmpegAVFormatModule::WasmEdgeFFmpegAVFormatModule( + std::shared_ptr<WasmEdgeFFmpegEnv> Env) + : ModuleInstance("wasmedge_ffmpeg_avformat") { + // avformat_func.h + addHostFunc("wasmedge_ffmpeg_avformat_avformat_open_input", + std::make_unique<AVFormatOpenInput>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_find_stream_info", + std::make_unique<AVFormatFindStreamInfo>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_close_input", + std::make_unique<AVFormatCloseInput>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_read_play", + std::make_unique<AVReadPlay>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_read_pause", + std::make_unique<AVReadPause>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_dump_format", + std::make_unique<AVDumpFormat>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_seek_file", + std::make_unique<AVFormatSeekFile>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_free_context", + std::make_unique<AVFormatFreeContext>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_find_best_stream", + std::make_unique<AVFindBestStream>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_read_frame", // TODO: Write Test + std::make_unique<AVReadFrame>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avio_close", + std::make_unique<AVIOClose>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_network_init", + std::make_unique<AVFormatNetworkInit>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_network_deinit", + std::make_unique<AVFormatNetworkDeInit>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_write_header", + std::make_unique<AVFormatWriteHeader>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_write_trailer", + std::make_unique<AVFormatWriteTrailer>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_alloc_output_context2", + std::make_unique<AVFormatAllocOutputContext2>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avio_open", + std::make_unique<AVIOOpen>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avio_open2", + std::make_unique<AVIOOpen2>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avchapter_mallocz", + std::make_unique<AVChapterMallocz>(Env)); + addHostFunc( + "wasmedge_ffmpeg_avformat_avchapter_dynarray_add", // TODO: Write Test + std::make_unique<AVChapterDynarrayAdd>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_avfreep", + std::make_unique<AVFreeP>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_version", + std::make_unique<AVFormatVersion>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_write_frame", + std::make_unique<AVWriteFrame>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_interleaved_write_frame", + std::make_unique<AVInterleavedWriteFrame>(Env)); + addHostFunc( + "wasmedge_ffmpeg_avformat_avformat_new_stream", // TODO: Write Test + std::make_unique<AVFormatNewStream>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_guess_codec", // TODO: Write Test + std::make_unique<AVGuessCodec>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_configuration_length", + std::make_unique<AVFormatConfigurationLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_configuration", + std::make_unique<AVFormatConfiguration>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_license_length", + std::make_unique<AVFormatLicenseLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_license", + std::make_unique<AVFormatLicense>(Env)); + + // avformatContext Struct functions. + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_iformat", + std::make_unique<AVFormatCtxIFormat>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_oformat", + std::make_unique<AVFormatCtxOFormat>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_probescope", + std::make_unique<AVFormatCtxProbeScore>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_nb_streams", + std::make_unique<AVFormatCtxNbStreams>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_duration", + std::make_unique<AVFormatCtxDuration>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_bit_rate", + std::make_unique<AVFormatCtxBitRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_nb_chapters", + std::make_unique<AVFormatCtxNbChapters>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_set_nb_chapters", + std::make_unique<AVFormatCtxSetNbChapters>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_metadata", + std::make_unique<AVFormatCtxMetadata>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_set_metadata", + std::make_unique<AVFormatCtxSetMetadata>(Env)); + + // avInputFormat Struct functions. + addHostFunc("wasmedge_ffmpeg_avformat_avIOFormat_name_length", + std::make_unique<AVIOFormatNameLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avInputFormat_name", + std::make_unique<AVInputFormatName>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avOutputFormat_name", + std::make_unique<AVOutputFormatName>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avIOFormat_long_name_length", + std::make_unique<AVIOFormatLongNameLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avInputFormat_long_name", + std::make_unique<AVInputFormatLongName>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avOutputFormat_long_name", + std::make_unique<AVOutputFormatExtensions>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avIOFormat_extensions_length", + std::make_unique<AVIOFormatExtensionsLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avInputFormat_extensions", + std::make_unique<AVInputFormatExtensions>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avOutputFormat_extensions", + std::make_unique<AVOutputFormatExtensions>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avIOFormat_mime_type_length", + std::make_unique<AVIOFormatMimeTypeLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avInputFormat_mime_type", + std::make_unique<AVInputFormatMimeType>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avOutputFormat_mime_type", + std::make_unique<AVOutputFormatMimeType>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avOutputFormat_flags", + std::make_unique<AVOutputFormatFlags>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avInputOutputFormat_free", + std::make_unique<AVInputOutputFormatFree>(Env)); + + // avStream Struct Functions. + addHostFunc("wasmedge_ffmpeg_avformat_avStream_id", + std::make_unique<AVStreamId>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_index", + std::make_unique<AVStreamIndex>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_codecpar", + std::make_unique<AVStreamCodecPar>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_timebase", + std::make_unique<AVStreamTimebase>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_set_timebase", + std::make_unique<AVStreamSetTimebase>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_duration", + std::make_unique<AVStreamDuration>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_start_time", + std::make_unique<AVStreamStartTime>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_nb_frames", + std::make_unique<AVStreamNbFrames>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_disposition", + std::make_unique<AVStreamDisposition>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_r_frame_rate", + std::make_unique<AVStreamRFrameRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_set_r_frame_rate", + std::make_unique<AVStreamSetRFrameRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_avg_frame_rate", + std::make_unique<AVStreamAvgFrameRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_set_avg_frame_rate", + std::make_unique<AVStreamSetAvgFrameRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_metadata", + std::make_unique<AVStreamMetadata>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_set_metadata", + std::make_unique<AVStreamSetMetadata>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_discard", + std::make_unique<AVStreamDiscard>(Env)); + + // avChapter Struct Functions. + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_id", + std::make_unique<AVChapterId>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_set_id", + std::make_unique<AVChapterSetId>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_timebase", + std::make_unique<AVChapterTimebase>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_set_timebase", + std::make_unique<AVChapterSetTimebase>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_start", + std::make_unique<AVChapterStart>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_set_start", + std::make_unique<AVChapterSetStart>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_end", + std::make_unique<AVChapterEnd>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_set_end", + std::make_unique<AVChapterSetEnd>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_metadata", + std::make_unique<AVChapterMetadata>(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_set_metadata", + std::make_unique<AVChapterSetMetadata>(Env)); +} + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avformat/module.h b/plugins/wasmedge_ffmpeg/avformat/module.h new file mode 100644 index 000000000000..47b604d96100 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/module.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_env.h" + +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +class WasmEdgeFFmpegAVFormatModule : public Runtime::Instance::ModuleInstance { +public: + WasmEdgeFFmpegAVFormatModule(std::shared_ptr<WasmEdgeFFmpegEnv> Env); +}; + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp b/plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp new file mode 100644 index 000000000000..908c47c6a5ea --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avDictionary.h" + +extern "C" { +#include "libavutil/dict.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect<int32_t> AVDictSet::body(const Runtime::CallingFrame &Frame, + uint32_t DictPtr, uint32_t KeyPtr, + uint32_t KeyLen, uint32_t ValuePtr, + uint32_t ValueLen, int32_t Flags) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(KeyBuf, MemInst, char, KeyPtr, + "Failed when accessing the return Key memory"sv); + MEM_PTR_CHECK(ValueBuf, MemInst, char, ValuePtr, + "Failed when accessing the return Value memory"sv); + MEM_PTR_CHECK(DictId, MemInst, uint32_t, DictPtr, + "Failed to access Memory for AVDict"sv) + + std::string Key; + std::string Value; + std::copy_n(KeyBuf, KeyLen, std::back_inserter(Key)); + std::copy_n(ValueBuf, ValueLen, std::back_inserter(Value)); + + int Res = 0; + + // Using Maybe::uninit(); in Rust. If Uninitialized, zero is + // passed. Else the Ptr contains a Number. + if (*DictId) { + FFMPEG_PTR_FETCH(AvDict, *DictId, AVDictionary *); + Res = av_dict_set(AvDict, Key.c_str(), Value.c_str(), Flags); + } else { + AVDictionary **AvDict = + static_cast<AVDictionary **>(av_mallocz(sizeof(AVDictionary *))); + Res = av_dict_set(AvDict, Key.c_str(), Value.c_str(), Flags); + FFMPEG_PTR_STORE(AvDict, DictId); + } + + return Res; +} + +Expect<int32_t> AVDictCopy::body(const Runtime::CallingFrame &Frame, + uint32_t DestDictPtr, uint32_t SrcDictId, + uint32_t Flags) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(DestDictId, MemInst, uint32_t, DestDictPtr, + "Failed to access Memory for AVDict"sv) + + FFMPEG_PTR_FETCH(SrcAvDict, SrcDictId, AVDictionary *); + + int Res = 0; + + if (SrcAvDict == nullptr) { + return static_cast<int32_t>(ErrNo::InternalError); + } + + if (*DestDictId) { + FFMPEG_PTR_FETCH(DestAvDict, *DestDictId, AVDictionary *); + Res = av_dict_copy(DestAvDict, *SrcAvDict, Flags); + } else { + AVDictionary **DestAvDict = + static_cast<AVDictionary **>(av_mallocz(sizeof(AVDictionary *))); + av_dict_copy(DestAvDict, *SrcAvDict, Flags); + FFMPEG_PTR_STORE(DestAvDict, DestDictId); + } + + return Res; +} + +Expect<int32_t> AVDictGet::body(const Runtime::CallingFrame &Frame, + uint32_t DictId, uint32_t KeyPtr, + uint32_t KeyLen, uint32_t PrevDictEntryIdx, + uint32_t Flags, uint32_t KeyLenPtr, + uint32_t ValueLenPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(KeyStr, MemInst, char, KeyPtr, + "Failed when accessing the return Key memory"sv); + MEM_PTR_CHECK(KeyLenId, MemInst, uint32_t, KeyLenPtr, + "Failed when accessing the return KeyLen memory"sv); + MEM_PTR_CHECK(ValueLenId, MemInst, uint32_t, ValueLenPtr, + "Failed when accessing the return ValueLen memory"sv); + + FFMPEG_PTR_FETCH(AvDict, DictId, AVDictionary *); + + // If Dict Not created return (i.e. 0 is passed as AVDictId) + if (AvDict == nullptr) { + return static_cast<int32_t>(ErrNo::InternalError); + } + std::string Key; + std::copy_n(KeyStr, KeyLen, std::back_inserter(Key)); + + AVDictionaryEntry *DictEntry = nullptr; + uint32_t Curr = 0; + while (Curr <= PrevDictEntryIdx) { + DictEntry = av_dict_get(*AvDict, Key.c_str(), DictEntry, Flags); + Curr++; + } + + if (DictEntry == nullptr) { + return static_cast<int32_t>(ErrNo::InternalError); + } + + *KeyLenId = strlen(DictEntry->key); + *ValueLenId = strlen(DictEntry->value); + return Curr; +} + +Expect<int32_t> AVDictGetKeyValue::body( + const Runtime::CallingFrame &Frame, uint32_t DictId, uint32_t KeyPtr, + uint32_t KeyLen, uint32_t ValBufPtr, uint32_t ValBufLen, uint32_t KeyBufPtr, + uint32_t KeyBufLen, uint32_t PrevDictEntryIdx, uint32_t Flags) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(KeyStr, MemInst, char, KeyPtr, + "Failed when accessing the return Key memory"sv); + MEM_SPAN_CHECK(KeyBuf, MemInst, char, KeyBufPtr, KeyBufLen, ""); + MEM_SPAN_CHECK(ValBuf, MemInst, char, ValBufPtr, ValBufLen, ""); + + FFMPEG_PTR_FETCH(AvDict, DictId, AVDictionary *); + + // If Dict Not created return (i.e. 0 is passed as AVDictId) + if (AvDict == nullptr) { + return static_cast<int32_t>(ErrNo::InternalError); + } + + std::string Key; + std::copy_n(KeyStr, KeyLen, std::back_inserter(Key)); + + AVDictionaryEntry *DictEntry = nullptr; + uint32_t Curr = 0; + while (Curr <= PrevDictEntryIdx) { + DictEntry = av_dict_get(*AvDict, Key.c_str(), DictEntry, Flags); + Curr++; + } + if (DictEntry == nullptr) { + return static_cast<int32_t>(ErrNo::InternalError); + } + std::copy_n(DictEntry->value, strlen(DictEntry->value), ValBuf.data()); + std::copy_n(DictEntry->key, strlen(DictEntry->key), KeyBuf.data()); + return Curr; +} + +Expect<int32_t> AVDictFree::body(const Runtime::CallingFrame &, + uint32_t DictId) { + if (DictId == 0) { + return static_cast<int32_t>(ErrNo::Success); + } + FFMPEG_PTR_FETCH(AvDict, DictId, AVDictionary *); + av_dict_free(AvDict); + FFMPEG_PTR_DELETE(DictId); + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/avDictionary.h b/plugins/wasmedge_ffmpeg/avutil/avDictionary.h new file mode 100644 index 000000000000..c1731a330dd0 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avDictionary.h @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVDictSet : public HostFunction<AVDictSet> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t DictId, + uint32_t KeyPtr, uint32_t KeyLen, uint32_t ValuePtr, + uint32_t ValueLen, int32_t Flags); +}; + +class AVDictGet : public HostFunction<AVDictGet> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t DictId, + uint32_t KeyPtr, uint32_t KeyLen, + uint32_t PrevDictEntryIdx, uint32_t Flags, + uint32_t KeyLenPtr, uint32_t ValueLenPtr); +}; + +class AVDictGetKeyValue : public HostFunction<AVDictGetKeyValue> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t DictId, + uint32_t KeyPtr, uint32_t KeyLen, uint32_t ValBufPtr, + uint32_t ValBufLen, uint32_t KeyBufPtr, + uint32_t KeyBufLen, uint32_t PrevDictEntryIdx, + uint32_t Flags); +}; + +class AVDictCopy : public HostFunction<AVDictCopy> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t DestDictId, + uint32_t SrcDictId, uint32_t Flags); +}; + +class AVDictFree : public HostFunction<AVDictFree> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t DictId); +}; + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/avFrame.cpp b/plugins/wasmedge_ffmpeg/avutil/avFrame.cpp new file mode 100644 index 000000000000..2dc1449b3195 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avFrame.cpp @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avFrame.h" + +extern "C" { +#include "libavutil/frame.h" +#include "libavutil/pixfmt.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect<int32_t> AVFrameAlloc::body(const Runtime::CallingFrame &Frame, + uint32_t FramePtr) { + MEMINST_CHECK(MemInst, Frame, 0) + MEM_PTR_CHECK(FrameId, MemInst, uint32_t, FramePtr, + "Failed to access Memory for AVFrame"sv) + + AVFrame *AvFrame = av_frame_alloc(); + FFMPEG_PTR_STORE(AvFrame, FrameId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameFree::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + av_frame_free(&AvFrame); + FFMPEG_PTR_DELETE(FrameId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameWidth::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->width; +} + +Expect<int32_t> AVFrameHeight::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->height; +} + +Expect<int32_t> AVFrameSetHeight::body(const Runtime::CallingFrame &, + uint32_t FrameId, uint32_t Height) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->height = Height; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameSetWidth::body(const Runtime::CallingFrame &, + uint32_t FrameId, uint32_t Width) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->width = Width; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameVideoFormat::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + int const Format = AvFrame->format; + if (Format == -1) { + return -1; + } + AVPixelFormat const PixelFormat = static_cast<AVPixelFormat>(Format); + return FFmpegUtils::PixFmt::fromAVPixFmt(PixelFormat); +} + +Expect<uint32_t> AVFrameSetVideoFormat::body(const Runtime::CallingFrame &, + uint32_t FrameId, + uint32_t AvPixFormatId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AVPixelFormat const PixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(AvPixFormatId); + AvFrame->format = PixelFormat; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameIsNull::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->data[0] == nullptr; +} + +Expect<int32_t> AVFrameLinesize::body(const Runtime::CallingFrame &, + uint32_t FrameId, uint32_t Idx) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->linesize[Idx]; +} + +Expect<int32_t> AVFrameData::body(const Runtime::CallingFrame &Frame, + uint32_t FrameId, uint32_t FrameBufPtr, + uint32_t FrameBufLen, uint32_t Index) { + MEMINST_CHECK(MemInst, Frame, 0) + MEM_SPAN_CHECK(Buffer, MemInst, uint8_t, FrameBufPtr, FrameBufLen, ""); + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + + uint8_t *Data = AvFrame->data[Index]; + std::copy_n(Data, FrameBufLen, Buffer.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameGetBuffer::body(const Runtime::CallingFrame &, + uint32_t FrameId, int32_t Align) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return av_frame_get_buffer(AvFrame, Align); +} + +Expect<int32_t> AVFrameAudioFormat::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + int const Format = AvFrame->format; + if (Format == -1) { + return -1; + } + + AVSampleFormat const SampleFormat = static_cast<AVSampleFormat>(Format); + return FFmpegUtils::SampleFmt::toSampleID(SampleFormat); +} + +Expect<int32_t> AVFrameSetAudioFormat::body(const Runtime::CallingFrame &, + uint32_t FrameId, + uint32_t SampleFormatId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AVSampleFormat const SampleFormat = + FFmpegUtils::SampleFmt::fromSampleID(SampleFormatId); + AvFrame->format = SampleFormat; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameSetChannelLayout::body(const Runtime::CallingFrame &, + uint32_t FrameId, + uint64_t ChannelLayoutID) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + uint64_t const ChannelLayout = + FFmpegUtils::ChannelLayout::fromChannelLayoutID(ChannelLayoutID); + AvFrame->channel_layout = ChannelLayout; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameSetNbSamples::body(const Runtime::CallingFrame &, + uint32_t FrameId, int32_t Samples) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->nb_samples = Samples; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameNbSamples::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->nb_samples; +} + +Expect<int32_t> AVFrameSampleRate::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->sample_rate; +} + +Expect<int32_t> AVFrameSetSampleRate::body(const Runtime::CallingFrame &, + uint32_t FrameId, + int32_t SampleRate) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->sample_rate = SampleRate; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameChannels::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->channels; +} + +Expect<int32_t> AVFrameSetChannels::body(const Runtime::CallingFrame &, + uint32_t FrameId, int32_t Channels) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->channels = Channels; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<uint64_t> AVFrameChannelLayout::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + uint64_t const ChannelLayout = AvFrame->channel_layout; + return FFmpegUtils::ChannelLayout::intoChannelLayoutID(ChannelLayout); +} + +Expect<int64_t> AVFrameBestEffortTimestamp::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->best_effort_timestamp; +} + +Expect<int32_t> AVFramePictType::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AVPictureType const AvPictureType = AvFrame->pict_type; + return FFmpegUtils::PictureType::fromAVPictureType(AvPictureType); +} + +Expect<int32_t> AVFrameSetPictType::body(const Runtime::CallingFrame &, + uint32_t FrameId, int32_t PictureId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AVPictureType const AvPictureType = + FFmpegUtils::PictureType::intoAVPictureType(PictureId); + + AvFrame->pict_type = AvPictureType; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameInterlacedFrame::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->interlaced_frame; +} + +Expect<int32_t> AVFrameTopFieldFirst::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->top_field_first; +} + +Expect<int32_t> AVFramePaletteHasChanged::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->palette_has_changed; +} + +Expect<int32_t> AVFrameColorSpace::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AVColorSpace const AvColorSpace = AvFrame->colorspace; + return FFmpegUtils::ColorSpace::fromAVColorSpace(AvColorSpace); +} + +Expect<int32_t> AVFrameSetColorSpace::body(const Runtime::CallingFrame &, + uint32_t FrameId, + int32_t ColorSpaceId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->colorspace = FFmpegUtils::ColorSpace::intoAVColorSpace(ColorSpaceId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameColorRange::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AVColorRange const AvColorRange = AvFrame->color_range; + + return static_cast<int32_t>(AvColorRange); +} + +Expect<int32_t> AVFrameSetColorRange::body(const Runtime::CallingFrame &, + uint32_t FrameId, + int32_t ColorRangeId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->color_range = static_cast<AVColorRange>(ColorRangeId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVFrameColorTransferCharacteristic::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AVColorTransferCharacteristic const Characteristic = AvFrame->color_trc; + + // Can use the binding as well. Currently, Commented the binding. + return static_cast<int32_t>(Characteristic); +} + +Expect<int32_t> AVFrameSetColorTransferCharacteristic::body( + const Runtime::CallingFrame &, uint32_t FrameId, + int32_t ColorTransferCharacteristicId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->color_trc = + static_cast<AVColorTransferCharacteristic>(ColorTransferCharacteristicId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameChromaLocation::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AVChromaLocation const AvChromaLocation = AvFrame->chroma_location; + return FFmpegUtils::ChromaLocation::fromAVChromaLocation(AvChromaLocation); +} + +Expect<int32_t> AVFrameCodedPictureNumber::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->coded_picture_number; +} + +Expect<int32_t> AVFrameDisplayPictureNumber::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->display_picture_number; +} + +Expect<int32_t> AVFrameRepeatPict::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->repeat_pict; +} + +Expect<int32_t> AVFrameFlags::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->flags; +} + +Expect<int32_t> AVFrameQuality::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->quality; +} + +Expect<int32_t> AVFrameMetadata::body(const Runtime::CallingFrame &Frame, + uint32_t FrameId, uint32_t DictPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(DictId, MemInst, uint32_t, DictPtr, + "Failed when accessing the return AVDictionary memory"sv); + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + + AVDictionary **AvDictionary = + static_cast<AVDictionary **>(av_malloc(sizeof(AVDictionary *))); + + *AvDictionary = AvFrame->metadata; + FFMPEG_PTR_STORE(AvDictionary, DictId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameSetMetadata::body(const Runtime::CallingFrame &, + uint32_t FrameId, uint32_t DictId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + FFMPEG_PTR_FETCH(AvDict, DictId, AVDictionary *); + + if (AvDict == nullptr) { + AvFrame->metadata = nullptr; + } else { + AvFrame->metadata = *AvDict; + } + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameKeyFrame::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->key_frame; +} + +Expect<int64_t> AVFramePts::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->pts; +} + +Expect<int32_t> AVFrameSetPts::body(const Runtime::CallingFrame &, + uint32_t FrameId, int64_t Pts) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->pts = Pts; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameCopy::body(const Runtime::CallingFrame &, + uint32_t DestFrameId, uint32_t SrcFrameId) { + FFMPEG_PTR_FETCH(DestAvFrame, DestFrameId, AVFrame); + FFMPEG_PTR_FETCH(SrcAvFrame, SrcFrameId, AVFrame); + + av_frame_copy(DestAvFrame, SrcAvFrame); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameCopyProps::body(const Runtime::CallingFrame &, + uint32_t DestFrameId, + uint32_t SrcFrameId) { + FFMPEG_PTR_FETCH(DestAvFrame, DestFrameId, AVFrame); + FFMPEG_PTR_FETCH(SrcAvFrame, SrcFrameId, AVFrame); + + av_frame_copy_props(DestAvFrame, SrcAvFrame); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +AVFrameSampleAspectRatio::body(const Runtime::CallingFrame &Frame, + uint32_t FrameId, uint32_t NumPtr, + uint32_t DenPtr) { + MEMINST_CHECK(MemInst, Frame, 0) + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + + MEM_PTR_CHECK(Num, MemInst, int32_t, NumPtr, + "Failed to access Numerator Ptr for AVRational"sv); + MEM_PTR_CHECK(Den, MemInst, int32_t, DenPtr, + "Failed to access Denominator Ptr for AVRational"sv); + + AVRational const Rational = AvFrame->sample_aspect_ratio; + *Num = Rational.num; + *Den = Rational.den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVFrameColorPrimaries::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AVColorPrimaries const ColorPrimaries = AvFrame->color_primaries; + return FFmpegUtils::ColorPrimaries::fromAVColorPrimaries(ColorPrimaries); +} + +Expect<int32_t> AVFrameSetColorPrimaries::body(const Runtime::CallingFrame &, + uint32_t FrameId, + int32_t ColorPrimariesId) { + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AVColorPrimaries const ColorPrimaries = + FFmpegUtils::ColorPrimaries::intoAVColorPrimaries(ColorPrimariesId); + AvFrame->color_primaries = ColorPrimaries; + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/avFrame.h b/plugins/wasmedge_ffmpeg/avutil/avFrame.h new file mode 100644 index 000000000000..9e4a36397f65 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avFrame.h @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVFrameAlloc : public HostFunction<AVFrameAlloc> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FramePtr); +}; + +class AVFrameFree : public HostFunction<AVFrameFree> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameWidth : public HostFunction<AVFrameWidth> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameHeight : public HostFunction<AVFrameHeight> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetWidth : public HostFunction<AVFrameSetWidth> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t Width); +}; + +class AVFrameSetHeight : public HostFunction<AVFrameSetHeight> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t Height); +}; + +class AVFrameVideoFormat : public HostFunction<AVFrameVideoFormat> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetVideoFormat : public HostFunction<AVFrameSetVideoFormat> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t AvPixFormatId); +}; + +class AVFrameIsNull : public HostFunction<AVFrameIsNull> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameLinesize : public HostFunction<AVFrameLinesize> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t Idx); +}; + +class AVFrameData : public HostFunction<AVFrameData> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t FrameBufPtr, uint32_t FrameBufLen, + uint32_t Index); +}; + +class AVFrameGetBuffer : public HostFunction<AVFrameGetBuffer> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t Align); +}; + +class AVFrameAudioFormat : public HostFunction<AVFrameAudioFormat> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetAudioFormat : public HostFunction<AVFrameSetAudioFormat> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t SampleFormatId); +}; + +class AVFrameSetChannelLayout : public HostFunction<AVFrameSetChannelLayout> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint64_t ChannelLayoutID); +}; + +class AVFrameSetNbSamples : public HostFunction<AVFrameSetNbSamples> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t Samples); +}; + +class AVFrameNbSamples : public HostFunction<AVFrameNbSamples> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSampleRate : public HostFunction<AVFrameSampleRate> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetSampleRate : public HostFunction<AVFrameSetSampleRate> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t SampleRate); +}; + +class AVFrameChannels : public HostFunction<AVFrameChannels> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetChannels : public HostFunction<AVFrameSetChannels> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t Channels); +}; + +class AVFrameChannelLayout : public HostFunction<AVFrameChannelLayout> { +public: + using HostFunction::HostFunction; + Expect<uint64_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameBestEffortTimestamp + : public HostFunction<AVFrameBestEffortTimestamp> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFramePictType : public HostFunction<AVFramePictType> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetPictType : public HostFunction<AVFrameSetPictType> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t PictureId); +}; + +class AVFrameInterlacedFrame : public HostFunction<AVFrameInterlacedFrame> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameTopFieldFirst : public HostFunction<AVFrameTopFieldFirst> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFramePaletteHasChanged : public HostFunction<AVFramePaletteHasChanged> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameColorSpace : public HostFunction<AVFrameColorSpace> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetColorSpace : public HostFunction<AVFrameSetColorSpace> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t ColorSpaceId); +}; + +class AVFrameColorRange : public HostFunction<AVFrameColorRange> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetColorRange : public HostFunction<AVFrameSetColorRange> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t ColorRangeId); +}; + +// color_transfer_characteristic + +class AVFrameColorTransferCharacteristic + : public HostFunction<AVFrameColorTransferCharacteristic> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetColorTransferCharacteristic + : public HostFunction<AVFrameSetColorTransferCharacteristic> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t ColorTransferCharacteristicId); +}; + +class AVFrameChromaLocation : public HostFunction<AVFrameChromaLocation> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameCodedPictureNumber + : public HostFunction<AVFrameCodedPictureNumber> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameDisplayPictureNumber + : public HostFunction<AVFrameDisplayPictureNumber> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameRepeatPict : public HostFunction<AVFrameRepeatPict> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameFlags : public HostFunction<AVFrameFlags> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameQuality : public HostFunction<AVFrameQuality> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameMetadata : public HostFunction<AVFrameMetadata> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t DictPtr); +}; + +class AVFrameSetMetadata : public HostFunction<AVFrameSetMetadata> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t DictId); +}; + +class AVFrameKeyFrame : public HostFunction<AVFrameKeyFrame> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFramePts : public HostFunction<AVFramePts> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetPts : public HostFunction<AVFrameSetPts> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int64_t Pts); +}; + +class AVFrameCopy : public HostFunction<AVFrameCopy> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t DestFrameId, + uint32_t SrcFrameId); +}; + +class AVFrameCopyProps : public HostFunction<AVFrameCopyProps> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t DestFrameId, + uint32_t SrcFrameId); +}; + +class AVFrameSampleAspectRatio : public HostFunction<AVFrameSampleAspectRatio> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t NumPtr, uint32_t DenPtr); +}; + +class AVFrameColorPrimaries : public HostFunction<AVFrameColorPrimaries> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetColorPrimaries : public HostFunction<AVFrameSetColorPrimaries> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t ColorPrimariesId); +}; + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/avRational.cpp b/plugins/wasmedge_ffmpeg/avutil/avRational.cpp new file mode 100644 index 000000000000..deedd7e44072 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avRational.cpp @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avRational.h" + +extern "C" { +#include "libavutil/rational.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect<int32_t> AVAddQ::body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, int32_t BNum, int32_t BDen, + uint32_t CNumPtr, uint32_t CDenPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(CNum, MemInst, int32_t, CNumPtr, + "Failed to access Numerator Ptr for AVRational"sv); + MEM_PTR_CHECK(CDen, MemInst, int32_t, CDenPtr, + "Failed to access Denominator Ptr for AVRational"sv); + + AVRational const A = av_make_q(ANum, ADen); + AVRational const B = av_make_q(BNum, BDen); + + AVRational const C = av_add_q(A, B); + *CNum = C.num; + *CDen = C.den; + + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVSubQ::body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, int32_t BNum, int32_t BDen, + uint32_t CNumPtr, uint32_t CDenPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(CNum, MemInst, int32_t, CNumPtr, + "Failed to access Numerator Ptr for AVRational"sv); + MEM_PTR_CHECK(CDen, MemInst, int32_t, CDenPtr, + "Failed to access Denominator Ptr for AVRational"sv); + + AVRational const A = av_make_q(ANum, ADen); + AVRational const B = av_make_q(BNum, BDen); + + AVRational const C = av_sub_q(A, B); + *CNum = C.num; + *CDen = C.den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVMulQ::body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, int32_t BNum, int32_t BDen, + uint32_t CNumPtr, uint32_t CDenPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(CNum, MemInst, int32_t, CNumPtr, + "Failed to access Numerator Ptr for AVRational"sv); + MEM_PTR_CHECK(CDen, MemInst, int32_t, CDenPtr, + "Failed to access Denominator Ptr for AVRational"sv); + + AVRational const A = av_make_q(ANum, ADen); + AVRational const B = av_make_q(BNum, BDen); + + AVRational const C = av_mul_q(A, B); + *CNum = C.num; + *CDen = C.den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVDivQ::body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, int32_t BNum, int32_t BDen, + uint32_t CNumPtr, uint32_t CDenPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(CNum, MemInst, int32_t, CNumPtr, + "Failed to access Numerator Ptr for AVRational"sv); + MEM_PTR_CHECK(CDen, MemInst, int32_t, CDenPtr, + "Failed to access Denominator Ptr for AVRational"sv); + + AVRational const A = av_make_q(ANum, ADen); + AVRational const B = av_make_q(BNum, BDen); + + AVRational const C = av_div_q(A, B); + *CNum = C.num; + *CDen = C.den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVCmpQ::body(const Runtime::CallingFrame &, int32_t ANum, + int32_t ADen, int32_t BNum, int32_t BDen) { + AVRational const A = av_make_q(ANum, ADen); + AVRational const B = av_make_q(BNum, BDen); + return av_cmp_q(A, B); +} + +Expect<int32_t> AVNearerQ::body(const Runtime::CallingFrame &, int32_t ANum, + int32_t ADen, int32_t BNum, int32_t BDen, + int32_t CNum, int32_t CDen) { + AVRational const A = av_make_q(ANum, ADen); + AVRational const B = av_make_q(BNum, BDen); + AVRational const C = av_make_q(CNum, CDen); + + return av_nearer_q(A, B, C); +} + +Expect<double_t> AVQ2d::body(const Runtime::CallingFrame &, int32_t ANum, + int32_t ADen) { + AVRational const A = av_make_q(ANum, ADen); + return av_q2d(A); +} + +Expect<int32_t> AVD2Q::body(const Runtime::CallingFrame &Frame, double_t D, + int32_t Max, uint32_t ANumPtr, uint32_t ADenPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(ANum, MemInst, int32_t, ANumPtr, + "Failed to access Numerator Ptr for AVRational"sv); + MEM_PTR_CHECK(ADen, MemInst, int32_t, ADenPtr, + "Failed to access Denominator Ptr for AVRational"sv); + + AVRational const A = av_d2q(D, Max); + *ANum = A.num; + *ADen = A.den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<uint32_t> AVQ2IntFloat::body(const Runtime::CallingFrame &, int32_t ANum, + int32_t ADen) { + AVRational const A = av_make_q(ANum, ADen); + return av_q2intfloat(A); +} + +Expect<int32_t> AVInvQ::body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, uint32_t BNumPtr, uint32_t BDenPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(BNum, MemInst, int32_t, BNumPtr, + "Failed to access Numerator Ptr for AVRational"sv); + MEM_PTR_CHECK(BDen, MemInst, int32_t, BDenPtr, + "Failed to access Denominator Ptr for AVRational"sv); + + AVRational const A = av_make_q(ANum, ADen); + AVRational const B = av_inv_q(A); + + *BNum = B.num; + *BDen = B.den; + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVReduce::body(const Runtime::CallingFrame &Frame, + uint32_t ANumPtr, uint32_t ADenPtr, int64_t BNum, + int64_t BDen, int64_t Max) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(ANum, MemInst, int32_t, ANumPtr, + "Failed to access Numerator Ptr for AVRational"sv); + MEM_PTR_CHECK(ADen, MemInst, int32_t, ADenPtr, + "Failed to access Denominator Ptr for AVRational"sv); + return av_reduce(ANum, ADen, BNum, BDen, Max); +} + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/avRational.h b/plugins/wasmedge_ffmpeg/avutil/avRational.h new file mode 100644 index 000000000000..828669408515 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avRational.h @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVAddQ : public HostFunction<AVAddQ> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, int32_t BNum, int32_t BDen, + uint32_t CNumPtr, uint32_t CDenPtr); +}; + +class AVSubQ : public HostFunction<AVSubQ> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, int32_t BNum, int32_t BDen, + uint32_t CNumPtr, uint32_t CDenPtr); +}; + +class AVMulQ : public HostFunction<AVMulQ> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, int32_t BNum, int32_t BDen, + uint32_t CNumPtr, uint32_t CDenPtr); +}; + +class AVDivQ : public HostFunction<AVDivQ> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, int32_t BNum, int32_t BDen, + uint32_t CNumPtr, uint32_t CDenPtr); +}; + +class AVCmpQ : public HostFunction<AVCmpQ> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, int32_t BNum, int32_t BDen); +}; + +class AVNearerQ : public HostFunction<AVNearerQ> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, int32_t BNum, int32_t BDen, int32_t CNum, + int32_t CDen); +}; + +class AVQ2d : public HostFunction<AVQ2d> { +public: + using HostFunction::HostFunction; + Expect<double_t> body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen); +}; + +class AVD2Q : public HostFunction<AVD2Q> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, double_t D, + int32_t Max, uint32_t ANumPtr, uint32_t ADenPtr); +}; + +class AVQ2IntFloat : public HostFunction<AVQ2IntFloat> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen); +}; + +class AVInvQ : public HostFunction<AVInvQ> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, uint32_t BNumPtr, uint32_t BDenPtr); +}; + +class AVReduce : public HostFunction<AVReduce> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t ANumPtr, + uint32_t ADenPtr, int64_t BNum, int64_t BDen, + int64_t Max); +}; + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/avTime.cpp b/plugins/wasmedge_ffmpeg/avutil/avTime.cpp new file mode 100644 index 000000000000..40cdaba10804 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avTime.cpp @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avTime.h" + +extern "C" { +#include "libavutil/time.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect<int64_t> AVGetTime::body(const Runtime::CallingFrame &) { + return av_gettime(); +} + +Expect<int64_t> AVGetTimeRelative::body(const Runtime::CallingFrame &) { + return av_gettime_relative(); +} + +Expect<int64_t> +AVGetTimeRelativeIsMonotonic::body(const Runtime::CallingFrame &) { + return av_gettime_relative_is_monotonic(); +} + +Expect<int32_t> AVUSleep::body(const Runtime::CallingFrame &, uint32_t USec) { + return av_usleep(USec); +} + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/avTime.h b/plugins/wasmedge_ffmpeg/avutil/avTime.h new file mode 100644 index 000000000000..6ec6e2c638b1 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avTime.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVGetTime : public HostFunction<AVGetTime> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVGetTimeRelative : public HostFunction<AVGetTimeRelative> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVGetTimeRelativeIsMonotonic + : public HostFunction<AVGetTimeRelativeIsMonotonic> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVUSleep : public HostFunction<AVUSleep> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t USec); +}; + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/avutil_func.cpp b/plugins/wasmedge_ffmpeg/avutil/avutil_func.cpp new file mode 100644 index 000000000000..6dfeaf01fc3a --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avutil_func.cpp @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avutil_func.h" + +extern "C" { +#include "libavutil/avutil.h" +#include "libavutil/time.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect<void> AVLogSetLevel::body(const Runtime::CallingFrame &, + int32_t LogLevelId) { + av_log_set_level(LogLevelId); + return {}; +} + +Expect<int32_t> AVLogGetLevel::body(const Runtime::CallingFrame &) { + return av_log_get_level(); +} + +Expect<int32_t> AVLogGetFlags::body(const Runtime::CallingFrame &) { + return av_log_get_flags(); +} + +Expect<void> AVLogSetFlags::body(const Runtime::CallingFrame &, + int32_t FlagId) { + av_log_set_flags(FlagId); + return {}; +} + +Expect<int64_t> AVRescaleQ::body(const Runtime::CallingFrame &, int64_t A, + int32_t BNum, int32_t BDen, int32_t CNum, + int32_t CDen) { + AVRational const B = av_make_q(BNum, BDen); + AVRational const C = av_make_q(CNum, CDen); + return av_rescale_q(A, B, C); +} + +Expect<int64_t> AVRescaleQRnd::body(const Runtime::CallingFrame &, int64_t A, + int32_t BNum, int32_t BDen, int32_t CNum, + int32_t CDen, int32_t RoundingId) { + AVRational const B = av_make_q(BNum, BDen); + AVRational const C = av_make_q(CNum, CDen); + AVRounding const Rounding = FFmpegUtils::Rounding::intoAVRounding(RoundingId); + return av_rescale_q_rnd(A, B, C, Rounding); +} + +Expect<uint32_t> AVUtilVersion::body(const Runtime::CallingFrame &) { + return avutil_version(); +} + +Expect<int32_t> +AVGetChannelLayoutNbChannels::body(const Runtime::CallingFrame &, + uint64_t ChannelLayoutId) { + uint64_t const ChannelLayout = + FFmpegUtils::ChannelLayout::fromChannelLayoutID(ChannelLayoutId); + return av_get_channel_layout_nb_channels(ChannelLayout); +} + +Expect<int32_t> AVGetChannelLayoutNameLen::body(const Runtime::CallingFrame &, + uint64_t ChannelLayoutId) { + uint64_t const ChannelLayout = + FFmpegUtils::ChannelLayout::fromChannelLayoutID(ChannelLayoutId); + const char *ChName = av_get_channel_name(ChannelLayout); + if (ChName == nullptr) { + return 0; + } + return strlen(ChName); +} + +Expect<int32_t> AVGetChannelLayoutName::body(const Runtime::CallingFrame &Frame, + uint64_t ChannelLayoutId, + uint32_t NamePtr, + uint32_t NameLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(NameBuf, MemInst, char, NamePtr, NameLen, ""); + + uint64_t const ChannelLayout = + FFmpegUtils::ChannelLayout::fromChannelLayoutID(ChannelLayoutId); + const char *ChName = av_get_channel_name(ChannelLayout); + + std::copy_n(ChName, NameLen, NameBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<uint64_t> AVGetChannelLayoutMask::body(const Runtime::CallingFrame &, + uint64_t ChannelLayoutId) { + uint64_t const ChannelLayout = + FFmpegUtils::ChannelLayout::fromChannelLayoutID(ChannelLayoutId); + return ChannelLayout; +} + +Expect<uint64_t> AVGetDefaultChannelLayout::body(const Runtime::CallingFrame &, + int32_t Number) { + uint64_t const ChannelLayout = av_get_default_channel_layout(Number); + return FFmpegUtils::ChannelLayout::intoChannelLayoutID(ChannelLayout); +} + +Expect<int32_t> AVUtilConfigurationLength::body(const Runtime::CallingFrame &) { + const char *Config = avutil_configuration(); + return strlen(Config); +} + +Expect<int32_t> AVUtilConfiguration::body(const Runtime::CallingFrame &Frame, + uint32_t ConfigPtr, + uint32_t ConfigLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(ConfigBuf, MemInst, char, ConfigPtr, ConfigLen, ""); + + const char *Config = avutil_configuration(); + std::copy_n(Config, ConfigLen, ConfigBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVUtilLicenseLength::body(const Runtime::CallingFrame &) { + const char *License = avutil_license(); + return strlen(License); +} + +Expect<int32_t> AVUtilLicense::body(const Runtime::CallingFrame &Frame, + uint32_t LicensePtr, uint32_t LicenseLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(LicenseBuf, MemInst, char, LicensePtr, LicenseLen, ""); + + const char *License = avutil_license(); + std::copy_n(License, LicenseLen, LicenseBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/avutil_func.h b/plugins/wasmedge_ffmpeg/avutil/avutil_func.h new file mode 100644 index 000000000000..05a2c7b5cf98 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avutil_func.h @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVLogSetLevel : public HostFunction<AVLogSetLevel> { +public: + using HostFunction::HostFunction; + Expect<void> body(const Runtime::CallingFrame &Frame, int32_t LogLevelId); +}; + +class AVLogGetLevel : public HostFunction<AVLogGetLevel> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVLogSetFlags : public HostFunction<AVLogSetFlags> { +public: + using HostFunction::HostFunction; + Expect<void> body(const Runtime::CallingFrame &Frame, int32_t FlagsId); +}; + +class AVLogGetFlags : public HostFunction<AVLogGetFlags> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +// Option funcs. +class AVOptSetBin : public HostFunction<AVOptSetBin> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSet : public HostFunction<AVOptSet> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetInt : public HostFunction<AVOptSetInt> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetDouble : public HostFunction<AVOptSetDouble> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetQ : public HostFunction<AVOptSetQ> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetImageSize : public HostFunction<AVOptSetImageSize> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetPixelFmt : public HostFunction<AVOptSetPixelFmt> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetSampleFmt : public HostFunction<AVOptSetSampleFmt> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetChannelLayout : public HostFunction<AVOptSetChannelLayout> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVRescaleQ : public HostFunction<AVRescaleQ> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, int64_t A, + int32_t BNum, int32_t BDen, int32_t CNum, int32_t CDen); +}; + +class AVRescaleQRnd : public HostFunction<AVRescaleQRnd> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &, int64_t A, int32_t BNum, + int32_t BDen, int32_t CNum, int32_t CDen, + int32_t RoundingId); +}; + +class AVUtilVersion : public HostFunction<AVUtilVersion> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &); +}; + +class AVGetChannelLayoutNbChannels + : public HostFunction<AVGetChannelLayoutNbChannels> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint64_t ChannelLayoutId); +}; + +class AVGetChannelLayoutNameLen + : public HostFunction<AVGetChannelLayoutNameLen> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint64_t ChannelLayoutId); +}; + +class AVGetChannelLayoutName : public HostFunction<AVGetChannelLayoutName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint64_t ChannelLayoutId, uint32_t NamePtr, + uint32_t NameLen); +}; + +class AVGetChannelLayoutMask : public HostFunction<AVGetChannelLayoutMask> { +public: + using HostFunction::HostFunction; + Expect<uint64_t> body(const Runtime::CallingFrame &Frame, + uint64_t ChannelLayoutId); +}; + +class AVGetDefaultChannelLayout + : public HostFunction<AVGetDefaultChannelLayout> { +public: + using HostFunction::HostFunction; + Expect<uint64_t> body(const Runtime::CallingFrame &Frame, + int32_t ChannelLayoutId); +}; + +class AVUtilConfigurationLength + : public HostFunction<AVUtilConfigurationLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVUtilConfiguration : public HostFunction<AVUtilConfiguration> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class AVUtilLicenseLength : public HostFunction<AVUtilLicenseLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class AVUtilLicense : public HostFunction<AVUtilLicense> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t LicensePtr, + uint32_t LicenseLen); +}; + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/error.cpp b/plugins/wasmedge_ffmpeg/avutil/error.cpp new file mode 100644 index 000000000000..90df0fbfb722 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/error.cpp @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "error.h" + +extern "C" { +#include "libavutil/error.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect<int32_t> AVUtilAVStrError::body(const Runtime::CallingFrame &Frame, + int32_t ErrNum, uint32_t ErrBuf, + uint32_t BufLen) { + MEMINST_CHECK(MemInst, Frame, 0); + + MEM_PTR_CHECK(ErrId, MemInst, char, ErrBuf, + "Failed when accessing the return URL memory"sv); + + std::string Error; + std::copy_n(ErrId, BufLen, std::back_inserter(Error)); + return av_strerror(ErrNum, const_cast<char *>(Error.c_str()), BufLen); +} + +Expect<int32_t> AVUtilAVError::body(const Runtime::CallingFrame &, + int32_t ErrNum) { + return AVERROR(ErrNum); +} + +Expect<int32_t> AVUtilAVUNError::body(const Runtime::CallingFrame &, + int32_t ErrNum) { + return AVUNERROR(ErrNum); +} + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/error.h b/plugins/wasmedge_ffmpeg/avutil/error.h new file mode 100644 index 000000000000..0ff38ce5e3b0 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/error.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVUtilAVStrError : public HostFunction<AVUtilAVStrError> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t ErrNum, + uint32_t ErrBuf, uint32_t BufLen); +}; + +class AVUtilAVError : public HostFunction<AVUtilAVError> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t ErrNum); +}; + +class AVUtilAVUNError : public HostFunction<AVUtilAVUNError> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t ErrNum); +}; + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/module.cpp b/plugins/wasmedge_ffmpeg/avutil/module.cpp new file mode 100644 index 000000000000..2dd207c3988b --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/module.cpp @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "module.h" +#include "avDictionary.h" +#include "avFrame.h" +#include "avRational.h" +#include "avTime.h" +#include "avutil_func.h" +#include "error.h" +#include "pixfmt.h" +#include "samplefmt.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +WasmEdgeFFmpegAVUtilModule::WasmEdgeFFmpegAVUtilModule( + std::shared_ptr<WasmEdgeFFmpegEnv> Env) + : ModuleInstance("wasmedge_ffmpeg_avutil") { + // error.h + addHostFunc("wasmedge_ffmpeg_avutil_av_strerror", + std::make_unique<AVUtilAVStrError>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_AVERROR", + std::make_unique<AVUtilAVError>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_AVUNERROR", + std::make_unique<AVUtilAVUNError>(Env)); + + // rational.h + addHostFunc("wasmedge_ffmpeg_avutil_av_add_q", std::make_unique<AVAddQ>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_sub_q", std::make_unique<AVSubQ>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_mul_q", std::make_unique<AVMulQ>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_div_q", std::make_unique<AVDivQ>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_d2q", std::make_unique<AVD2Q>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_q2d", std::make_unique<AVQ2d>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_inv_q", std::make_unique<AVInvQ>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_q2intfloat", + std::make_unique<AVQ2IntFloat>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_nearer_q", + std::make_unique<AVNearerQ>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_cmp_q", std::make_unique<AVCmpQ>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_reduce", + std::make_unique<AVReduce>(Env)); + + // frame.h + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_alloc", + std::make_unique<AVFrameAlloc>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_free", + std::make_unique<AVFrameFree>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_width", + std::make_unique<AVFrameWidth>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_height", + std::make_unique<AVFrameHeight>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_width", + std::make_unique<AVFrameSetWidth>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_height", + std::make_unique<AVFrameSetHeight>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_video_format", + std::make_unique<AVFrameVideoFormat>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_video_format", + std::make_unique<AVFrameSetVideoFormat>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_isnull", + std::make_unique<AVFrameIsNull>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_linesize", + std::make_unique<AVFrameLinesize>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_data", + std::make_unique<AVFrameData>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_get_buffer", + std::make_unique<AVFrameGetBuffer>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_audio_format", + std::make_unique<AVFrameAudioFormat>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_audio_format", + std::make_unique<AVFrameSetAudioFormat>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_nb_samples", + std::make_unique<AVFrameSetNbSamples>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_channel_layout", + std::make_unique<AVFrameSetChannelLayout>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_nb_samples", + std::make_unique<AVFrameNbSamples>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_sample_rate", + std::make_unique<AVFrameSampleRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_sample_rate", + std::make_unique<AVFrameSetSampleRate>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_channels", + std::make_unique<AVFrameChannels>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_channels", + std::make_unique<AVFrameSetChannels>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_channel_layout", + std::make_unique<AVFrameChannelLayout>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_best_effort_timestamp", + std::make_unique<AVFrameBestEffortTimestamp>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_pict_type", + std::make_unique<AVFramePictType>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_pict_type", + std::make_unique<AVFrameSetPictType>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_interlaced_frame", + std::make_unique<AVFrameInterlacedFrame>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_top_field_first", + std::make_unique<AVFrameTopFieldFirst>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_palette_has_changed", + std::make_unique<AVFramePaletteHasChanged>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_colorspace", + std::make_unique<AVFrameColorSpace>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_colorspace", + std::make_unique<AVFrameSetColorSpace>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_color_range", + std::make_unique<AVFrameColorRange>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_color_range", + std::make_unique<AVFrameSetColorRange>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_color_trc", + std::make_unique<AVFrameColorTransferCharacteristic>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_color_trc", + std::make_unique<AVFrameSetColorTransferCharacteristic>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_chroma_location", + std::make_unique<AVFrameChromaLocation>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_coded_picture_number", + std::make_unique<AVFrameCodedPictureNumber>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_display_picture_number", + std::make_unique<AVFrameDisplayPictureNumber>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_repeat_pict", + std::make_unique<AVFrameRepeatPict>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_flags", + std::make_unique<AVFrameFlags>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_quality", + std::make_unique<AVFrameQuality>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_metadata", + std::make_unique<AVFrameMetadata>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_metadata", + std::make_unique<AVFrameSetMetadata>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_key_frame", + std::make_unique<AVFrameKeyFrame>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_pts", + std::make_unique<AVFramePts>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_pts", + std::make_unique<AVFrameSetPts>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_copy", + std::make_unique<AVFrameCopy>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_copy_props", + std::make_unique<AVFrameCopyProps>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_sample_aspect_ratio", + std::make_unique<AVFrameSampleAspectRatio>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_color_primaries", + std::make_unique<AVFrameSetColorPrimaries>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_color_primaries", + std::make_unique<AVFrameColorPrimaries>(Env)); + + // pixfmt.h (Even AvPixFmtDesc is in this file) + addHostFunc("wasmedge_ffmpeg_avutil_avpixfmtdescriptor_nb_components", + std::make_unique<AvPixFmtDescriptorNbComponents>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avpixfmtdescriptor_log2_chromaw", + std::make_unique<AvPixFmtDescriptorLog2ChromaW>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avpixfmtdescriptor_log2_chromah", + std::make_unique<AvPixFmtDescriptorLog2ChromaH>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_transfer_name_length", + std::make_unique<AVColorTransferNameLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_transfer_name", + std::make_unique<AVColorTransferName>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_range_name_length", + std::make_unique<AVColorRangeNameLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_range_name", + std::make_unique<AVColorRangeName>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_space_name_length", + std::make_unique<AVColorSpaceNameLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_space_name", + std::make_unique<AVColorSpaceName>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_primaries_name_length", + std::make_unique<AVColorPrimariesNameLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_primaries_name", + std::make_unique<AVColorPrimariesName>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_pix_format_name_length", + std::make_unique<AVPixelFormatNameLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_pix_format_name", + std::make_unique<AVPixelFormatName>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_pix_format_mask", + std::make_unique<AVPixelFormatMask>(Env)); + + // samplefmt.h + addHostFunc("wasmedge_ffmpeg_avutil_av_get_packed_sample_fmt", + std::make_unique<AVGetPackedSampleFmt>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_planar_sample_fmt", + std::make_unique<AVGetPlanarSampleFmt>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_sample_fmt_is_planar", + std::make_unique<AVSampleFmtIsPlanar>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_bytes_per_sample", + std::make_unique<AVGetBytesPerSample>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_sample_fmt", + std::make_unique<AVGetSampleFmt>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_samples_get_buffer_size", + std::make_unique<AVSamplesGetBufferSize>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_samples_alloc_array_and_samples", + std::make_unique<AVSamplesAllocArrayAndSamples>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_sample_fmt_name_length", + std::make_unique<AVGetSampleFmtNameLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_sample_fmt_name", + std::make_unique<AVGetSampleFmtName>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_sample_fmt_mask", + std::make_unique<AVGetSampleFmtMask>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_freep", + std::make_unique<AVFreep>(Env)); + + // dict.h + addHostFunc("wasmedge_ffmpeg_avutil_av_dict_set", + std::make_unique<AVDictSet>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_dict_get", + std::make_unique<AVDictGet>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_dict_get_key_value", + std::make_unique<AVDictGetKeyValue>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_dict_copy", + std::make_unique<AVDictCopy>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_dict_free", + std::make_unique<AVDictFree>(Env)); + + // avutil_func.h + addHostFunc("wasmedge_ffmpeg_avutil_av_log_set_level", + std::make_unique<AVLogSetLevel>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_log_get_level", + std::make_unique<AVLogGetLevel>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_log_set_flags", + std::make_unique<AVLogSetFlags>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_log_get_flags", + std::make_unique<AVLogGetFlags>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_rescale_q", + std::make_unique<AVRescaleQ>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_rescale_q_rnd", + std::make_unique<AVRescaleQRnd>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_channel_layout_nb_channels", + std::make_unique<AVGetChannelLayoutNbChannels>(Env)); + addHostFunc( + "wasmedge_ffmpeg_avutil_av_get_channel_layout_name_len", // TODO: Write + std::make_unique<AVGetChannelLayoutNameLen>(Env)); + addHostFunc( + "wasmedge_ffmpeg_avutil_av_get_channel_layout_name", // TODO: Write Test + std::make_unique<AVGetChannelLayoutName>(Env)); + addHostFunc( + "wasmedge_ffmpeg_avutil_av_get_channel_layout_mask", // TODO: Write Test + std::make_unique<AVGetChannelLayoutMask>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_default_channel_layout", + std::make_unique<AVGetDefaultChannelLayout>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avutil_version", + std::make_unique<AVUtilVersion>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avutil_configuration_length", + std::make_unique<AVUtilConfigurationLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avutil_configuration", + std::make_unique<AVUtilConfiguration>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avutil_license_length", + std::make_unique<AVUtilLicenseLength>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avutil_license", + std::make_unique<AVUtilLicense>(Env)); + + // time.h + addHostFunc("wasmedge_ffmpeg_avutil_av_gettime", + std::make_unique<AVGetTime>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_gettime_relative", + std::make_unique<AVGetTimeRelative>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_gettime_relative_is_monotonic", + std::make_unique<AVGetTimeRelativeIsMonotonic>(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_usleep", + std::make_unique<AVUSleep>(Env)); +} + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/module.h b/plugins/wasmedge_ffmpeg/avutil/module.h new file mode 100644 index 000000000000..6c22537b686e --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/module.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_env.h" + +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class WasmEdgeFFmpegAVUtilModule : public Runtime::Instance::ModuleInstance { +public: + WasmEdgeFFmpegAVUtilModule(std::shared_ptr<WasmEdgeFFmpegEnv> Env); +}; + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/pixfmt.cpp b/plugins/wasmedge_ffmpeg/avutil/pixfmt.cpp new file mode 100644 index 000000000000..639a9241d29b --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/pixfmt.cpp @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "pixfmt.h" + +extern "C" { +#include "libavutil/pixdesc.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect<int32_t> +AvPixFmtDescriptorNbComponents::body(const Runtime::CallingFrame &, + uint32_t PixFormatId) { + AVPixelFormat const PixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(PixFormatId); + const AVPixFmtDescriptor *AvPixFmtDescriptor = + av_pix_fmt_desc_get(PixelFormat); + return AvPixFmtDescriptor->nb_components; +} + +Expect<int32_t> +AvPixFmtDescriptorLog2ChromaW::body(const Runtime::CallingFrame &, + uint32_t PixFormatId) { + AVPixelFormat const PixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(PixFormatId); + const AVPixFmtDescriptor *AvPixFmtDescriptor = + av_pix_fmt_desc_get(PixelFormat); + return AvPixFmtDescriptor->log2_chroma_w; +} + +Expect<int32_t> +AvPixFmtDescriptorLog2ChromaH::body(const Runtime::CallingFrame &, + uint32_t PixFormatId) { + AVPixelFormat const PixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(PixFormatId); + const AVPixFmtDescriptor *AvPixFmtDescriptor = + av_pix_fmt_desc_get(PixelFormat); + return AvPixFmtDescriptor->log2_chroma_h; +} + +Expect<int32_t> AVColorRangeNameLength::body(const Runtime::CallingFrame &, + int32_t RangeId) { + AVColorRange const ColorRange = static_cast<AVColorRange>(RangeId); + const char *Name = av_color_range_name(ColorRange); + return strlen(Name); +} + +Expect<int32_t> AVColorRangeName::body(const Runtime::CallingFrame &Frame, + int32_t RangeId, uint32_t RangeNamePtr, + uint32_t RangeLength) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(RangeNameBuf, MemInst, char, RangeNamePtr, RangeLength, ""); + + AVColorRange const ColorRange = static_cast<AVColorRange>(RangeId); + const char *RangeName = av_color_range_name(ColorRange); + std::copy_n(RangeName, RangeLength, RangeNameBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVColorTransferNameLength::body(const Runtime::CallingFrame &, + int32_t TransferId) { + AVColorTransferCharacteristic const Characteristic = + static_cast<AVColorTransferCharacteristic>(TransferId); + const char *Name = av_color_transfer_name(Characteristic); + return strlen(Name); +} + +Expect<int32_t> AVColorTransferName::body(const Runtime::CallingFrame &Frame, + int32_t TransferId, + uint32_t TransferNamePtr, + uint32_t TransferLength) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(TransferNameBuf, MemInst, char, TransferNamePtr, + TransferLength, ""); + + AVColorTransferCharacteristic const Characteristic = + static_cast<AVColorTransferCharacteristic>(TransferId); + const char *TransferName = av_color_transfer_name(Characteristic); + std::copy_n(TransferName, TransferLength, TransferNameBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVColorSpaceNameLength::body(const Runtime::CallingFrame &, + int32_t ColorSpaceId) { + AVColorSpace const ColorSpace = static_cast<AVColorSpace>(ColorSpaceId); + const char *Name = av_color_space_name(ColorSpace); + return strlen(Name); +} + +Expect<int32_t> AVColorSpaceName::body(const Runtime::CallingFrame &Frame, + int32_t ColorSpaceId, + uint32_t ColorSpaceNamePtr, + uint32_t ColorSpaceLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(ColorSpaceBuf, MemInst, char, ColorSpaceNamePtr, ColorSpaceLen, + ""); + + AVColorSpace const ColorSpace = static_cast<AVColorSpace>(ColorSpaceId); + const char *ColorSpaceName = av_color_space_name(ColorSpace); + std::copy_n(ColorSpaceName, ColorSpaceLen, ColorSpaceBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVColorPrimariesNameLength::body(const Runtime::CallingFrame &, + int32_t ColorPrimariesId) { + AVColorPrimaries const ColorPrimaries = + FFmpegUtils::ColorPrimaries::intoAVColorPrimaries(ColorPrimariesId); + const char *Name = av_color_primaries_name(ColorPrimaries); + return strlen(Name); +} + +Expect<int32_t> AVColorPrimariesName::body(const Runtime::CallingFrame &Frame, + int32_t ColorPrimariesId, + uint32_t ColorPrimariesNamePtr, + uint32_t ColorPrimariesLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(ColorPrimariesBuf, MemInst, char, ColorPrimariesNamePtr, + ColorPrimariesLen, ""); + + AVColorPrimaries const ColorPrimaries = + FFmpegUtils::ColorPrimaries::intoAVColorPrimaries(ColorPrimariesId); + const char *PrimariesName = av_color_primaries_name(ColorPrimaries); + std::copy_n(PrimariesName, ColorPrimariesLen, ColorPrimariesBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVPixelFormatNameLength::body(const Runtime::CallingFrame &, + uint32_t AvPixFormatId) { + AVPixelFormat const PixFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(AvPixFormatId); + const AVPixFmtDescriptor *PixFmtDescriptor = av_pix_fmt_desc_get(PixFormat); + + return strlen(PixFmtDescriptor->name); +} + +Expect<int32_t> AVPixelFormatName::body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId, + uint32_t PixFormatNamePtr, + uint32_t PixFormatNameLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(PixFormatBuf, MemInst, char, PixFormatNamePtr, + PixFormatNameLen, ""); + + AVPixelFormat const PixFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(PixFormatId); + const AVPixFmtDescriptor *PixFmtDescriptor = av_pix_fmt_desc_get(PixFormat); + const char *PixFormatName = PixFmtDescriptor->name; + std::copy_n(PixFormatName, PixFormatNameLen, PixFormatBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVPixelFormatMask::body(const Runtime::CallingFrame &, + uint32_t PixFormatId) { + AVPixelFormat const PixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(PixFormatId); + return static_cast<int32_t>(PixelFormat); +} + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/pixfmt.h b/plugins/wasmedge_ffmpeg/avutil/pixfmt.h new file mode 100644 index 000000000000..0b5dfc64702f --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/pixfmt.h @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AvPixFmtDescriptorNbComponents + : public HostFunction<AvPixFmtDescriptorNbComponents> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId); +}; + +class AvPixFmtDescriptorLog2ChromaW + : public HostFunction<AvPixFmtDescriptorLog2ChromaW> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId); +}; + +class AvPixFmtDescriptorLog2ChromaH + : public HostFunction<AvPixFmtDescriptorLog2ChromaH> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId); +}; + +class AVColorRangeNameLength : public HostFunction<AVColorRangeNameLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t RangeId); +}; + +class AVColorRangeName : public HostFunction<AVColorRangeName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t RangeId, + uint32_t RangeName, uint32_t RangeLength); +}; + +class AVColorTransferNameLength + : public HostFunction<AVColorTransferNameLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t TransferId); +}; + +class AVColorTransferName : public HostFunction<AVColorTransferName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t TransferId, + uint32_t TransferNamePtr, uint32_t TransferLength); +}; + +class AVColorSpaceNameLength : public HostFunction<AVColorSpaceNameLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + int32_t ColorSpaceId); +}; + +class AVColorSpaceName : public HostFunction<AVColorSpaceName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t ColorSpaceId, + uint32_t ColorSpaceNamePtr, uint32_t ColorSpaceLen); +}; + +class AVColorPrimariesNameLength + : public HostFunction<AVColorPrimariesNameLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + int32_t ColorPrimariesId); +}; + +class AVColorPrimariesName : public HostFunction<AVColorPrimariesName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + int32_t ColorPrimariesId, uint32_t ColorPrimariesNamePtr, + uint32_t ColorPrimariesLen); +}; + +class AVPixelFormatNameLength : public HostFunction<AVPixelFormatNameLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t AvPixFormatId); +}; + +class AVPixelFormatName : public HostFunction<AVPixelFormatName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t PixFormatId, + uint32_t PixFormatNamePtr, uint32_t PixFormatNameLen); +}; + +class AVPixelFormatMask : public HostFunction<AVPixelFormatMask> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId); +}; + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/samplefmt.cpp b/plugins/wasmedge_ffmpeg/avutil/samplefmt.cpp new file mode 100644 index 000000000000..40150a6896a6 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/samplefmt.cpp @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "samplefmt.h" + +extern "C" { +#include "libavutil/samplefmt.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect<uint32_t> AVGetPlanarSampleFmt::body(const Runtime::CallingFrame &, + uint32_t SampleFormatId) { + AVSampleFormat const AvSampleFormat = + FFmpegUtils::SampleFmt::fromSampleID(SampleFormatId); + AVSampleFormat const PlanarSampleFmt = + av_get_planar_sample_fmt(AvSampleFormat); + return FFmpegUtils::SampleFmt::toSampleID(PlanarSampleFmt); +} + +Expect<uint32_t> AVGetPackedSampleFmt::body(const Runtime::CallingFrame &, + uint32_t SampleFormatId) { + AVSampleFormat const AvSampleFormat = + FFmpegUtils::SampleFmt::fromSampleID(SampleFormatId); + AVSampleFormat const PackedSampleFmt = + av_get_packed_sample_fmt(AvSampleFormat); + return FFmpegUtils::SampleFmt::toSampleID(PackedSampleFmt); +} + +Expect<uint32_t> AVSampleFmtIsPlanar::body(const Runtime::CallingFrame &, + uint32_t SampleFormatId) { + AVSampleFormat const AvSampleFormat = + FFmpegUtils::SampleFmt::fromSampleID(SampleFormatId); + return av_sample_fmt_is_planar(AvSampleFormat); +} + +Expect<int32_t> AVGetBytesPerSample::body(const Runtime::CallingFrame &, + uint32_t SampleFormatId) { + AVSampleFormat const AvSampleFormat = + FFmpegUtils::SampleFmt::fromSampleID(SampleFormatId); + return av_get_bytes_per_sample(AvSampleFormat); +} + +Expect<int32_t> AVGetSampleFmt::body(const Runtime::CallingFrame &Frame, + uint32_t Str, uint32_t StrLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(StrId, MemInst, char, Str, ""); + + std::string TargetUrl; + std::copy_n(StrId, StrLen, std::back_inserter(TargetUrl)); + + AVSampleFormat const AvSampleFormat = av_get_sample_fmt(TargetUrl.c_str()); + return FFmpegUtils::SampleFmt::toSampleID(AvSampleFormat); +} + +Expect<int32_t> AVSamplesGetBufferSize::body(const Runtime::CallingFrame &, + int32_t NbChannels, + int32_t NbSamples, + uint32_t SampleFormatId, + int32_t Align) { + AVSampleFormat const AvSampleFormat = + FFmpegUtils::SampleFmt::fromSampleID(SampleFormatId); + return av_samples_get_buffer_size(nullptr, NbChannels, NbSamples, + AvSampleFormat, + Align); // linesize is NULL in RustSDK. +} + +Expect<int32_t> +AVSamplesAllocArrayAndSamples::body(const Runtime::CallingFrame &Frame, + uint32_t BufferPtr, uint32_t LinesizePtr, + int32_t NbChannels, int32_t NbSamples, + uint32_t SampleFmtId, int32_t Align) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(BufId, MemInst, uint32_t, BufferPtr, ""); + MEM_PTR_CHECK(LineSize, MemInst, int32_t, LinesizePtr, ""); + + FFMPEG_PTR_FETCH(Buf, *BufId, uint8_t *); + int LineSizeValue = 0; + AVSampleFormat const AvSampleFormat = + FFmpegUtils::SampleFmt::fromSampleID(SampleFmtId); + int Res = av_samples_alloc_array_and_samples( + &Buf, &LineSizeValue, NbChannels, NbSamples, AvSampleFormat, Align); + + *LineSize = LineSizeValue; + FFMPEG_PTR_STORE(Buf, BufId); + return Res; +} + +Expect<int32_t> AVGetSampleFmtNameLength::body(const Runtime::CallingFrame &, + uint32_t SampleFmtId) { + AVSampleFormat const SampleFmt = + FFmpegUtils::SampleFmt::fromSampleID(SampleFmtId); + + const char *Name = av_get_sample_fmt_name(SampleFmt); + return strlen(Name); +} + +Expect<int32_t> AVGetSampleFmtName::body(const Runtime::CallingFrame &Frame, + uint32_t SampleFmtId, + uint32_t SampleFmtNamePtr, + uint32_t SampleFmtNameLen) { + + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(SampleFmtBuf, MemInst, char, SampleFmtNamePtr, + SampleFmtNameLen, ""); + AVSampleFormat const SampleFmt = + FFmpegUtils::SampleFmt::fromSampleID(SampleFmtId); + const char *Name = av_get_sample_fmt_name(SampleFmt); + std::copy_n(Name, SampleFmtNameLen, SampleFmtBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVGetSampleFmtMask::body(const Runtime::CallingFrame &, + uint32_t SampleFmtId) { + AVSampleFormat const SampleFmt = + FFmpegUtils::SampleFmt::fromSampleID(SampleFmtId); + return static_cast<int32_t>(SampleFmt); +} + +Expect<int32_t> AVFreep::body(const Runtime::CallingFrame &, + uint32_t BufferId) { + FFMPEG_PTR_FETCH(Buffer, BufferId, uint8_t *); + av_freep(Buffer); + FFMPEG_PTR_DELETE(BufferId); + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/samplefmt.h b/plugins/wasmedge_ffmpeg/avutil/samplefmt.h new file mode 100644 index 000000000000..373ec2b790be --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/samplefmt.h @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVGetPlanarSampleFmt : public HostFunction<AVGetPlanarSampleFmt> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SampleFormatId); +}; + +class AVGetPackedSampleFmt : public HostFunction<AVGetPackedSampleFmt> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SampleFormatId); +}; + +class AVSampleFmtIsPlanar : public HostFunction<AVSampleFmtIsPlanar> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SampleFormatId); +}; + +class AVGetBytesPerSample : public HostFunction<AVGetBytesPerSample> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SampleFormatId); +}; + +class AVGetSampleFmt : public HostFunction<AVGetSampleFmt> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t Str, + uint32_t StrLen); +}; + +class AVSamplesGetBufferSize : public HostFunction<AVSamplesGetBufferSize> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, int32_t NbChannels, + int32_t NbSamples, uint32_t SampleFormatId, + int32_t Align); +}; + +class AVSamplesAllocArrayAndSamples + : public HostFunction<AVSamplesAllocArrayAndSamples> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t BufferPtr, + uint32_t LinesizePtr, int32_t NbChannels, + int32_t NbSamples, uint32_t SampleFmtId, int32_t Align); +}; + +class AVGetSampleFmtNameLength : public HostFunction<AVGetSampleFmtNameLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SampleFmtId); +}; + +class AVGetSampleFmtName : public HostFunction<AVGetSampleFmtName> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t SampleFmtId, + uint32_t SampleFmtNamePtr, uint32_t SampleFmtNameLen); +}; + +class AVGetSampleFmtMask : public HostFunction<AVGetSampleFmtMask> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SampleFmtId); +}; + +class AVFreep : public HostFunction<AVFreep> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t BufferId); +}; + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/bindings.h b/plugins/wasmedge_ffmpeg/bindings.h new file mode 100644 index 000000000000..ac8fb6fb25d7 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/bindings.h @@ -0,0 +1,4536 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +extern "C" { +#include "libavcodec/avcodec.h" +#include "libavutil/avutil.h" +#include "libavutil/opt.h" +#include "libswresample/swresample.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace FFmpegUtils { +class MediaType { +public: + static AVMediaType intoMediaType(int32_t MediaTypeId) { + switch (MediaTypeId) { + case 0: + return AVMEDIA_TYPE_VIDEO; + case 1: + return AVMEDIA_TYPE_AUDIO; + case 2: + return AVMEDIA_TYPE_DATA; + case 3: + return AVMEDIA_TYPE_SUBTITLE; + case 4: + return AVMEDIA_TYPE_ATTACHMENT; + case 5: + return AVMEDIA_TYPE_NB; + default: + return AVMEDIA_TYPE_UNKNOWN; + } + } + + static int32_t fromMediaType(AVMediaType MediaType) { + switch (MediaType) { + case AVMEDIA_TYPE_VIDEO: + return 0; + case AVMEDIA_TYPE_AUDIO: + return 1; + case AVMEDIA_TYPE_DATA: + return 2; + case AVMEDIA_TYPE_SUBTITLE: + return 3; + case 4: + return AVMEDIA_TYPE_ATTACHMENT; + case 5: + return AVMEDIA_TYPE_NB; + default: + return AVMEDIA_TYPE_UNKNOWN; + } + } +}; + +class CodecID { +public: + static AVCodecID intoAVCodecID(uint32_t AvCodecIndex) { + switch (AvCodecIndex) { + case 0: + return AV_CODEC_ID_NONE; + case 1: + return AV_CODEC_ID_MPEG1VIDEO; + case 2: + return AV_CODEC_ID_MPEG2VIDEO; + case 3: + return AV_CODEC_ID_H261; + case 4: + return AV_CODEC_ID_H263; + case 5: + return AV_CODEC_ID_RV10; + case 6: + return AV_CODEC_ID_RV20; + case 7: + return AV_CODEC_ID_MJPEG; + case 8: + return AV_CODEC_ID_MJPEGB; + case 9: + return AV_CODEC_ID_LJPEG; + case 10: + return AV_CODEC_ID_SP5X; + case 11: + return AV_CODEC_ID_JPEGLS; + case 12: + return AV_CODEC_ID_MPEG4; + case 13: + return AV_CODEC_ID_RAWVIDEO; + case 14: + return AV_CODEC_ID_MSMPEG4V1; + case 15: + return AV_CODEC_ID_MSMPEG4V2; + case 16: + return AV_CODEC_ID_MSMPEG4V3; + case 17: + return AV_CODEC_ID_WMV1; + case 18: + return AV_CODEC_ID_WMV2; + case 19: + return AV_CODEC_ID_H263P; + case 20: + return AV_CODEC_ID_H263I; + case 21: + return AV_CODEC_ID_FLV1; + case 22: + return AV_CODEC_ID_SVQ1; + case 23: + return AV_CODEC_ID_SVQ3; + case 24: + return AV_CODEC_ID_DVVIDEO; + case 25: + return AV_CODEC_ID_HUFFYUV; + case 26: + return AV_CODEC_ID_CYUV; + case 27: + return AV_CODEC_ID_H264; + case 28: + return AV_CODEC_ID_INDEO3; + case 29: + return AV_CODEC_ID_VP3; + case 30: + return AV_CODEC_ID_THEORA; + case 31: + return AV_CODEC_ID_ASV1; + case 32: + return AV_CODEC_ID_ASV2; + case 33: + return AV_CODEC_ID_FFV1; + case 34: + return AV_CODEC_ID_4XM; + case 35: + return AV_CODEC_ID_VCR1; + case 36: + return AV_CODEC_ID_CLJR; + case 37: + return AV_CODEC_ID_MDEC; + case 38: + return AV_CODEC_ID_ROQ; + case 39: + return AV_CODEC_ID_INTERPLAY_VIDEO; + case 40: + return AV_CODEC_ID_XAN_WC3; + case 41: + return AV_CODEC_ID_XAN_WC4; + case 42: + return AV_CODEC_ID_RPZA; + case 43: + return AV_CODEC_ID_CINEPAK; + case 44: + return AV_CODEC_ID_WS_VQA; + case 45: + return AV_CODEC_ID_MSRLE; + case 46: + return AV_CODEC_ID_MSVIDEO1; + case 47: + return AV_CODEC_ID_IDCIN; + case 48: + return AV_CODEC_ID_8BPS; + case 49: + return AV_CODEC_ID_SMC; + case 50: + return AV_CODEC_ID_FLIC; + case 51: + return AV_CODEC_ID_TRUEMOTION1; + case 52: + return AV_CODEC_ID_VMDVIDEO; + case 53: + return AV_CODEC_ID_MSZH; + case 54: + return AV_CODEC_ID_ZLIB; + case 55: + return AV_CODEC_ID_QTRLE; + case 56: + return AV_CODEC_ID_TSCC; + case 57: + return AV_CODEC_ID_ULTI; + case 58: + return AV_CODEC_ID_QDRAW; + case 59: + return AV_CODEC_ID_VIXL; + case 60: + return AV_CODEC_ID_QPEG; + case 61: + return AV_CODEC_ID_PNG; + case 62: + return AV_CODEC_ID_PPM; + case 63: + return AV_CODEC_ID_PBM; + case 64: + return AV_CODEC_ID_PGM; + case 65: + return AV_CODEC_ID_PGMYUV; + case 66: + return AV_CODEC_ID_PAM; + case 67: + return AV_CODEC_ID_FFVHUFF; + case 68: + return AV_CODEC_ID_RV30; + case 69: + return AV_CODEC_ID_RV40; + case 70: + return AV_CODEC_ID_VC1; + case 71: + return AV_CODEC_ID_WMV3; + case 72: + return AV_CODEC_ID_LOCO; + case 73: + return AV_CODEC_ID_WNV1; + case 74: + return AV_CODEC_ID_AASC; + case 75: + return AV_CODEC_ID_INDEO2; + case 76: + return AV_CODEC_ID_FRAPS; + case 77: + return AV_CODEC_ID_TRUEMOTION2; + case 78: + return AV_CODEC_ID_BMP; + case 79: + return AV_CODEC_ID_CSCD; + case 80: + return AV_CODEC_ID_MMVIDEO; + case 81: + return AV_CODEC_ID_ZMBV; + case 82: + return AV_CODEC_ID_AVS; + case 83: + return AV_CODEC_ID_SMACKVIDEO; + case 84: + return AV_CODEC_ID_NUV; + case 85: + return AV_CODEC_ID_KMVC; + case 86: + return AV_CODEC_ID_FLASHSV; + case 87: + return AV_CODEC_ID_CAVS; + case 88: + return AV_CODEC_ID_JPEG2000; + case 89: + return AV_CODEC_ID_VMNC; + case 90: + return AV_CODEC_ID_VP5; + case 91: + return AV_CODEC_ID_VP6; + case 92: + return AV_CODEC_ID_VP6F; + case 93: + return AV_CODEC_ID_TARGA; + case 94: + return AV_CODEC_ID_DSICINVIDEO; + case 95: + return AV_CODEC_ID_TIERTEXSEQVIDEO; + case 96: + return AV_CODEC_ID_TIFF; + case 97: + return AV_CODEC_ID_GIF; + case 98: + return AV_CODEC_ID_DXA; + case 99: + return AV_CODEC_ID_DNXHD; + case 100: + return AV_CODEC_ID_THP; + case 101: + return AV_CODEC_ID_SGI; + case 102: + return AV_CODEC_ID_C93; + case 103: + return AV_CODEC_ID_BETHSOFTVID; + case 104: + return AV_CODEC_ID_PTX; + case 105: + return AV_CODEC_ID_TXD; + case 106: + return AV_CODEC_ID_VP6A; + case 107: + return AV_CODEC_ID_AMV; + case 108: + return AV_CODEC_ID_VB; + case 109: + return AV_CODEC_ID_PCX; + case 110: + return AV_CODEC_ID_SUNRAST; + case 111: + return AV_CODEC_ID_INDEO4; + case 112: + return AV_CODEC_ID_INDEO5; + case 113: + return AV_CODEC_ID_MIMIC; + case 114: + return AV_CODEC_ID_RL2; + case 115: + return AV_CODEC_ID_ESCAPE124; + case 116: + return AV_CODEC_ID_DIRAC; + case 117: + return AV_CODEC_ID_BFI; + case 118: + return AV_CODEC_ID_CMV; + case 119: + return AV_CODEC_ID_MOTIONPIXELS; + case 120: + return AV_CODEC_ID_TGV; + case 121: + return AV_CODEC_ID_TGQ; + case 122: + return AV_CODEC_ID_TQI; + case 123: + return AV_CODEC_ID_AURA; + case 124: + return AV_CODEC_ID_AURA2; + case 125: + return AV_CODEC_ID_V210X; + case 126: + return AV_CODEC_ID_TMV; + case 127: + return AV_CODEC_ID_V210; + case 128: + return AV_CODEC_ID_DPX; + case 129: + return AV_CODEC_ID_MAD; + case 130: + return AV_CODEC_ID_FRWU; + case 131: + return AV_CODEC_ID_FLASHSV2; + case 132: + return AV_CODEC_ID_CDGRAPHICS; + case 133: + return AV_CODEC_ID_R210; + case 134: + return AV_CODEC_ID_ANM; + case 135: + return AV_CODEC_ID_BINKVIDEO; + case 136: + return AV_CODEC_ID_IFF_ILBM; + case 137: + return AV_CODEC_ID_IFF_ILBM; + case 138: + return AV_CODEC_ID_KGV1; + case 139: + return AV_CODEC_ID_YOP; + case 140: + return AV_CODEC_ID_VP8; + case 141: + return AV_CODEC_ID_PICTOR; + case 142: + return AV_CODEC_ID_ANSI; + case 143: + return AV_CODEC_ID_A64_MULTI; + case 144: + return AV_CODEC_ID_A64_MULTI5; + case 145: + return AV_CODEC_ID_R10K; + case 146: + return AV_CODEC_ID_MXPEG; + case 147: + return AV_CODEC_ID_LAGARITH; + case 148: + return AV_CODEC_ID_PRORES; + case 149: + return AV_CODEC_ID_JV; + case 150: + return AV_CODEC_ID_DFA; + case 151: + return AV_CODEC_ID_WMV3IMAGE; + case 152: + return AV_CODEC_ID_VC1IMAGE; + case 153: + return AV_CODEC_ID_UTVIDEO; + case 154: + return AV_CODEC_ID_BMV_VIDEO; + case 155: + return AV_CODEC_ID_VBLE; + case 156: + return AV_CODEC_ID_DXTORY; + case 157: + return AV_CODEC_ID_V410; + case 158: + return AV_CODEC_ID_XWD; + case 159: + return AV_CODEC_ID_CDXL; + case 160: + return AV_CODEC_ID_XBM; + case 161: + return AV_CODEC_ID_ZEROCODEC; + case 162: + return AV_CODEC_ID_MSS1; + case 163: + return AV_CODEC_ID_MSA1; + case 164: + return AV_CODEC_ID_TSCC2; + case 165: + return AV_CODEC_ID_MTS2; + case 166: + return AV_CODEC_ID_CLLC; + case 167: + return AV_CODEC_ID_MSS2; + case 168: + return AV_CODEC_ID_VP9; + case 169: + return AV_CODEC_ID_AIC; + case 170: + return AV_CODEC_ID_ESCAPE130; + case 171: + return AV_CODEC_ID_G2M; + case 172: + return AV_CODEC_ID_WEBP; + case 173: + return AV_CODEC_ID_HNM4_VIDEO; + case 174: + return AV_CODEC_ID_HEVC; + case 175: + return AV_CODEC_ID_HEVC; + case 176: + return AV_CODEC_ID_FIC; + case 177: + return AV_CODEC_ID_ALIAS_PIX; + case 178: + return AV_CODEC_ID_BRENDER_PIX; + case 179: + return AV_CODEC_ID_PAF_VIDEO; + case 180: + return AV_CODEC_ID_EXR; + case 181: + return AV_CODEC_ID_VP7; + case 182: + return AV_CODEC_ID_SANM; + case 183: + return AV_CODEC_ID_SGIRLE; + case 184: + return AV_CODEC_ID_MVC1; + case 185: + return AV_CODEC_ID_MVC2; + case 186: + return AV_CODEC_ID_HQX; + case 187: + return AV_CODEC_ID_TDSC; + case 188: + return AV_CODEC_ID_HQ_HQA; + case 189: + return AV_CODEC_ID_HAP; + case 190: + return AV_CODEC_ID_DDS; + case 191: + return AV_CODEC_ID_DXV; + case 192: + return AV_CODEC_ID_SCREENPRESSO; + case 193: + return AV_CODEC_ID_RSCC; + /////////////////////////////// + // case 194: + // return AV_CODEC_ID_Y41P; + // case 194: + // return AV_CODEC_ID_AVS2; + case 194: + return AV_CODEC_ID_Y41P; + case 195: + return AV_CODEC_ID_AVRP; + case 196: + return AV_CODEC_ID_012V; + case 197: + return AV_CODEC_ID_AVUI; + case 198: + return AV_CODEC_ID_AYUV; + case 199: + return AV_CODEC_ID_TARGA_Y216; + case 200: + return AV_CODEC_ID_V308; + case 201: + return AV_CODEC_ID_V408; + case 202: + return AV_CODEC_ID_YUV4; + case 203: + return AV_CODEC_ID_AVRN; + case 204: + return AV_CODEC_ID_CPIA; + case 205: + return AV_CODEC_ID_XFACE; + case 206: + return AV_CODEC_ID_SNOW; + case 207: + return AV_CODEC_ID_SMVJPEG; + case 208: + return AV_CODEC_ID_APNG; + case 209: + return AV_CODEC_ID_DAALA; + case 210: + return AV_CODEC_ID_CFHD; + case 211: + return AV_CODEC_ID_TRUEMOTION2RT; + case 212: + return AV_CODEC_ID_M101; + case 213: + return AV_CODEC_ID_MAGICYUV; + case 214: + return AV_CODEC_ID_SHEERVIDEO; + case 215: + return AV_CODEC_ID_YLC; + case 216: + return AV_CODEC_ID_PCM_S16LE; + case 217: + return AV_CODEC_ID_PCM_S16BE; + case 218: + return AV_CODEC_ID_PCM_U16LE; + case 219: + return AV_CODEC_ID_PCM_U16BE; + case 220: + return AV_CODEC_ID_PCM_S8; + case 221: + return AV_CODEC_ID_PCM_U8; + case 222: + return AV_CODEC_ID_PCM_MULAW; + case 223: + return AV_CODEC_ID_PCM_ALAW; + case 224: + return AV_CODEC_ID_PCM_S32LE; + case 225: + return AV_CODEC_ID_PCM_S32BE; + case 226: + return AV_CODEC_ID_PCM_U32LE; + case 227: + return AV_CODEC_ID_PCM_U32BE; + case 228: + return AV_CODEC_ID_PCM_S24LE; + case 229: + return AV_CODEC_ID_PCM_S24BE; + case 230: + return AV_CODEC_ID_PCM_U24LE; + case 231: + return AV_CODEC_ID_PCM_U24BE; + case 232: + return AV_CODEC_ID_PCM_S24DAUD; + case 233: + return AV_CODEC_ID_PCM_ZORK; + case 234: + return AV_CODEC_ID_PCM_S16LE_PLANAR; + case 235: + return AV_CODEC_ID_PCM_DVD; + case 236: + return AV_CODEC_ID_PCM_F32BE; + case 237: + return AV_CODEC_ID_PCM_F32LE; + case 238: + return AV_CODEC_ID_PCM_F64BE; + case 239: + return AV_CODEC_ID_PCM_F64LE; + case 240: + return AV_CODEC_ID_PCM_BLURAY; + case 241: + return AV_CODEC_ID_PCM_LXF; + case 242: + return AV_CODEC_ID_S302M; + case 243: + return AV_CODEC_ID_PCM_S8_PLANAR; + case 244: + return AV_CODEC_ID_PCM_S24LE_PLANAR; + case 245: + return AV_CODEC_ID_PCM_S32LE_PLANAR; + case 246: + return AV_CODEC_ID_PCM_S16BE_PLANAR; + case 247: + return AV_CODEC_ID_PCM_S64LE; + case 248: + return AV_CODEC_ID_PCM_S64BE; + case 249: + return AV_CODEC_ID_ADPCM_IMA_QT; + case 250: + return AV_CODEC_ID_ADPCM_IMA_WAV; + case 251: + return AV_CODEC_ID_ADPCM_IMA_DK3; + case 252: + return AV_CODEC_ID_ADPCM_IMA_DK4; + case 253: + return AV_CODEC_ID_ADPCM_IMA_WS; + case 254: + return AV_CODEC_ID_ADPCM_IMA_SMJPEG; + case 255: + return AV_CODEC_ID_ADPCM_MS; + case 256: + return AV_CODEC_ID_ADPCM_4XM; + case 257: + return AV_CODEC_ID_ADPCM_XA; + case 258: + return AV_CODEC_ID_ADPCM_ADX; + case 259: + return AV_CODEC_ID_ADPCM_EA; + case 260: + return AV_CODEC_ID_ADPCM_G726; + case 261: + return AV_CODEC_ID_ADPCM_CT; + case 262: + return AV_CODEC_ID_ADPCM_SWF; + case 263: + return AV_CODEC_ID_ADPCM_YAMAHA; + case 264: + return AV_CODEC_ID_ADPCM_SBPRO_4; + case 265: + return AV_CODEC_ID_ADPCM_SBPRO_3; + case 266: + return AV_CODEC_ID_ADPCM_SBPRO_2; + case 267: + return AV_CODEC_ID_ADPCM_THP; + case 268: + return AV_CODEC_ID_ADPCM_IMA_AMV; + case 269: + return AV_CODEC_ID_ADPCM_EA_R1; + case 270: + return AV_CODEC_ID_ADPCM_EA_R3; + case 271: + return AV_CODEC_ID_ADPCM_EA_R2; + case 272: + return AV_CODEC_ID_ADPCM_IMA_EA_SEAD; + case 273: + return AV_CODEC_ID_ADPCM_IMA_EA_EACS; + case 274: + return AV_CODEC_ID_ADPCM_EA_XAS; + case 275: + return AV_CODEC_ID_ADPCM_EA_MAXIS_XA; + case 276: + return AV_CODEC_ID_ADPCM_IMA_ISS; + case 277: + return AV_CODEC_ID_ADPCM_G722; + case 278: + return AV_CODEC_ID_ADPCM_IMA_APC; + case 279: + return AV_CODEC_ID_ADPCM_VIMA; + case 280: + return AV_CODEC_ID_ADPCM_AFC; + case 281: + return AV_CODEC_ID_ADPCM_IMA_OKI; + case 282: + return AV_CODEC_ID_ADPCM_DTK; + case 283: + return AV_CODEC_ID_ADPCM_IMA_RAD; + case 284: + return AV_CODEC_ID_ADPCM_G726LE; + case 285: + return AV_CODEC_ID_ADPCM_THP_LE; + case 286: + return AV_CODEC_ID_ADPCM_PSX; + case 287: + return AV_CODEC_ID_ADPCM_AICA; + case 288: + return AV_CODEC_ID_ADPCM_IMA_DAT4; + case 289: + return AV_CODEC_ID_ADPCM_MTAF; + case 290: + return AV_CODEC_ID_AMR_NB; + case 291: + return AV_CODEC_ID_AMR_WB; + case 292: + return AV_CODEC_ID_RA_144; + case 293: + return AV_CODEC_ID_RA_288; + case 294: + return AV_CODEC_ID_ROQ_DPCM; + case 295: + return AV_CODEC_ID_INTERPLAY_DPCM; + case 296: + return AV_CODEC_ID_XAN_DPCM; + case 297: + return AV_CODEC_ID_SOL_DPCM; + case 298: + return AV_CODEC_ID_SDX2_DPCM; + case 299: + return AV_CODEC_ID_MP2; + case 300: + return AV_CODEC_ID_MP3; + case 301: + return AV_CODEC_ID_AAC; + case 302: + return AV_CODEC_ID_AC3; + case 303: + return AV_CODEC_ID_DTS; + case 304: + return AV_CODEC_ID_VORBIS; + case 305: + return AV_CODEC_ID_DVAUDIO; + case 306: + return AV_CODEC_ID_WMAV1; + case 307: + return AV_CODEC_ID_WMAV2; + case 308: + return AV_CODEC_ID_MACE3; + case 309: + return AV_CODEC_ID_MACE6; + case 310: + return AV_CODEC_ID_VMDAUDIO; + case 311: + return AV_CODEC_ID_FLAC; + case 312: + return AV_CODEC_ID_MP3ADU; + case 313: + return AV_CODEC_ID_MP3ON4; + case 314: + return AV_CODEC_ID_SHORTEN; + case 315: + return AV_CODEC_ID_ALAC; + case 316: + return AV_CODEC_ID_WESTWOOD_SND1; + case 317: + return AV_CODEC_ID_GSM; + case 318: + return AV_CODEC_ID_QDM2; + case 319: + return AV_CODEC_ID_COOK; + case 320: + return AV_CODEC_ID_TRUESPEECH; + case 321: + return AV_CODEC_ID_TTA; + case 322: + return AV_CODEC_ID_SMACKAUDIO; + case 323: + return AV_CODEC_ID_QCELP; + case 324: + return AV_CODEC_ID_WAVPACK; + case 325: + return AV_CODEC_ID_DSICINAUDIO; + case 326: + return AV_CODEC_ID_IMC; + case 327: + return AV_CODEC_ID_MUSEPACK7; + case 328: + return AV_CODEC_ID_MLP; + case 329: + return AV_CODEC_ID_GSM_MS; + case 330: + return AV_CODEC_ID_ATRAC3; + // #[cfg(feature = "ff_api_voxware")] + // case 331: + // return AV_CODEC_ID_VOXWARE; + case 332: + return AV_CODEC_ID_APE; + case 333: + return AV_CODEC_ID_NELLYMOSER; + case 334: + return AV_CODEC_ID_MUSEPACK8; + case 335: + return AV_CODEC_ID_SPEEX; + case 336: + return AV_CODEC_ID_WMAVOICE; + case 337: + return AV_CODEC_ID_WMAPRO; + case 338: + return AV_CODEC_ID_WMALOSSLESS; + case 339: + return AV_CODEC_ID_ATRAC3P; + case 340: + return AV_CODEC_ID_EAC3; + case 341: + return AV_CODEC_ID_SIPR; + case 342: + return AV_CODEC_ID_MP1; + case 343: + return AV_CODEC_ID_TWINVQ; + case 344: + return AV_CODEC_ID_TRUEHD; + case 345: + return AV_CODEC_ID_MP4ALS; + case 346: + return AV_CODEC_ID_ATRAC1; + case 347: + return AV_CODEC_ID_BINKAUDIO_RDFT; + case 348: + return AV_CODEC_ID_BINKAUDIO_DCT; + case 349: + return AV_CODEC_ID_AAC_LATM; + case 350: + return AV_CODEC_ID_QDMC; + case 351: + return AV_CODEC_ID_CELT; + case 352: + return AV_CODEC_ID_G723_1; + case 353: + return AV_CODEC_ID_G729; + case 354: + return AV_CODEC_ID_8SVX_EXP; + case 355: + return AV_CODEC_ID_8SVX_FIB; + case 356: + return AV_CODEC_ID_BMV_AUDIO; + case 357: + return AV_CODEC_ID_RALF; + case 358: + return AV_CODEC_ID_IAC; + case 359: + return AV_CODEC_ID_ILBC; + case 360: + return AV_CODEC_ID_OPUS; + case 361: + return AV_CODEC_ID_COMFORT_NOISE; + case 362: + return AV_CODEC_ID_TAK; + case 363: + return AV_CODEC_ID_METASOUND; + case 364: + return AV_CODEC_ID_PAF_AUDIO; + case 365: + return AV_CODEC_ID_ON2AVC; + case 366: + return AV_CODEC_ID_DSS_SP; + case 367: + return AV_CODEC_ID_CODEC2; + case 368: + return AV_CODEC_ID_FFWAVESYNTH; + case 369: + return AV_CODEC_ID_SONIC; + case 370: + return AV_CODEC_ID_SONIC_LS; + case 371: + return AV_CODEC_ID_EVRC; + case 372: + return AV_CODEC_ID_SMV; + case 373: + return AV_CODEC_ID_DSD_LSBF; + case 374: + return AV_CODEC_ID_DSD_MSBF; + case 375: + return AV_CODEC_ID_DSD_LSBF_PLANAR; + case 376: + return AV_CODEC_ID_DSD_MSBF_PLANAR; + case 377: + return AV_CODEC_ID_4GV; + case 378: + return AV_CODEC_ID_INTERPLAY_ACM; + case 379: + return AV_CODEC_ID_XMA1; + case 380: + return AV_CODEC_ID_XMA2; + case 381: + return AV_CODEC_ID_DST; + ///////////// + ///////////// + ///////////// + case 382: + return AV_CODEC_ID_DVD_SUBTITLE; + case 383: + return AV_CODEC_ID_DVB_SUBTITLE; + case 384: + return AV_CODEC_ID_TEXT; + case 385: + return AV_CODEC_ID_XSUB; + case 386: + return AV_CODEC_ID_SSA; + case 387: + return AV_CODEC_ID_MOV_TEXT; + case 388: + return AV_CODEC_ID_HDMV_PGS_SUBTITLE; + case 389: + return AV_CODEC_ID_DVB_TELETEXT; + case 390: + return AV_CODEC_ID_SRT; + case 391: + return AV_CODEC_ID_MICRODVD; + case 392: + return AV_CODEC_ID_EIA_608; + case 393: + return AV_CODEC_ID_JACOSUB; + case 394: + return AV_CODEC_ID_SAMI; + case 395: + return AV_CODEC_ID_REALTEXT; + case 396: + return AV_CODEC_ID_STL; + case 397: + return AV_CODEC_ID_SUBVIEWER1; + case 398: + return AV_CODEC_ID_SUBVIEWER; + case 399: + return AV_CODEC_ID_SUBRIP; + case 400: + return AV_CODEC_ID_WEBVTT; + case 401: + return AV_CODEC_ID_MPL2; + case 402: + return AV_CODEC_ID_VPLAYER; + case 403: + return AV_CODEC_ID_PJS; + case 404: + return AV_CODEC_ID_ASS; + case 405: + return AV_CODEC_ID_HDMV_TEXT_SUBTITLE; + case 406: + return AV_CODEC_ID_TTF; + case 407: + return AV_CODEC_ID_SCTE_35; + case 408: + return AV_CODEC_ID_BINTEXT; + case 409: + return AV_CODEC_ID_XBIN; + case 410: + return AV_CODEC_ID_IDF; + case 411: + return AV_CODEC_ID_OTF; + case 412: + return AV_CODEC_ID_SMPTE_KLV; + case 413: + return AV_CODEC_ID_DVD_NAV; + case 414: + return AV_CODEC_ID_TIMED_ID3; + case 415: + return AV_CODEC_ID_BIN_DATA; + case 416: + return AV_CODEC_ID_PROBE; + case 417: + return AV_CODEC_ID_MPEG2TS; + case 418: + return AV_CODEC_ID_MPEG4SYSTEMS; + case 419: + return AV_CODEC_ID_FFMETADATA; + case 420: + return AV_CODEC_ID_WRAPPED_AVFRAME; + case 421: + return AV_CODEC_ID_PSD; + case 422: + return AV_CODEC_ID_PIXLET; + case 423: + return AV_CODEC_ID_SPEEDHQ; + case 424: + return AV_CODEC_ID_CLEARVIDEO; + case 425: + return AV_CODEC_ID_FMVC; + case 426: + return AV_CODEC_ID_SCPR; + case 427: + return AV_CODEC_ID_XPM; + case 428: + return AV_CODEC_ID_AV1; + case 429: + return AV_CODEC_ID_PCM_F16LE; + case 430: + return AV_CODEC_ID_PCM_F24LE; + //////////// + case 431: + return AV_CODEC_ID_ATRAC3AL; + case 432: + return AV_CODEC_ID_ATRAC3PAL; + case 433: + return AV_CODEC_ID_BITPACKED; + case 434: + return AV_CODEC_ID_MSCC; + case 435: + return AV_CODEC_ID_SRGC; + case 436: + return AV_CODEC_ID_SVG; + case 437: + return AV_CODEC_ID_GDV; + case 438: + return AV_CODEC_ID_FITS; + case 439: + return AV_CODEC_ID_GREMLIN_DPCM; + case 440: + return AV_CODEC_ID_DOLBY_E; + case 441: + return AV_CODEC_ID_APTX; + case 442: + return AV_CODEC_ID_APTX_HD; + case 443: + return AV_CODEC_ID_SBC; + case 444: + return AV_CODEC_ID_AVS2; + case 445: + return AV_CODEC_ID_IMM4; + case 446: + return AV_CODEC_ID_PROSUMER; + case 447: + return AV_CODEC_ID_MWSC; + case 448: + return AV_CODEC_ID_WCMV; + case 449: + return AV_CODEC_ID_RASC; + case 450: + return AV_CODEC_ID_PCM_VIDC; + case 451: + return AV_CODEC_ID_ATRAC9; + case 452: + return AV_CODEC_ID_TTML; + case 453: + return AV_CODEC_ID_HYMT; + case 454: + return AV_CODEC_ID_ARBC; + case 455: + return AV_CODEC_ID_AGM; + case 456: + return AV_CODEC_ID_LSCR; + case 457: + return AV_CODEC_ID_VP4; + case 458: + return AV_CODEC_ID_ADPCM_AGM; + case 459: + return AV_CODEC_ID_HCOM; + case 460: + return AV_CODEC_ID_ARIB_CAPTION; + case 461: + return AV_CODEC_ID_IMM5; + case 462: + return AV_CODEC_ID_MVDV; + case 463: + return AV_CODEC_ID_MVHA; + case 464: + return AV_CODEC_ID_CDTOONS; + case 465: + return AV_CODEC_ID_MV30; + case 466: + return AV_CODEC_ID_NOTCHLC; + case 467: + return AV_CODEC_ID_PFM; + case 468: + return AV_CODEC_ID_ARGO; + case 469: + return AV_CODEC_ID_ADPCM_IMA_SSI; + case 470: + return AV_CODEC_ID_ADPCM_ZORK; + case 471: + return AV_CODEC_ID_ADPCM_IMA_APM; + case 472: + return AV_CODEC_ID_ADPCM_IMA_ALP; + case 473: + return AV_CODEC_ID_ADPCM_IMA_MTF; + case 474: + return AV_CODEC_ID_ADPCM_IMA_CUNNING; + case 475: + return AV_CODEC_ID_DERF_DPCM; + case 476: + return AV_CODEC_ID_ACELP_KELVIN; + case 477: + return AV_CODEC_ID_MPEGH_3D_AUDIO; + case 478: + return AV_CODEC_ID_SIREN; + case 479: + return AV_CODEC_ID_HCA; + case 480: + return AV_CODEC_ID_EPG; + case 481: + return AV_CODEC_ID_AVS3; + case 482: + return AV_CODEC_ID_PGX; + case 483: + return AV_CODEC_ID_MSP2; + case 484: + return AV_CODEC_ID_VVC; + case 485: + return AV_CODEC_ID_MOBICLIP; + case 486: + return AV_CODEC_ID_PHOTOCD; + case 487: + return AV_CODEC_ID_ADPCM_ARGO; + case 488: + return AV_CODEC_ID_CRI; + case 489: + return AV_CODEC_ID_IPU; + case 490: + return AV_CODEC_ID_SIMBIOSIS_IMX; + case 491: + return AV_CODEC_ID_SGA_VIDEO; + case 492: + return AV_CODEC_ID_PCM_SGA; + case 493: + return AV_CODEC_ID_ADPCM_IMA_MOFLEX; + case 494: + return AV_CODEC_ID_FASTAUDIO; + case 495: + return AV_CODEC_ID_GEM; + case 496: + return AV_CODEC_ID_ADPCM_IMA_ACORN; + case 497: + return AV_CODEC_ID_MSNSIREN; + case 498: + return AV_CODEC_ID_VBN; + case 499: + return AV_CODEC_ID_JPEGXL; + case 500: + return AV_CODEC_ID_QOI; + case 501: + return AV_CODEC_ID_PHM; + case 502: + return AV_CODEC_ID_DFPWM; + case 503: + return AV_CODEC_ID_RADIANCE_HDR; + case 504: + return AV_CODEC_ID_WBMP; + case 505: + return AV_CODEC_ID_MEDIA100; + case 506: + return AV_CODEC_ID_VQC; + case 507: + return AV_CODEC_ID_ADPCM_XMD; + case 508: + return AV_CODEC_ID_WADY_DPCM; + case 509: + return AV_CODEC_ID_CBD2_DPCM; + case 510: + return AV_CODEC_ID_BONK; + case 511: + return AV_CODEC_ID_MISC4; + case 512: + return AV_CODEC_ID_APAC; + case 513: + return AV_CODEC_ID_FTR; + case 514: + return AV_CODEC_ID_WAVARC; + case 515: + return AV_CODEC_ID_RKA; + case 516: + return AV_CODEC_ID_VNULL; + case 517: + return AV_CODEC_ID_ANULL; + // case 518: + // return AV_CODEC_ID_MPEG2VIDEO_XVMC; + default: + return AV_CODEC_ID_NONE; + }; + } + + // Convert AVCodecID to uint32_t for rust SDK. + static uint32_t fromAVCodecID(AVCodecID AvCodecId) { + switch (AvCodecId) { + case AV_CODEC_ID_NONE: + return 0; + case AV_CODEC_ID_MPEG1VIDEO: + return 1; + case AV_CODEC_ID_MPEG2VIDEO: + return 2; + case AV_CODEC_ID_H261: + return 3; + case AV_CODEC_ID_H263: + return 4; + case AV_CODEC_ID_RV10: + return 5; + case AV_CODEC_ID_RV20: + return 6; + case AV_CODEC_ID_MJPEG: + return 7; + case AV_CODEC_ID_MJPEGB: + return 8; + case AV_CODEC_ID_LJPEG: + return 9; + case AV_CODEC_ID_SP5X: + return 10; + case AV_CODEC_ID_JPEGLS: + return 11; + case AV_CODEC_ID_MPEG4: + return 12; + case AV_CODEC_ID_RAWVIDEO: + return 13; + case AV_CODEC_ID_MSMPEG4V1: + return 14; + case AV_CODEC_ID_MSMPEG4V2: + return 15; + case AV_CODEC_ID_MSMPEG4V3: + return 16; + case AV_CODEC_ID_WMV1: + return 17; + case AV_CODEC_ID_WMV2: + return 18; + case AV_CODEC_ID_H263P: + return 19; + case AV_CODEC_ID_H263I: + return 20; + case AV_CODEC_ID_FLV1: + return 21; + case AV_CODEC_ID_SVQ1: + return 22; + case AV_CODEC_ID_SVQ3: + return 23; + case AV_CODEC_ID_DVVIDEO: + return 24; + case AV_CODEC_ID_HUFFYUV: + return 25; + case AV_CODEC_ID_CYUV: + return 26; + case AV_CODEC_ID_H264: + return 27; + case AV_CODEC_ID_INDEO3: + return 28; + case AV_CODEC_ID_VP3: + return 29; + case AV_CODEC_ID_THEORA: + return 30; + case AV_CODEC_ID_ASV1: + return 31; + case AV_CODEC_ID_ASV2: + return 32; + case AV_CODEC_ID_FFV1: + return 33; + case AV_CODEC_ID_4XM: + return 34; + case AV_CODEC_ID_VCR1: + return 35; + case AV_CODEC_ID_CLJR: + return 36; + case AV_CODEC_ID_MDEC: + return 37; + case AV_CODEC_ID_ROQ: + return 38; + case AV_CODEC_ID_INTERPLAY_VIDEO: + return 39; + case AV_CODEC_ID_XAN_WC3: + return 40; + case AV_CODEC_ID_XAN_WC4: + return 41; + case AV_CODEC_ID_RPZA: + return 42; + case AV_CODEC_ID_CINEPAK: + return 43; + case AV_CODEC_ID_WS_VQA: + return 44; + case AV_CODEC_ID_MSRLE: + return 45; + case AV_CODEC_ID_MSVIDEO1: + return 46; + case AV_CODEC_ID_IDCIN: + return 47; + case AV_CODEC_ID_8BPS: + return 48; + case AV_CODEC_ID_SMC: + return 49; + case AV_CODEC_ID_FLIC: + return 50; + case AV_CODEC_ID_TRUEMOTION1: + return 51; + case AV_CODEC_ID_VMDVIDEO: + return 52; + case AV_CODEC_ID_MSZH: + return 53; + case AV_CODEC_ID_ZLIB: + return 54; + case AV_CODEC_ID_QTRLE: + return 55; + case AV_CODEC_ID_TSCC: + return 56; + case AV_CODEC_ID_ULTI: + return 57; + case AV_CODEC_ID_QDRAW: + return 58; + case AV_CODEC_ID_VIXL: + return 59; + case AV_CODEC_ID_QPEG: + return 60; + case AV_CODEC_ID_PNG: + return 61; + case AV_CODEC_ID_PPM: + return 62; + case AV_CODEC_ID_PBM: + return 63; + case AV_CODEC_ID_PGM: + return 64; + case AV_CODEC_ID_PGMYUV: + return 65; + case AV_CODEC_ID_PAM: + return 66; + case AV_CODEC_ID_FFVHUFF: + return 67; + case AV_CODEC_ID_RV30: + return 68; + case AV_CODEC_ID_RV40: + return 69; + case AV_CODEC_ID_VC1: + return 70; + case AV_CODEC_ID_WMV3: + return 71; + case AV_CODEC_ID_LOCO: + return 72; + case AV_CODEC_ID_WNV1: + return 73; + case AV_CODEC_ID_AASC: + return 74; + case AV_CODEC_ID_INDEO2: + return 75; + case AV_CODEC_ID_FRAPS: + return 76; + case AV_CODEC_ID_TRUEMOTION2: + return 77; + case AV_CODEC_ID_BMP: + return 78; + case AV_CODEC_ID_CSCD: + return 79; + case AV_CODEC_ID_MMVIDEO: + return 80; + case AV_CODEC_ID_ZMBV: + return 81; + case AV_CODEC_ID_AVS: + return 82; + case AV_CODEC_ID_SMACKVIDEO: + return 83; + case AV_CODEC_ID_NUV: + return 84; + case AV_CODEC_ID_KMVC: + return 85; + case AV_CODEC_ID_FLASHSV: + return 86; + case AV_CODEC_ID_CAVS: + return 87; + case AV_CODEC_ID_JPEG2000: + return 88; + case AV_CODEC_ID_VMNC: + return 89; + case AV_CODEC_ID_VP5: + return 90; + case AV_CODEC_ID_VP6: + return 91; + case AV_CODEC_ID_VP6F: + return 92; + case AV_CODEC_ID_TARGA: + return 93; + case AV_CODEC_ID_DSICINVIDEO: + return 94; + case AV_CODEC_ID_TIERTEXSEQVIDEO: + return 95; + case AV_CODEC_ID_TIFF: + return 96; + case AV_CODEC_ID_GIF: + return 97; + case AV_CODEC_ID_DXA: + return 98; + case AV_CODEC_ID_DNXHD: + return 99; + case AV_CODEC_ID_THP: + return 100; + case AV_CODEC_ID_SGI: + return 101; + case AV_CODEC_ID_C93: + return 102; + case AV_CODEC_ID_BETHSOFTVID: + return 103; + case AV_CODEC_ID_PTX: + return 104; + case AV_CODEC_ID_TXD: + return 105; + case AV_CODEC_ID_VP6A: + return 106; + case AV_CODEC_ID_AMV: + return 107; + case AV_CODEC_ID_VB: + return 108; + case AV_CODEC_ID_PCX: + return 109; + case AV_CODEC_ID_SUNRAST: + return 110; + case AV_CODEC_ID_INDEO4: + return 111; + case AV_CODEC_ID_INDEO5: + return 112; + case AV_CODEC_ID_MIMIC: + return 113; + case AV_CODEC_ID_RL2: + return 114; + case AV_CODEC_ID_ESCAPE124: + return 115; + case AV_CODEC_ID_DIRAC: + return 116; + case AV_CODEC_ID_BFI: + return 117; + case AV_CODEC_ID_CMV: + return 118; + case AV_CODEC_ID_MOTIONPIXELS: + return 119; + case AV_CODEC_ID_TGV: + return 120; + case AV_CODEC_ID_TGQ: + return 121; + case AV_CODEC_ID_TQI: + return 122; + case AV_CODEC_ID_AURA: + return 123; + case AV_CODEC_ID_AURA2: + return 124; + case AV_CODEC_ID_V210X: + return 125; + case AV_CODEC_ID_TMV: + return 126; + case AV_CODEC_ID_V210: + return 127; + case AV_CODEC_ID_DPX: + return 128; + case AV_CODEC_ID_MAD: + return 129; + case AV_CODEC_ID_FRWU: + return 130; + case AV_CODEC_ID_FLASHSV2: + return 131; + case AV_CODEC_ID_CDGRAPHICS: + return 132; + case AV_CODEC_ID_R210: + return 133; + case AV_CODEC_ID_ANM: + return 134; + case AV_CODEC_ID_BINKVIDEO: + return 135; + case AV_CODEC_ID_IFF_ILBM: + return 136; + // case AV_CODEC_ID_IFF_ILBM: + // return 137; + case AV_CODEC_ID_KGV1: + return 138; + case AV_CODEC_ID_YOP: + return 139; + case AV_CODEC_ID_VP8: + return 140; + case AV_CODEC_ID_PICTOR: + return 141; + case AV_CODEC_ID_ANSI: + return 142; + case AV_CODEC_ID_A64_MULTI: + return 143; + case AV_CODEC_ID_A64_MULTI5: + return 144; + case AV_CODEC_ID_R10K: + return 145; + case AV_CODEC_ID_MXPEG: + return 146; + case AV_CODEC_ID_LAGARITH: + return 147; + case AV_CODEC_ID_PRORES: + return 148; + case AV_CODEC_ID_JV: + return 149; + case AV_CODEC_ID_DFA: + return 150; + case AV_CODEC_ID_WMV3IMAGE: + return 151; + case AV_CODEC_ID_VC1IMAGE: + return 152; + case AV_CODEC_ID_UTVIDEO: + return 153; + case AV_CODEC_ID_BMV_VIDEO: + return 154; + case AV_CODEC_ID_VBLE: + return 155; + case AV_CODEC_ID_DXTORY: + return 156; + case AV_CODEC_ID_V410: + return 157; + case AV_CODEC_ID_XWD: + return 158; + case AV_CODEC_ID_CDXL: + return 159; + case AV_CODEC_ID_XBM: + return 160; + case AV_CODEC_ID_ZEROCODEC: + return 161; + case AV_CODEC_ID_MSS1: + return 162; + case AV_CODEC_ID_MSA1: + return 163; + case AV_CODEC_ID_TSCC2: + return 164; + case AV_CODEC_ID_MTS2: + return 165; + case AV_CODEC_ID_CLLC: + return 166; + case AV_CODEC_ID_MSS2: + return 167; + case AV_CODEC_ID_VP9: + return 168; + case AV_CODEC_ID_AIC: + return 169; + case AV_CODEC_ID_ESCAPE130: + return 170; + case AV_CODEC_ID_G2M: + return 171; + case AV_CODEC_ID_WEBP: + return 172; + case AV_CODEC_ID_HNM4_VIDEO: + return 173; + case AV_CODEC_ID_HEVC: + return 174; + // case AV_CODEC_ID_HEVC: + // return 175; + case AV_CODEC_ID_FIC: + return 176; + case AV_CODEC_ID_ALIAS_PIX: + return 177; + case AV_CODEC_ID_BRENDER_PIX: + return 178; + case AV_CODEC_ID_PAF_VIDEO: + return 179; + case AV_CODEC_ID_EXR: + return 180; + case AV_CODEC_ID_VP7: + return 181; + case AV_CODEC_ID_SANM: + return 182; + case AV_CODEC_ID_SGIRLE: + return 183; + case AV_CODEC_ID_MVC1: + return 184; + case AV_CODEC_ID_MVC2: + return 185; + case AV_CODEC_ID_HQX: + return 186; + case AV_CODEC_ID_TDSC: + return 187; + case AV_CODEC_ID_HQ_HQA: + return 188; + case AV_CODEC_ID_HAP: + return 189; + case AV_CODEC_ID_DDS: + return 190; + case AV_CODEC_ID_DXV: + return 191; + case AV_CODEC_ID_SCREENPRESSO: + return 192; + case AV_CODEC_ID_RSCC: + return 193; + /////////////////////////////// + // return ; + // case AV_CODEC_ID_Y41P: + // return ; + // case AV_CODEC_ID_AVS2: + case AV_CODEC_ID_Y41P: + return 194; + case AV_CODEC_ID_AVRP: + return 195; + case AV_CODEC_ID_012V: + return 196; + case AV_CODEC_ID_AVUI: + return 197; + case AV_CODEC_ID_AYUV: + return 198; + case AV_CODEC_ID_TARGA_Y216: + return 199; + case AV_CODEC_ID_V308: + return 200; + case AV_CODEC_ID_V408: + return 201; + case AV_CODEC_ID_YUV4: + return 202; + case AV_CODEC_ID_AVRN: + return 203; + case AV_CODEC_ID_CPIA: + return 204; + case AV_CODEC_ID_XFACE: + return 205; + case AV_CODEC_ID_SNOW: + return 206; + case AV_CODEC_ID_SMVJPEG: + return 207; + case AV_CODEC_ID_APNG: + return 208; + case AV_CODEC_ID_DAALA: + return 209; + case AV_CODEC_ID_CFHD: + return 210; + case AV_CODEC_ID_TRUEMOTION2RT: + return 211; + case AV_CODEC_ID_M101: + return 212; + case AV_CODEC_ID_MAGICYUV: + return 213; + case AV_CODEC_ID_SHEERVIDEO: + return 214; + case AV_CODEC_ID_YLC: + return 215; + // ================================= + // ================================= + // ================================= + case AV_CODEC_ID_PCM_S16LE: + return 216; + case AV_CODEC_ID_PCM_S16BE: + return 217; + case AV_CODEC_ID_PCM_U16LE: + return 218; + case AV_CODEC_ID_PCM_U16BE: + return 219; + case AV_CODEC_ID_PCM_S8: + return 220; + case AV_CODEC_ID_PCM_U8: + return 221; + case AV_CODEC_ID_PCM_MULAW: + return 222; + case AV_CODEC_ID_PCM_ALAW: + return 223; + case AV_CODEC_ID_PCM_S32LE: + return 224; + case AV_CODEC_ID_PCM_S32BE: + return 225; + case AV_CODEC_ID_PCM_U32LE: + return 226; + case AV_CODEC_ID_PCM_U32BE: + return 227; + case AV_CODEC_ID_PCM_S24LE: + return 228; + case AV_CODEC_ID_PCM_S24BE: + return 229; + case AV_CODEC_ID_PCM_U24LE: + return 230; + case AV_CODEC_ID_PCM_U24BE: + return 231; + case AV_CODEC_ID_PCM_S24DAUD: + return 232; + case AV_CODEC_ID_PCM_ZORK: + return 233; + case AV_CODEC_ID_PCM_S16LE_PLANAR: + return 234; + case AV_CODEC_ID_PCM_DVD: + return 235; + case AV_CODEC_ID_PCM_F32BE: + return 236; + case AV_CODEC_ID_PCM_F32LE: + return 237; + case AV_CODEC_ID_PCM_F64BE: + return 238; + case AV_CODEC_ID_PCM_F64LE: + return 239; + case AV_CODEC_ID_PCM_BLURAY: + return 240; + case AV_CODEC_ID_PCM_LXF: + return 241; + case AV_CODEC_ID_S302M: + return 242; + case AV_CODEC_ID_PCM_S8_PLANAR: + return 243; + case AV_CODEC_ID_PCM_S24LE_PLANAR: + return 244; + case AV_CODEC_ID_PCM_S32LE_PLANAR: + return 245; + case AV_CODEC_ID_PCM_S16BE_PLANAR: + return 246; + case AV_CODEC_ID_PCM_S64LE: + return 247; + case AV_CODEC_ID_PCM_S64BE: + return 248; + case AV_CODEC_ID_ADPCM_IMA_QT: + return 249; + case AV_CODEC_ID_ADPCM_IMA_WAV: + return 250; + case AV_CODEC_ID_ADPCM_IMA_DK3: + return 251; + case AV_CODEC_ID_ADPCM_IMA_DK4: + return 252; + case AV_CODEC_ID_ADPCM_IMA_WS: + return 253; + case AV_CODEC_ID_ADPCM_IMA_SMJPEG: + return 254; + case AV_CODEC_ID_ADPCM_MS: + return 255; + case AV_CODEC_ID_ADPCM_4XM: + return 256; + case AV_CODEC_ID_ADPCM_XA: + return 257; + case AV_CODEC_ID_ADPCM_ADX: + return 258; + case AV_CODEC_ID_ADPCM_EA: + return 259; + case AV_CODEC_ID_ADPCM_G726: + return 260; + case AV_CODEC_ID_ADPCM_CT: + return 261; + case AV_CODEC_ID_ADPCM_SWF: + return 262; + case AV_CODEC_ID_ADPCM_YAMAHA: + return 263; + case AV_CODEC_ID_ADPCM_SBPRO_4: + return 264; + case AV_CODEC_ID_ADPCM_SBPRO_3: + return 265; + case AV_CODEC_ID_ADPCM_SBPRO_2: + return 266; + case AV_CODEC_ID_ADPCM_THP: + return 267; + case AV_CODEC_ID_ADPCM_IMA_AMV: + return 268; + case AV_CODEC_ID_ADPCM_EA_R1: + return 269; + case AV_CODEC_ID_ADPCM_EA_R3: + return 270; + case AV_CODEC_ID_ADPCM_EA_R2: + return 271; + case AV_CODEC_ID_ADPCM_IMA_EA_SEAD: + return 272; + case AV_CODEC_ID_ADPCM_IMA_EA_EACS: + return 273; + case AV_CODEC_ID_ADPCM_EA_XAS: + return 274; + case AV_CODEC_ID_ADPCM_EA_MAXIS_XA: + return 275; + case AV_CODEC_ID_ADPCM_IMA_ISS: + return 276; + case AV_CODEC_ID_ADPCM_G722: + return 277; + case AV_CODEC_ID_ADPCM_IMA_APC: + return 278; + case AV_CODEC_ID_ADPCM_VIMA: + return 279; + case AV_CODEC_ID_ADPCM_AFC: + return 280; + case AV_CODEC_ID_ADPCM_IMA_OKI: + return 281; + case AV_CODEC_ID_ADPCM_DTK: + return 282; + case AV_CODEC_ID_ADPCM_IMA_RAD: + return 283; + case AV_CODEC_ID_ADPCM_G726LE: + return 284; + case AV_CODEC_ID_ADPCM_THP_LE: + return 285; + case AV_CODEC_ID_ADPCM_PSX: + return 286; + case AV_CODEC_ID_ADPCM_AICA: + return 287; + case AV_CODEC_ID_ADPCM_IMA_DAT4: + return 288; + case AV_CODEC_ID_ADPCM_MTAF: + return 289; + case AV_CODEC_ID_AMR_NB: + return 290; + case AV_CODEC_ID_AMR_WB: + return 291; + case AV_CODEC_ID_RA_144: + return 292; + case AV_CODEC_ID_RA_288: + return 293; + case AV_CODEC_ID_ROQ_DPCM: + return 294; + case AV_CODEC_ID_INTERPLAY_DPCM: + return 295; + case AV_CODEC_ID_XAN_DPCM: + return 296; + case AV_CODEC_ID_SOL_DPCM: + return 297; + case AV_CODEC_ID_SDX2_DPCM: + return 298; + case AV_CODEC_ID_MP2: + return 299; + case AV_CODEC_ID_MP3: + return 300; + case AV_CODEC_ID_AAC: + return 301; + case AV_CODEC_ID_AC3: + return 302; + case AV_CODEC_ID_DTS: + return 303; + case AV_CODEC_ID_VORBIS: + return 304; + case AV_CODEC_ID_DVAUDIO: + return 305; + case AV_CODEC_ID_WMAV1: + return 306; + case AV_CODEC_ID_WMAV2: + return 307; + case AV_CODEC_ID_MACE3: + return 308; + case AV_CODEC_ID_MACE6: + return 309; + case AV_CODEC_ID_VMDAUDIO: + return 310; + case AV_CODEC_ID_FLAC: + return 311; + case AV_CODEC_ID_MP3ADU: + return 312; + case AV_CODEC_ID_MP3ON4: + return 313; + case AV_CODEC_ID_SHORTEN: + return 314; + case AV_CODEC_ID_ALAC: + return 315; + case AV_CODEC_ID_WESTWOOD_SND1: + return 316; + case AV_CODEC_ID_GSM: + return 317; + case AV_CODEC_ID_QDM2: + return 318; + case AV_CODEC_ID_COOK: + return 319; + case AV_CODEC_ID_TRUESPEECH: + return 320; + case AV_CODEC_ID_TTA: + return 321; + case AV_CODEC_ID_SMACKAUDIO: + return 322; + case AV_CODEC_ID_QCELP: + return 323; + case AV_CODEC_ID_WAVPACK: + return 324; + case AV_CODEC_ID_DSICINAUDIO: + return 325; + case AV_CODEC_ID_IMC: + return 326; + case AV_CODEC_ID_MUSEPACK7: + return 327; + case AV_CODEC_ID_MLP: + return 328; + case AV_CODEC_ID_GSM_MS: + return 329; + case AV_CODEC_ID_ATRAC3: + return 330; + // #[cfg(feature = "ff_api_voxware")] + // case AV_CODEC_ID_VOXWARE: + // return 331; + case AV_CODEC_ID_APE: + return 332; + case AV_CODEC_ID_NELLYMOSER: + return 333; + case AV_CODEC_ID_MUSEPACK8: + return 334; + case AV_CODEC_ID_SPEEX: + return 335; + case AV_CODEC_ID_WMAVOICE: + return 336; + case AV_CODEC_ID_WMAPRO: + return 337; + case AV_CODEC_ID_WMALOSSLESS: + return 338; + case AV_CODEC_ID_ATRAC3P: + return 339; + case AV_CODEC_ID_EAC3: + return 340; + case AV_CODEC_ID_SIPR: + return 341; + case AV_CODEC_ID_MP1: + return 342; + case AV_CODEC_ID_TWINVQ: + return 343; + case AV_CODEC_ID_TRUEHD: + return 344; + case AV_CODEC_ID_MP4ALS: + return 345; + case AV_CODEC_ID_ATRAC1: + return 346; + case AV_CODEC_ID_BINKAUDIO_RDFT: + return 347; + case AV_CODEC_ID_BINKAUDIO_DCT: + return 348; + case AV_CODEC_ID_AAC_LATM: + return 349; + case AV_CODEC_ID_QDMC: + return 350; + case AV_CODEC_ID_CELT: + return 351; + case AV_CODEC_ID_G723_1: + return 352; + case AV_CODEC_ID_G729: + return 353; + case AV_CODEC_ID_8SVX_EXP: + return 354; + case AV_CODEC_ID_8SVX_FIB: + return 355; + case AV_CODEC_ID_BMV_AUDIO: + return 356; + case AV_CODEC_ID_RALF: + return 357; + case AV_CODEC_ID_IAC: + return 358; + case AV_CODEC_ID_ILBC: + return 359; + case AV_CODEC_ID_OPUS: + return 360; + case AV_CODEC_ID_COMFORT_NOISE: + return 361; + case AV_CODEC_ID_TAK: + return 362; + case AV_CODEC_ID_METASOUND: + return 363; + case AV_CODEC_ID_PAF_AUDIO: + return 364; + case AV_CODEC_ID_ON2AVC: + return 365; + case AV_CODEC_ID_DSS_SP: + return 366; + case AV_CODEC_ID_CODEC2: + return 367; + case AV_CODEC_ID_FFWAVESYNTH: + return 368; + case AV_CODEC_ID_SONIC: + return 369; + case AV_CODEC_ID_SONIC_LS: + return 370; + case AV_CODEC_ID_EVRC: + return 371; + case AV_CODEC_ID_SMV: + return 372; + case AV_CODEC_ID_DSD_LSBF: + return 373; + case AV_CODEC_ID_DSD_MSBF: + return 374; + case AV_CODEC_ID_DSD_LSBF_PLANAR: + return 375; + case AV_CODEC_ID_DSD_MSBF_PLANAR: + return 376; + case AV_CODEC_ID_4GV: + return 377; + case AV_CODEC_ID_INTERPLAY_ACM: + return 378; + case AV_CODEC_ID_XMA1: + return 379; + case AV_CODEC_ID_XMA2: + return 380; + case AV_CODEC_ID_DST: + return 381; + case AV_CODEC_ID_DVD_SUBTITLE: + return 382; + case AV_CODEC_ID_DVB_SUBTITLE: + return 383; + case AV_CODEC_ID_TEXT: + return 384; + case AV_CODEC_ID_XSUB: + return 385; + case AV_CODEC_ID_SSA: + return 386; + case AV_CODEC_ID_MOV_TEXT: + return 387; + case AV_CODEC_ID_HDMV_PGS_SUBTITLE: + return 388; + case AV_CODEC_ID_DVB_TELETEXT: + return 389; + case AV_CODEC_ID_SRT: + return 390; + case AV_CODEC_ID_MICRODVD: + return 391; + case AV_CODEC_ID_EIA_608: + return 392; + case AV_CODEC_ID_JACOSUB: + return 393; + case AV_CODEC_ID_SAMI: + return 394; + case AV_CODEC_ID_REALTEXT: + return 395; + case AV_CODEC_ID_STL: + return 396; + case AV_CODEC_ID_SUBVIEWER1: + return 397; + case AV_CODEC_ID_SUBVIEWER: + return 398; + case AV_CODEC_ID_SUBRIP: + return 399; + case AV_CODEC_ID_WEBVTT: + return 400; + case AV_CODEC_ID_MPL2: + return 401; + case AV_CODEC_ID_VPLAYER: + return 402; + case AV_CODEC_ID_PJS: + return 403; + case AV_CODEC_ID_ASS: + return 404; + case AV_CODEC_ID_HDMV_TEXT_SUBTITLE: + return 405; + case AV_CODEC_ID_TTF: + return 406; + case AV_CODEC_ID_SCTE_35: + return 407; + case AV_CODEC_ID_BINTEXT: + return 408; + case AV_CODEC_ID_XBIN: + return 409; + case AV_CODEC_ID_IDF: + return 410; + case AV_CODEC_ID_OTF: + return 411; + case AV_CODEC_ID_SMPTE_KLV: + return 412; + case AV_CODEC_ID_DVD_NAV: + return 413; + case AV_CODEC_ID_TIMED_ID3: + return 414; + case AV_CODEC_ID_BIN_DATA: + return 415; + case AV_CODEC_ID_PROBE: + return 416; + case AV_CODEC_ID_MPEG2TS: + return 417; + case AV_CODEC_ID_MPEG4SYSTEMS: + return 418; + case AV_CODEC_ID_FFMETADATA: + return 419; + case AV_CODEC_ID_WRAPPED_AVFRAME: + return 420; + case AV_CODEC_ID_PSD: + return 421; + case AV_CODEC_ID_PIXLET: + return 422; + case AV_CODEC_ID_SPEEDHQ: + return 423; + case AV_CODEC_ID_CLEARVIDEO: + return 424; + case AV_CODEC_ID_FMVC: + return 425; + case AV_CODEC_ID_SCPR: + return 426; + case AV_CODEC_ID_XPM: + return 427; + case AV_CODEC_ID_AV1: + return 428; + case AV_CODEC_ID_PCM_F16LE: + return 429; + case AV_CODEC_ID_PCM_F24LE: + return 430; + //////////// + case AV_CODEC_ID_ATRAC3AL: + return 431; + case AV_CODEC_ID_ATRAC3PAL: + return 432; + case AV_CODEC_ID_BITPACKED: + return 433; + case AV_CODEC_ID_MSCC: + return 434; + case AV_CODEC_ID_SRGC: + return 435; + case AV_CODEC_ID_SVG: + return 436; + case AV_CODEC_ID_GDV: + return 437; + case AV_CODEC_ID_FITS: + return 438; + case AV_CODEC_ID_GREMLIN_DPCM: + return 439; + case AV_CODEC_ID_DOLBY_E: + return 440; + case AV_CODEC_ID_APTX: + return 441; + case AV_CODEC_ID_APTX_HD: + return 442; + case AV_CODEC_ID_SBC: + return 443; + case AV_CODEC_ID_AVS2: + return 444; + case AV_CODEC_ID_IMM4: + return 445; + case AV_CODEC_ID_PROSUMER: + return 446; + case AV_CODEC_ID_MWSC: + return 447; + case AV_CODEC_ID_WCMV: + return 448; + case AV_CODEC_ID_RASC: + return 449; + case AV_CODEC_ID_PCM_VIDC: + return 450; + case AV_CODEC_ID_ATRAC9: + return 451; + case AV_CODEC_ID_TTML: + return 452; + case AV_CODEC_ID_HYMT: + return 453; + case AV_CODEC_ID_ARBC: + return 454; + case AV_CODEC_ID_AGM: + return 455; + case AV_CODEC_ID_LSCR: + return 456; + case AV_CODEC_ID_VP4: + return 457; + case AV_CODEC_ID_ADPCM_AGM: + return 458; + case AV_CODEC_ID_HCOM: + return 459; + case AV_CODEC_ID_ARIB_CAPTION: + return 460; + case AV_CODEC_ID_IMM5: + return 461; + case AV_CODEC_ID_MVDV: + return 462; + case AV_CODEC_ID_MVHA: + return 463; + case AV_CODEC_ID_CDTOONS: + return 464; + case AV_CODEC_ID_MV30: + return 465; + case AV_CODEC_ID_NOTCHLC: + return 466; + case AV_CODEC_ID_PFM: + return 467; + case AV_CODEC_ID_ARGO: + return 468; + case AV_CODEC_ID_ADPCM_IMA_SSI: + return 469; + case AV_CODEC_ID_ADPCM_ZORK: + return 470; + case AV_CODEC_ID_ADPCM_IMA_APM: + return 471; + case AV_CODEC_ID_ADPCM_IMA_ALP: + return 472; + case AV_CODEC_ID_ADPCM_IMA_MTF: + return 473; + case AV_CODEC_ID_ADPCM_IMA_CUNNING: + return 474; + case AV_CODEC_ID_DERF_DPCM: + return 475; + case AV_CODEC_ID_ACELP_KELVIN: + return 476; + case AV_CODEC_ID_MPEGH_3D_AUDIO: + return 477; + case AV_CODEC_ID_SIREN: + return 478; + case AV_CODEC_ID_HCA: + return 479; + case AV_CODEC_ID_EPG: + return 480; + case AV_CODEC_ID_AVS3: + return 481; + case AV_CODEC_ID_PGX: + return 482; + case AV_CODEC_ID_MSP2: + return 483; + case AV_CODEC_ID_VVC: + return 484; + case AV_CODEC_ID_MOBICLIP: + return 485; + case AV_CODEC_ID_PHOTOCD: + return 486; + case AV_CODEC_ID_ADPCM_ARGO: + return 487; + case AV_CODEC_ID_CRI: + return 488; + case AV_CODEC_ID_IPU: + return 489; + case AV_CODEC_ID_SIMBIOSIS_IMX: + return 490; + case AV_CODEC_ID_SGA_VIDEO: + return 491; + case AV_CODEC_ID_PCM_SGA: + return 492; + case AV_CODEC_ID_ADPCM_IMA_MOFLEX: + return 493; + case AV_CODEC_ID_FASTAUDIO: + return 494; + case AV_CODEC_ID_GEM: + return 495; + case AV_CODEC_ID_ADPCM_IMA_ACORN: + return 496; + case AV_CODEC_ID_MSNSIREN: + return 497; + case AV_CODEC_ID_VBN: + return 498; + case AV_CODEC_ID_JPEGXL: + return 499; + case AV_CODEC_ID_QOI: + return 500; + case AV_CODEC_ID_PHM: + return 501; + case AV_CODEC_ID_DFPWM: + return 502; + case AV_CODEC_ID_RADIANCE_HDR: + return 503; + case AV_CODEC_ID_WBMP: + return 504; + case AV_CODEC_ID_MEDIA100: + return 505; + case AV_CODEC_ID_VQC: + return 506; + case AV_CODEC_ID_ADPCM_XMD: + return 507; + case AV_CODEC_ID_WADY_DPCM: + return 508; + case AV_CODEC_ID_CBD2_DPCM: + return 509; + case AV_CODEC_ID_BONK: + return 510; + case AV_CODEC_ID_MISC4: + return 511; + case AV_CODEC_ID_APAC: + return 512; + case AV_CODEC_ID_FTR: + return 513; + case AV_CODEC_ID_WAVARC: + return 514; + case AV_CODEC_ID_RKA: + return 515; + case AV_CODEC_ID_VNULL: + return 516; + case AV_CODEC_ID_ANULL: + return 517; + // case AV_CODEC_ID_MPEG2VIDEO_XVMC: + // return 518; + default: + return 0; + } + } +}; + +class PixFmt { + +public: + static uint32_t fromAVPixFmt(AVPixelFormat AvPixelFormat) { + switch (AvPixelFormat) { + case AV_PIX_FMT_NONE: + return 0; + case AV_PIX_FMT_YUV420P: + return 1; + case AV_PIX_FMT_YUYV422: + return 2; + case AV_PIX_FMT_RGB24: + return 3; + case AV_PIX_FMT_BGR24: + return 4; + case AV_PIX_FMT_YUV422P: + return 5; + case AV_PIX_FMT_YUV444P: + return 7; + case AV_PIX_FMT_YUV410P: + return 8; + case AV_PIX_FMT_YUV411P: + return 9; + case AV_PIX_FMT_GRAY8: + return 10; + case AV_PIX_FMT_MONOWHITE: + return 11; + case AV_PIX_FMT_MONOBLACK: + return 12; + case AV_PIX_FMT_PAL8: + return 13; + case AV_PIX_FMT_YUVJ420P: + return 14; + case AV_PIX_FMT_YUVJ422P: + return 15; + case AV_PIX_FMT_YUVJ444P: + return 16; + // case AV_PIX_FMT_XVMC_MPEG2_MC : // Lower FFmpeg Version + // return 17; + // case AV_PIX_FMT_XVMC_MPEG2_IDCT : + // return 18; + case AV_PIX_FMT_UYVY422: + return 19; + case AV_PIX_FMT_UYYVYY411: + return 20; + case AV_PIX_FMT_BGR8: + return 21; + case AV_PIX_FMT_BGR4: + return 22; + case AV_PIX_FMT_BGR4_BYTE: + return 23; + case AV_PIX_FMT_RGB8: + return 24; + case AV_PIX_FMT_RGB4: + return 25; + case AV_PIX_FMT_RGB4_BYTE: + return 26; + case AV_PIX_FMT_NV12: + return 27; + case AV_PIX_FMT_NV21: + return 28; + case AV_PIX_FMT_ARGB: // Big Endian + return 29; + case AV_PIX_FMT_RGBA: // Big + return 30; + case AV_PIX_FMT_ABGR: // Big + return 31; + case AV_PIX_FMT_BGRA: // little + return 32; + case AV_PIX_FMT_GRAY16BE: // big + return 33; + case AV_PIX_FMT_GRAY16LE: + return 34; + case AV_PIX_FMT_YUV440P: + return 35; + case AV_PIX_FMT_YUVJ440P: + return 36; + case AV_PIX_FMT_YUVA420P: + return 37; + // case AV_PIX_FMT_VDPAU_H264 : + // return 38; + // case AV_PIX_FMT_VDPAU_MPEG1 : + // return 39; + // case AV_PIX_FMT_VDPAU_MPEG2 : + // return 40; + // case AV_PIX_FMT_VDPAU_WMV3 : // Conditional compile. + // return 41; + // case AV_PIX_FMT_VDPAU_VC1 : // ff_api_vdpau is present + // return 42; + case AV_PIX_FMT_RGB48BE: + return 43; + case AV_PIX_FMT_RGB48LE: + return 44; + case AV_PIX_FMT_RGB565BE: + return 45; + case AV_PIX_FMT_RGB565LE: + return 46; + case AV_PIX_FMT_RGB555BE: + return 47; + case AV_PIX_FMT_RGB555LE: + return 48; + case AV_PIX_FMT_BGR565BE: + return 49; + case AV_PIX_FMT_BGR565LE: + return 50; + case AV_PIX_FMT_BGR555BE: + return 51; + case AV_PIX_FMT_BGR555LE: + return 52; + // case AV_PIX_FMT_VAAPI_MOCO : + // return 53; + // case AV_PIX_FMT_VAAPI_IDCT : + // return 54; + // case AV_PIX_FMT_VAAPI_VLD : + // return 55; + // case AV_PIX_FMT_VAAPI : // ff_api_vdpau is present + // return 56; + case AV_PIX_FMT_YUV420P16LE: + return 57; + case AV_PIX_FMT_YUV420P16BE: + return 58; + case AV_PIX_FMT_YUV422P16LE: + return 59; + case AV_PIX_FMT_YUV422P16BE: + return 60; + case AV_PIX_FMT_YUV444P16LE: + return 61; + case AV_PIX_FMT_YUV444P16BE: + return 62; + // case AV_PIX_FMT_VDPAU_MPEG4 : // ff_api_vdpau is present + // return 63; + case AV_PIX_FMT_DXVA2_VLD: + return 64; + case AV_PIX_FMT_RGB444LE: + return 65; + case AV_PIX_FMT_RGB444BE: + return 66; + case AV_PIX_FMT_BGR444LE: + return 67; + case AV_PIX_FMT_BGR444BE: + return 68; + case AV_PIX_FMT_YA8: + return 69; + case AV_PIX_FMT_BGR48BE: + return 70; + case AV_PIX_FMT_BGR48LE: + return 71; + case AV_PIX_FMT_YUV420P9BE: + return 72; + case AV_PIX_FMT_YUV420P9LE: + return 73; + case AV_PIX_FMT_YUV420P10BE: + return 74; + case AV_PIX_FMT_YUV420P10LE: + return 75; + case AV_PIX_FMT_YUV422P10BE: + return 76; + case AV_PIX_FMT_YUV422P10LE: + return 77; + case AV_PIX_FMT_YUV444P9BE: + return 78; + case AV_PIX_FMT_YUV444P9LE: + return 79; + case AV_PIX_FMT_YUV444P10BE: + return 80; + case AV_PIX_FMT_YUV444P10LE: + return 81; + case AV_PIX_FMT_YUV422P9BE: + return 82; + case AV_PIX_FMT_YUV422P9LE: + return 83; + // case AV_PIX_FMT_VDA_VLD : // Lower than ffmpeg version 4 + // return 84; + case AV_PIX_FMT_GBRP: + return 85; + case AV_PIX_FMT_GBRP9BE: + return 86; + case AV_PIX_FMT_GBRP9LE: + return 87; + case AV_PIX_FMT_GBRP10BE: + return 88; + case AV_PIX_FMT_GBRP10LE: + return 89; + case AV_PIX_FMT_GBRP16BE: + return 90; + case AV_PIX_FMT_GBRP16LE: + return 91; + case AV_PIX_FMT_YUVA420P9BE: + return 92; + case AV_PIX_FMT_YUVA420P9LE: + return 93; + case AV_PIX_FMT_YUVA422P9BE: + return 94; + case AV_PIX_FMT_YUVA422P9LE: + return 95; + case AV_PIX_FMT_YUVA444P9BE: + return 96; + case AV_PIX_FMT_YUVA444P9LE: + return 97; + case AV_PIX_FMT_YUVA420P10BE: + return 98; + case AV_PIX_FMT_YUVA420P10LE: + return 99; + case AV_PIX_FMT_YUVA422P10BE: + return 100; + case AV_PIX_FMT_YUVA422P10LE: + return 101; + case AV_PIX_FMT_YUVA444P10BE: + return 102; + case AV_PIX_FMT_YUVA444P10LE: + return 103; + case AV_PIX_FMT_YUVA420P16BE: + return 104; + case AV_PIX_FMT_YUVA420P16LE: + return 105; + case AV_PIX_FMT_YUVA422P16BE: + return 106; + case AV_PIX_FMT_YUVA422P16LE: + return 107; + case AV_PIX_FMT_YUVA444P16BE: + return 108; + case AV_PIX_FMT_YUVA444P16LE: + return 109; + case AV_PIX_FMT_VDPAU: + return 110; + case AV_PIX_FMT_XYZ12LE: + return 111; + case AV_PIX_FMT_XYZ12BE: + return 112; + case AV_PIX_FMT_NV16: + return 113; + case AV_PIX_FMT_NV20LE: + return 114; + case AV_PIX_FMT_NV20BE: + return 115; + case AV_PIX_FMT_RGBA64BE: + return 116; + case AV_PIX_FMT_RGBA64LE: + return 117; + case AV_PIX_FMT_BGRA64BE: + return 118; + case AV_PIX_FMT_BGRA64LE: + return 119; + case AV_PIX_FMT_YVYU422: + return 120; + // case AV_PIX_FMT_VDA : // Lower than ffmpeg version 4. + // return 121; + case AV_PIX_FMT_YA16BE: // big + return 122; + case AV_PIX_FMT_YA16LE: + return 123; + case AV_PIX_FMT_QSV: + return 124; + case AV_PIX_FMT_MMAL: + return 125; + case AV_PIX_FMT_D3D11VA_VLD: + return 126; + case AV_PIX_FMT_CUDA: + return 127; + case AV_PIX_FMT_0RGB: // big + return 128; + case AV_PIX_FMT_RGB0: + return 129; + case AV_PIX_FMT_0BGR: // big + return 130; + case AV_PIX_FMT_BGR0: + return 131; + case AV_PIX_FMT_YUVA444P: + return 132; + case AV_PIX_FMT_YUVA422P: + return 133; + case AV_PIX_FMT_YUV420P12BE: + return 134; + case AV_PIX_FMT_YUV420P12LE: + return 135; + case AV_PIX_FMT_YUV420P14BE: + return 136; + case AV_PIX_FMT_YUV420P14LE: + return 137; + case AV_PIX_FMT_YUV422P12BE: + return 138; + case AV_PIX_FMT_YUV422P12LE: + return 139; + case AV_PIX_FMT_YUV422P14BE: + return 140; + case AV_PIX_FMT_YUV422P14LE: + return 141; + case AV_PIX_FMT_YUV444P12BE: + return 142; + case AV_PIX_FMT_YUV444P12LE: + return 143; + case AV_PIX_FMT_YUV444P14BE: + return 144; + case AV_PIX_FMT_YUV444P14LE: + return 146; + case AV_PIX_FMT_GBRP12BE: + return 147; + case AV_PIX_FMT_GBRP12LE: + return 148; + case AV_PIX_FMT_GBRP14BE: + return 149; + case AV_PIX_FMT_GBRP14LE: + return 150; + case AV_PIX_FMT_GBRAP: + return 151; + case AV_PIX_FMT_GBRAP16BE: + return 152; + case AV_PIX_FMT_GBRAP16LE: + return 153; + case AV_PIX_FMT_YUVJ411P: + return 154; + case AV_PIX_FMT_BAYER_BGGR8: + return 155; + case AV_PIX_FMT_BAYER_RGGB8: + return 156; + case AV_PIX_FMT_BAYER_GBRG8: + return 157; + case AV_PIX_FMT_BAYER_GRBG8: + return 158; + case AV_PIX_FMT_BAYER_BGGR16LE: + return 159; + case AV_PIX_FMT_BAYER_BGGR16BE: + return 160; + case AV_PIX_FMT_BAYER_RGGB16LE: + return 161; + case AV_PIX_FMT_BAYER_RGGB16BE: + return 162; + case AV_PIX_FMT_BAYER_GBRG16LE: + return 163; + case AV_PIX_FMT_BAYER_GBRG16BE: + return 164; + case AV_PIX_FMT_BAYER_GRBG16LE: + return 165; + case AV_PIX_FMT_BAYER_GRBG16BE: + return 166; + case AV_PIX_FMT_YUV440P10LE: + return 167; + case AV_PIX_FMT_YUV440P10BE: + return 168; + case AV_PIX_FMT_YUV440P12LE: + return 169; + case AV_PIX_FMT_YUV440P12BE: + return 170; + case AV_PIX_FMT_AYUV64LE: + return 171; + case AV_PIX_FMT_AYUV64BE: + return 172; + case AV_PIX_FMT_VIDEOTOOLBOX: + return 173; + case AV_PIX_FMT_XVMC: + return 174; + // case AV_PIX_FMT_RGB32: // IF format is this type, based on + // endianness, it resolves to big endian or small endian. + // return 175; // The Switch case contains both big and + // small endian, so No need to add these in switch case. + // case AV_PIX_FMT_RGB32_1: // Will Automatically resolve. + // return 176; + // case AV_PIX_FMT_BGR32: + // return 177; + // case AV_PIX_FMT_BGR32_1: + // return 178; + // case AV_PIX_FMT_0RGB32: + // return 179; + // case AV_PIX_FMT_0BGR32: + // return 180; + // case AV_PIX_FMT_GRAY16: + // return 181; + // case AV_PIX_FMT_YA16: + // return 182; + // case AV_PIX_FMT_RGB48: + // return 183; + // case AV_PIX_FMT_RGB565: + // return 184; + // case AV_PIX_FMT_RGB444: + // return 185; + // case AV_PIX_FMT_BGR48: + // return 186; + // case AV_PIX_FMT_BGR565: + // return 187; + // case AV_PIX_FMT_BGR555: + // return 188; + // case AV_PIX_FMT_BGR444: + // return 189; + // case AV_PIX_FMT_YUV420P9: + // return 190; + // case AV_PIX_FMT_YUV422P9: + // return 191; + // case AV_PIX_FMT_YUV444P9: + // return 192; + // case AV_PIX_FMT_YUV420P10: + // return 193; + // case AV_PIX_FMT_YUV422P10: + // return 194; + // case AV_PIX_FMT_YUV440P10: + // return 195; + // case AV_PIX_FMT_YUV444P10: + // return 196; + // case AV_PIX_FMT_YUV420P12: + // return 197; + // case AV_PIX_FMT_YUV422P12: + // return 198; + // case AV_PIX_FMT_YUV440P12: + // return 199; + // case AV_PIX_FMT_YUV444P12: + // return 200; + // case AV_PIX_FMT_YUV420P14: + // return 201; + // case AV_PIX_FMT_YUV422P14: + // return 202; + // case AV_PIX_FMT_YUV444P14: + // return 203; + // case AV_PIX_FMT_YUV420P16: + // return 204; + // case AV_PIX_FMT_YUV422P16: + // return 205; + // case AV_PIX_FMT_YUV444P16: + // return 206; + // case AV_PIX_FMT_GBRP9: + // return 207; + // case AV_PIX_FMT_GBRP10: + // return 208; + // case AV_PIX_FMT_GBRP12: + // return 209; + // case AV_PIX_FMT_GBRP14: + // return 210; + // case AV_PIX_FMT_GBRP16: + // return 211; + // case AV_PIX_FMT_GBRAP16: + // return 212; + // case AV_PIX_FMT_BAYER_BGGR16: + // return 213; + // case AV_PIX_FMT_BAYER_RGGB16: + // return 214; + // case AV_PIX_FMT_BAYER_GBRG16: + // return 215; + // case AV_PIX_FMT_BAYER_GRBG16: + // return 216; + // case AV_PIX_FMT_YUVA420P9: + // return 217; + // case AV_PIX_FMT_YUVA422P9: + // return 218; + // case AV_PIX_FMT_YUVA444P9: + // return 219; + // case AV_PIX_FMT_YUVA420P10: + // return 220; + // case AV_PIX_FMT_YUVA422P10: + // return 221; + // case AV_PIX_FMT_YUVA444P10: + // return 222; + // case AV_PIX_FMT_YUVA420P16: + // return 223; + // case AV_PIX_FMT_YUVA422P16: + // return 224; + // case AV_PIX_FMT_YUVA444P16: + // return 225; + // case AV_PIX_FMT_XYZ12: + // return 226; + // case AV_PIX_FMT_NV20: + // return 227; + // case AV_PIX_FMT_AYUV64: + // return 228; + case AV_PIX_FMT_P010LE: + return 229; + case AV_PIX_FMT_P010BE: + return 230; + case AV_PIX_FMT_GBRAP12BE: + return 231; + case AV_PIX_FMT_GBRAP12LE: + return 232; + case AV_PIX_FMT_GBRAP10LE: + return 233; + case AV_PIX_FMT_GBRAP10BE: + return 234; + case AV_PIX_FMT_MEDIACODEC: + return 235; + case AV_PIX_FMT_GRAY12BE: + return 236; + case AV_PIX_FMT_GRAY12LE: + return 237; + case AV_PIX_FMT_GRAY10BE: + return 238; + case AV_PIX_FMT_GRAY10LE: + return 239; + case AV_PIX_FMT_P016LE: + return 240; + case AV_PIX_FMT_P016BE: + return 241; + case AV_PIX_FMT_D3D11: + return 242; + case AV_PIX_FMT_GRAY9BE: + return 243; + case AV_PIX_FMT_GRAY9LE: + return 244; + case AV_PIX_FMT_GBRPF32BE: + return 245; + case AV_PIX_FMT_GBRPF32LE: + return 246; + case AV_PIX_FMT_GBRAPF32BE: + return 247; + case AV_PIX_FMT_GBRAPF32LE: + return 248; + case AV_PIX_FMT_DRM_PRIME: + return 249; + // Above ffmpeg 4.0 Need to add versions. + case AV_PIX_FMT_OPENCL: + return 250; + case AV_PIX_FMT_GRAY14BE: + return 251; + case AV_PIX_FMT_GRAY14LE: + return 252; + case AV_PIX_FMT_GRAYF32BE: + return 253; + case AV_PIX_FMT_GRAYF32LE: + return 254; + case AV_PIX_FMT_YUVA422P12BE: + return 255; + case AV_PIX_FMT_YUVA422P12LE: + return 256; + case AV_PIX_FMT_YUVA444P12BE: + return 257; + case AV_PIX_FMT_YUVA444P12LE: + return 258; + case AV_PIX_FMT_NV24: + return 259; + case AV_PIX_FMT_NV42: + return 260; + case AV_PIX_FMT_VULKAN: + return 261; + case AV_PIX_FMT_Y210BE: + return 262; + case AV_PIX_FMT_Y210LE: + return 263; + case AV_PIX_FMT_X2RGB10LE: + return 264; + case AV_PIX_FMT_X2RGB10BE: + return 265; + case AV_PIX_FMT_X2BGR10LE: + return 266; + case AV_PIX_FMT_X2BGR10BE: + return 267; + case AV_PIX_FMT_P210BE: + return 268; + case AV_PIX_FMT_P210LE: + return 269; + case AV_PIX_FMT_P410BE: + return 270; + case AV_PIX_FMT_P410LE: + return 271; + case AV_PIX_FMT_P216BE: + return 272; + case AV_PIX_FMT_P216LE: + return 273; + case AV_PIX_FMT_P416BE: + return 274; + case AV_PIX_FMT_P416LE: + return 275; + case AV_PIX_FMT_VUYA: + return 276; + case AV_PIX_FMT_RGBAF16BE: + return 277; + case AV_PIX_FMT_RGBAF16LE: + return 278; + case AV_PIX_FMT_VUYX: + return 279; + case AV_PIX_FMT_P012LE: + return 280; + case AV_PIX_FMT_P012BE: + return 281; + case AV_PIX_FMT_Y212BE: + return 282; + case AV_PIX_FMT_Y212LE: + return 283; + case AV_PIX_FMT_XV30BE: + return 284; + case AV_PIX_FMT_XV30LE: + return 285; + case AV_PIX_FMT_XV36BE: + return 286; + case AV_PIX_FMT_XV36LE: + return 287; + case AV_PIX_FMT_RGBF32BE: + return 288; + case AV_PIX_FMT_RGBF32LE: + return 289; + case AV_PIX_FMT_RGBAF32BE: + return 290; + case AV_PIX_FMT_RGBAF32LE: + return 291; + // case AV_PIX_FMT_RPI : + // return 292; + // case AV_PIX_FMT_SAND128 : + // return 293; + // case AV_PIX_FMT_SAND64_10 : + // return 294; + // case AV_PIX_FMT_SAND64_16 : + // return 295; + // case AV_PIX_FMT_RPI4_8 : // rpi turn on then only + // return 296; + // case AV_PIX_FMT_RPI4_10 : + // return 297; + // case AV_PIX_FMT_RGB555: // Little Endian, Big Endian WIll + // Resolve on it's own. + // return 298; + default: + return 0; + } + } + + static AVPixelFormat intoAVPixFmt(uint32_t AvPixFmtId) { + switch (AvPixFmtId) { + case 0: + return AV_PIX_FMT_NONE; + case 1: + return AV_PIX_FMT_YUV420P; + case 2: + return AV_PIX_FMT_YUYV422; + case 3: + return AV_PIX_FMT_RGB24; + case 4: + return AV_PIX_FMT_BGR24; + case 5: + return AV_PIX_FMT_YUV422P; + case 7: + return AV_PIX_FMT_YUV444P; + case 8: + return AV_PIX_FMT_YUV410P; + case 9: + return AV_PIX_FMT_YUV411P; + case 10: + return AV_PIX_FMT_GRAY8; + case 11: + return AV_PIX_FMT_MONOWHITE; + case 12: + return AV_PIX_FMT_MONOBLACK; + case 13: + return AV_PIX_FMT_PAL8; + case 14: + return AV_PIX_FMT_YUVJ420P; + case 15: + return AV_PIX_FMT_YUVJ422P; + case 16: + return AV_PIX_FMT_YUVJ444P; + // case 17: + // return AV_PIX_FMT_XVMC_MPEG2_MC ; // Lower FFmpeg Version + // case 18: + // return AV_PIX_FMT_XVMC_MPEG2_IDCT ; + case 19: + return AV_PIX_FMT_UYVY422; + case 20: + return AV_PIX_FMT_UYYVYY411; + case 21: + return AV_PIX_FMT_BGR8; + case 22: + return AV_PIX_FMT_BGR4; + case 23: + return AV_PIX_FMT_BGR4_BYTE; + case 24: + return AV_PIX_FMT_RGB8; + case 25: + return AV_PIX_FMT_RGB4; + case 26: + return AV_PIX_FMT_RGB4_BYTE; + case 27: + return AV_PIX_FMT_NV12; + case 28: + return AV_PIX_FMT_NV21; + case 29: + return AV_PIX_FMT_ARGB; + case 30: + return AV_PIX_FMT_RGBA; + case 31: + return AV_PIX_FMT_ABGR; + case 32: + return AV_PIX_FMT_BGRA; // Little + case 33: + return AV_PIX_FMT_GRAY16BE; + case 34: + return AV_PIX_FMT_GRAY16LE; + case 35: + return AV_PIX_FMT_YUV440P; + case 36: + return AV_PIX_FMT_YUVJ440P; + case 37: + return AV_PIX_FMT_YUVA420P; + // case 38: + // return AV_PIX_FMT_VDPAU_H264 ; + // case 39: + // return AV_PIX_FMT_VDPAU_MPEG1 ; + // case 40: + // return AV_PIX_FMT_VDPAU_MPEG2 ; + // case 41: + // return AV_PIX_FMT_VDPAU_WMV3 ; // Conditional compile. + // case 42: + // return AV_PIX_FMT_VDPAU_VC1 ; // ff_api_vdpau is present + case 43: + return AV_PIX_FMT_RGB48BE; + case 44: + return AV_PIX_FMT_RGB48LE; + case 45: + return AV_PIX_FMT_RGB565BE; + case 46: + return AV_PIX_FMT_RGB565LE; + case 47: + return AV_PIX_FMT_RGB555BE; + case 48: + return AV_PIX_FMT_RGB555LE; + case 49: + return AV_PIX_FMT_BGR565BE; + case 50: + return AV_PIX_FMT_BGR565LE; + case 51: + return AV_PIX_FMT_BGR555BE; + case 52: + return AV_PIX_FMT_BGR555LE; + // case 53: + // return AV_PIX_FMT_VAAPI_MOCO ; + // case 54: + // return AV_PIX_FMT_VAAPI_IDCT ; + // case 55: + // return AV_PIX_FMT_VAAPI_VLD ; + // case 56: + // return AV_PIX_FMT_VAAPI ; // ff_api_vdpau is present + case 57: + return AV_PIX_FMT_YUV420P16LE; + case 58: + return AV_PIX_FMT_YUV420P16BE; + case 59: + return AV_PIX_FMT_YUV422P16LE; + case 60: + return AV_PIX_FMT_YUV422P16BE; + case 61: + return AV_PIX_FMT_YUV444P16LE; + case 62: + return AV_PIX_FMT_YUV444P16BE; + // case 63: + // return AV_PIX_FMT_VDPAU_MPEG4 ; // ff_api_vdpau is present + case 64: + return AV_PIX_FMT_DXVA2_VLD; + case 65: + return AV_PIX_FMT_RGB444LE; + case 66: + return AV_PIX_FMT_RGB444BE; + case 67: + return AV_PIX_FMT_BGR444LE; + case 68: + return AV_PIX_FMT_BGR444BE; + case 69: + return AV_PIX_FMT_YA8; + case 70: + return AV_PIX_FMT_BGR48BE; + case 71: + return AV_PIX_FMT_BGR48LE; + case 72: + return AV_PIX_FMT_YUV420P9BE; + case 73: + return AV_PIX_FMT_YUV420P9LE; + case 74: + return AV_PIX_FMT_YUV420P10BE; + case 75: + return AV_PIX_FMT_YUV420P10LE; + case 76: + return AV_PIX_FMT_YUV422P10BE; + case 77: + return AV_PIX_FMT_YUV422P10LE; + case 78: + return AV_PIX_FMT_YUV444P9BE; + case 79: + return AV_PIX_FMT_YUV444P9LE; + case 80: + return AV_PIX_FMT_YUV444P10BE; + case 81: + return AV_PIX_FMT_YUV444P10LE; + case 82: + return AV_PIX_FMT_YUV422P9BE; + case 83: + return AV_PIX_FMT_YUV422P9LE; + // case 84: + // return AV_PIX_FMT_VDA_VLD ; // Lower than ffmpeg version 4 + case 85: + return AV_PIX_FMT_GBRP; + case 86: + return AV_PIX_FMT_GBRP9BE; + case 87: + return AV_PIX_FMT_GBRP9LE; + case 88: + return AV_PIX_FMT_GBRP10BE; + case 89: + return AV_PIX_FMT_GBRP10LE; + case 90: + return AV_PIX_FMT_GBRP16BE; + case 91: + return AV_PIX_FMT_GBRP16LE; + case 92: + return AV_PIX_FMT_YUVA420P9BE; + case 93: + return AV_PIX_FMT_YUVA420P9LE; + case 94: + return AV_PIX_FMT_YUVA422P9BE; + case 95: + return AV_PIX_FMT_YUVA422P9LE; + case 96: + return AV_PIX_FMT_YUVA444P9BE; + case 97: + return AV_PIX_FMT_YUVA444P9LE; + case 98: + return AV_PIX_FMT_YUVA420P10BE; + case 99: + return AV_PIX_FMT_YUVA420P10LE; + case 100: + return AV_PIX_FMT_YUVA422P10BE; + case 101: + return AV_PIX_FMT_YUVA422P10LE; + case 102: + return AV_PIX_FMT_YUVA444P10BE; + case 103: + return AV_PIX_FMT_YUVA444P10LE; + case 104: + return AV_PIX_FMT_YUVA420P16BE; + case 105: + return AV_PIX_FMT_YUVA420P16LE; + case 106: + return AV_PIX_FMT_YUVA422P16BE; + case 107: + return AV_PIX_FMT_YUVA422P16LE; + case 108: + return AV_PIX_FMT_YUVA444P16BE; + case 109: + return AV_PIX_FMT_YUVA444P16LE; + case 110: + return AV_PIX_FMT_VDPAU; + case 111: + return AV_PIX_FMT_XYZ12LE; + case 112: + return AV_PIX_FMT_XYZ12BE; + case 113: + return AV_PIX_FMT_NV16; + case 114: + return AV_PIX_FMT_NV20LE; + case 115: + return AV_PIX_FMT_NV20BE; + case 116: + return AV_PIX_FMT_RGBA64BE; + case 117: + return AV_PIX_FMT_RGBA64LE; + case 118: + return AV_PIX_FMT_BGRA64BE; + case 119: + return AV_PIX_FMT_BGRA64LE; + case 120: + return AV_PIX_FMT_YVYU422; + // case 121: + // return AV_PIX_FMT_VDA ; // Lower than ffmpeg version 4. + case 122: + return AV_PIX_FMT_YA16BE; + case 123: + return AV_PIX_FMT_YA16LE; + case 124: + return AV_PIX_FMT_QSV; + case 125: + return AV_PIX_FMT_MMAL; + case 126: + return AV_PIX_FMT_D3D11VA_VLD; + case 127: + return AV_PIX_FMT_CUDA; + case 128: + return AV_PIX_FMT_0RGB; + case 129: + return AV_PIX_FMT_RGB0; + case 130: + return AV_PIX_FMT_0BGR; + case 131: + return AV_PIX_FMT_BGR0; + case 132: + return AV_PIX_FMT_YUVA444P; + case 133: + return AV_PIX_FMT_YUVA422P; + case 134: + return AV_PIX_FMT_YUV420P12BE; + case 135: + return AV_PIX_FMT_YUV420P12LE; + case 136: + return AV_PIX_FMT_YUV420P14BE; + case 137: + return AV_PIX_FMT_YUV420P14LE; + case 138: + return AV_PIX_FMT_YUV422P12BE; + case 139: + return AV_PIX_FMT_YUV422P12LE; + case 140: + return AV_PIX_FMT_YUV422P14BE; + case 141: + return AV_PIX_FMT_YUV422P14LE; + case 142: + return AV_PIX_FMT_YUV444P12BE; + case 143: + return AV_PIX_FMT_YUV444P12LE; + case 144: + return AV_PIX_FMT_YUV444P14BE; + case 146: + return AV_PIX_FMT_YUV444P14LE; + case 147: + return AV_PIX_FMT_GBRP12BE; + case 148: + return AV_PIX_FMT_GBRP12LE; + case 149: + return AV_PIX_FMT_GBRP14BE; + case 150: + return AV_PIX_FMT_GBRP14LE; + case 151: + return AV_PIX_FMT_GBRAP; + case 152: + return AV_PIX_FMT_GBRAP16BE; + case 153: + return AV_PIX_FMT_GBRAP16LE; + case 154: + return AV_PIX_FMT_YUVJ411P; + case 155: + return AV_PIX_FMT_BAYER_BGGR8; + case 156: + return AV_PIX_FMT_BAYER_RGGB8; + case 157: + return AV_PIX_FMT_BAYER_GBRG8; + case 158: + return AV_PIX_FMT_BAYER_GRBG8; + case 159: + return AV_PIX_FMT_BAYER_BGGR16LE; + case 160: + return AV_PIX_FMT_BAYER_BGGR16BE; + case 161: + return AV_PIX_FMT_BAYER_RGGB16LE; + case 162: + return AV_PIX_FMT_BAYER_RGGB16BE; + case 163: + return AV_PIX_FMT_BAYER_GBRG16LE; + case 164: + return AV_PIX_FMT_BAYER_GBRG16BE; + case 165: + return AV_PIX_FMT_BAYER_GRBG16LE; + case 166: + return AV_PIX_FMT_BAYER_GRBG16BE; + case 167: + return AV_PIX_FMT_YUV440P10LE; + case 168: + return AV_PIX_FMT_YUV440P10BE; + case 169: + return AV_PIX_FMT_YUV440P12LE; + case 170: + return AV_PIX_FMT_YUV440P12BE; + case 171: + return AV_PIX_FMT_AYUV64LE; + case 172: + return AV_PIX_FMT_AYUV64BE; + case 173: + return AV_PIX_FMT_VIDEOTOOLBOX; + case 174: + return AV_PIX_FMT_XVMC; + case 175: + return AV_PIX_FMT_RGB32; + case 176: + return AV_PIX_FMT_RGB32_1; + case 177: + return AV_PIX_FMT_BGR32; + case 178: + return AV_PIX_FMT_BGR32_1; + case 179: + return AV_PIX_FMT_0RGB32; + case 180: + return AV_PIX_FMT_0BGR32; + case 181: + return AV_PIX_FMT_GRAY16; + case 182: + return AV_PIX_FMT_YA16; + case 183: + return AV_PIX_FMT_RGB48; + case 184: + return AV_PIX_FMT_RGB565; + case 185: + return AV_PIX_FMT_RGB444; + case 186: + return AV_PIX_FMT_BGR48; + case 187: + return AV_PIX_FMT_BGR565; + case 188: + return AV_PIX_FMT_BGR555; + case 189: + return AV_PIX_FMT_BGR444; + case 190: + return AV_PIX_FMT_YUV420P9; + case 191: + return AV_PIX_FMT_YUV422P9; + case 192: + return AV_PIX_FMT_YUV444P9; + case 193: + return AV_PIX_FMT_YUV420P10; + case 194: + return AV_PIX_FMT_YUV422P10; + case 195: + return AV_PIX_FMT_YUV440P10; + case 196: + return AV_PIX_FMT_YUV444P10; + case 197: + return AV_PIX_FMT_YUV420P12; + case 198: + return AV_PIX_FMT_YUV422P12; + case 199: + return AV_PIX_FMT_YUV440P12; + case 200: + return AV_PIX_FMT_YUV444P12; + case 201: + return AV_PIX_FMT_YUV420P14; + case 202: + return AV_PIX_FMT_YUV422P14; + case 203: + return AV_PIX_FMT_YUV444P14; + case 204: + return AV_PIX_FMT_YUV420P16; + case 205: + return AV_PIX_FMT_YUV422P16; + case 206: + return AV_PIX_FMT_YUV444P16; + case 207: + return AV_PIX_FMT_GBRP9; + case 208: + return AV_PIX_FMT_GBRP10; + case 209: + return AV_PIX_FMT_GBRP12; + case 210: + return AV_PIX_FMT_GBRP14; + case 211: + return AV_PIX_FMT_GBRP16; + case 212: + return AV_PIX_FMT_GBRAP16; + case 213: + return AV_PIX_FMT_BAYER_BGGR16; + case 214: + return AV_PIX_FMT_BAYER_RGGB16; + case 215: + return AV_PIX_FMT_BAYER_GBRG16; + case 216: + return AV_PIX_FMT_BAYER_GRBG16; + case 217: + return AV_PIX_FMT_YUVA420P9; + case 218: + return AV_PIX_FMT_YUVA422P9; + case 219: + return AV_PIX_FMT_YUVA444P9; + case 220: + return AV_PIX_FMT_YUVA420P10; + case 221: + return AV_PIX_FMT_YUVA422P10; + case 222: + return AV_PIX_FMT_YUVA444P10; + case 223: + return AV_PIX_FMT_YUVA420P16; + case 224: + return AV_PIX_FMT_YUVA422P16; + case 225: + return AV_PIX_FMT_YUVA444P16; + case 226: + return AV_PIX_FMT_XYZ12; + case 227: + return AV_PIX_FMT_NV20; + case 228: + return AV_PIX_FMT_AYUV64; + case 229: + return AV_PIX_FMT_P010LE; + case 230: + return AV_PIX_FMT_P010BE; + case 231: + return AV_PIX_FMT_GBRAP12BE; + case 232: + return AV_PIX_FMT_GBRAP12LE; + case 233: + return AV_PIX_FMT_GBRAP10LE; + case 234: + return AV_PIX_FMT_GBRAP10BE; + case 235: + return AV_PIX_FMT_MEDIACODEC; + case 236: + return AV_PIX_FMT_GRAY12BE; + case 237: + return AV_PIX_FMT_GRAY12LE; + case 238: + return AV_PIX_FMT_GRAY10BE; + case 239: + return AV_PIX_FMT_GRAY10LE; + case 240: + return AV_PIX_FMT_P016LE; + case 241: + return AV_PIX_FMT_P016BE; + case 242: + return AV_PIX_FMT_D3D11; + case 243: + return AV_PIX_FMT_GRAY9BE; + case 244: + return AV_PIX_FMT_GRAY9LE; + case 245: + return AV_PIX_FMT_GBRPF32BE; + case 246: + return AV_PIX_FMT_GBRPF32LE; + case 247: + return AV_PIX_FMT_GBRAPF32BE; + case 248: + return AV_PIX_FMT_GBRAPF32LE; + case 249: + return AV_PIX_FMT_DRM_PRIME; + + // Above ffmpeg 4.0 Need to add versions. + case 250: + return AV_PIX_FMT_OPENCL; + case 251: + return AV_PIX_FMT_GRAY14BE; + case 252: + return AV_PIX_FMT_GRAY14LE; + case 253: + return AV_PIX_FMT_GRAYF32BE; + case 254: + return AV_PIX_FMT_GRAYF32LE; + case 255: + return AV_PIX_FMT_YUVA422P12BE; + case 256: + return AV_PIX_FMT_YUVA422P12LE; + case 257: + return AV_PIX_FMT_YUVA444P12BE; + case 258: + return AV_PIX_FMT_YUVA444P12LE; + case 259: + return AV_PIX_FMT_NV24; + case 260: + return AV_PIX_FMT_NV42; + case 261: + return AV_PIX_FMT_VULKAN; + case 262: + return AV_PIX_FMT_Y210BE; + case 263: + return AV_PIX_FMT_Y210LE; + case 264: + return AV_PIX_FMT_X2RGB10LE; + case 265: + return AV_PIX_FMT_X2RGB10BE; + case 266: + return AV_PIX_FMT_X2BGR10LE; + case 267: + return AV_PIX_FMT_X2BGR10BE; + case 268: + return AV_PIX_FMT_P210BE; + case 269: + return AV_PIX_FMT_P210LE; + case 270: + return AV_PIX_FMT_P410BE; + case 271: + return AV_PIX_FMT_P410LE; + case 272: + return AV_PIX_FMT_P216BE; + case 273: + return AV_PIX_FMT_P216LE; + case 274: + return AV_PIX_FMT_P416BE; + case 275: + return AV_PIX_FMT_P416LE; + case 276: + return AV_PIX_FMT_VUYA; + case 277: + return AV_PIX_FMT_RGBAF16BE; + case 278: + return AV_PIX_FMT_RGBAF16LE; + case 279: + return AV_PIX_FMT_VUYX; + case 280: + return AV_PIX_FMT_P012LE; + case 281: + return AV_PIX_FMT_P012BE; + case 282: + return AV_PIX_FMT_Y212BE; + case 283: + return AV_PIX_FMT_Y212LE; + case 284: + return AV_PIX_FMT_XV30BE; + case 285: + return AV_PIX_FMT_XV30LE; + case 286: + return AV_PIX_FMT_XV36BE; + case 287: + return AV_PIX_FMT_XV36LE; + case 288: + return AV_PIX_FMT_RGBF32BE; + case 289: + return AV_PIX_FMT_RGBF32LE; + case 290: + return AV_PIX_FMT_RGBAF32BE; + case 291: + return AV_PIX_FMT_RGBAF32LE; + // case 292: + // return AV_PIX_FMT_RPI ; + // case 293: + // return AV_PIX_FMT_SAND128 ; + // case 294: + // return AV_PIX_FMT_SAND64_10 ; + // case 295: + // return AV_PIX_FMT_SAND64_16 ; + // case 296: + // return AV_PIX_FMT_RPI4_8 ; // rpi turn on then only + // case 297: + // return AV_PIX_FMT_RPI4_10 ; + case 298: + return AV_PIX_FMT_RGB555; + default: + return AV_PIX_FMT_NONE; + } + } +}; + +class SampleFmt { +public: + static AVSampleFormat fromSampleID(uint32_t SampleID) { + switch (SampleID) { + case 0: + return AV_SAMPLE_FMT_NONE; + case 1: + return AV_SAMPLE_FMT_U8; + case 2: + return AV_SAMPLE_FMT_S16; + case 3: + return AV_SAMPLE_FMT_S32; + case 4: + return AV_SAMPLE_FMT_FLT; + case 5: + return AV_SAMPLE_FMT_DBL; + case 6: + return AV_SAMPLE_FMT_U8P; + case 7: + return AV_SAMPLE_FMT_S16P; + case 8: + return AV_SAMPLE_FMT_S32P; + case 9: + return AV_SAMPLE_FMT_FLTP; + case 10: + return AV_SAMPLE_FMT_DBLP; + case 11: + return AV_SAMPLE_FMT_S64; + case 12: + return AV_SAMPLE_FMT_S64P; + case 13: + return AV_SAMPLE_FMT_NB; + default: + return AV_SAMPLE_FMT_NONE; + } + } + + static uint32_t toSampleID(AVSampleFormat AvSampleFormat) { + switch (AvSampleFormat) { + case AV_SAMPLE_FMT_NONE: + return 0; + case AV_SAMPLE_FMT_U8: + return 1; + case AV_SAMPLE_FMT_S16: + return 2; + case AV_SAMPLE_FMT_S32: + return 3; + case AV_SAMPLE_FMT_FLT: + return 4; + case AV_SAMPLE_FMT_DBL: + return 5; + case AV_SAMPLE_FMT_U8P: + return 6; + case AV_SAMPLE_FMT_S16P: + return 7; + case AV_SAMPLE_FMT_S32P: + return 8; + case AV_SAMPLE_FMT_FLTP: + return 9; + case AV_SAMPLE_FMT_DBLP: + return 10; + case AV_SAMPLE_FMT_S64: + return 11; + case AV_SAMPLE_FMT_S64P: + return 12; + case AV_SAMPLE_FMT_NB: + return 13; + default: + return 0; + } + } +}; + +// Could have avoided, but Did this to support older version of FFMPEG +// (V5,V4,V3) Version 6 FFmpeg uses AVChannelLayout Struct; +class ChannelLayout { +private: + const static uint64_t FRONT_LEFT = 1; + const static uint64_t FRONT_RIGHT = 1ULL << 1; + const static uint64_t FRONT_CENTER = 1ULL << 2; + const static uint64_t LOW_FREQUENCY = 1ULL << 3; + const static uint64_t BACK_LEFT = 1ULL << 4; + const static uint64_t BACK_RIGHT = 1ULL << 5; + const static uint64_t FRONT_LEFT_OF_CENTER = 1ULL << 6; + const static uint64_t FRONT_RIGHT_OF_CENTER = 1ULL << 7; + const static uint64_t BACK_CENTER = 1ULL << 8; + const static uint64_t SIDE_LEFT = 1ULL << 9; + const static uint64_t SIDE_RIGHT = 1ULL << 10; + const static uint64_t TOP_CENTER = 1ULL << 11; + const static uint64_t TOP_FRONT_LEFT = 1ULL << 12; + const static uint64_t TOP_FRONT_CENTER = 1ULL << 13; + const static uint64_t TOP_FRONT_RIGHT = 1ULL << 14; + const static uint64_t TOP_BACK_LEFT = 1ULL << 15; + const static uint64_t TOP_BACK_CENTER = 1ULL << 16; + const static uint64_t TOP_BACK_RIGHT = 1ULL << 17; + const static uint64_t STEREO_LEFT = 1ULL << 18; + const static uint64_t STEREO_RIGHT = 1ULL << 19; + const static uint64_t WIDE_LEFT = 1ULL << 20; + const static uint64_t WIDE_RIGHT = 1ULL << 21; + const static uint64_t SURROUND_DIRECT_LEFT = 1ULL << 22; + const static uint64_t SURROUND_DIRECT_RIGHT = 1ULL << 23; + const static uint64_t LOW_FREQUENCY_2 = 1ULL << 24; + const static uint64_t NATIVE = 1ULL << 25; + + const static uint64_t MONO = 1ULL << 26; + const static uint64_t STEREO = 1ULL << 27; + const static uint64_t _2POINT1 = 1ULL << 28; + const static uint64_t _2_1 = 1ULL << 29; + const static uint64_t SURROUND = 1ULL << 30; + const static uint64_t _3POINT1 = 1ULL << 31; + const static uint64_t _4POINT0 = 1ULL << 32; + const static uint64_t _4POINT1 = 1ULL << 33; + const static uint64_t _2_2 = 1ULL << 34; + const static uint64_t QUAD = 1ULL << 35; + const static uint64_t _5POINT0 = 1ULL << 36; + const static uint64_t _5POINT1 = 1ULL << 37; + const static uint64_t _5POINT0_BACK = 1ULL << 38; + const static uint64_t _5POINT1_BACK = 1ULL << 39; + const static uint64_t _6POINT0 = 1ULL << 40; + const static uint64_t _6POINT0_FRONT = 1ULL << 41; + const static uint64_t HEXAGONAL = 1ULL << 42; + const static uint64_t _6POINT1 = 1ULL << 43; + const static uint64_t _6POINT1_BACK = 1ULL << 44; + const static uint64_t _6POINT1_FRONT = 1ULL << 45; + const static uint64_t _7POINT0 = 1ULL << 46; + const static uint64_t _7POINT0_FRONT = 1ULL << 47; + const static uint64_t _7POINT1 = 1ULL << 48; + const static uint64_t _7POINT1_WIDE = 1ULL << 49; + const static uint64_t _7POINT1_WIDE_BACK = 1ULL << 50; + const static uint64_t OCTAGONAL = 1ULL << 51; + const static uint64_t HEXADECAGONAL = 1ULL << 52; + const static uint64_t STEREO_DOWNMIX = 1ULL << 53; + +public: + // Check This function. (Looks good, test it) + static uint64_t fromChannelLayoutID(uint64_t ChannelLayout) { + uint64_t Channel = 0UL; + if (ChannelLayout & FRONT_LEFT) { + Channel |= AV_CH_FRONT_LEFT; + } + if (ChannelLayout & FRONT_RIGHT) { + Channel |= AV_CH_FRONT_RIGHT; + } + if (ChannelLayout & FRONT_CENTER) { + Channel |= AV_CH_FRONT_CENTER; + } + if (ChannelLayout & LOW_FREQUENCY) { + Channel |= AV_CH_LOW_FREQUENCY; + } + if (ChannelLayout & BACK_LEFT) { + Channel |= AV_CH_BACK_LEFT; + } + if (ChannelLayout & BACK_RIGHT) { + Channel |= AV_CH_BACK_RIGHT; + } + if (ChannelLayout & FRONT_LEFT_OF_CENTER) { + Channel |= AV_CH_FRONT_LEFT_OF_CENTER; + } + if (ChannelLayout & FRONT_RIGHT_OF_CENTER) { + Channel |= AV_CH_FRONT_RIGHT_OF_CENTER; + } + if (ChannelLayout & BACK_CENTER) { + Channel |= AV_CH_BACK_CENTER; + } + if (ChannelLayout & SIDE_LEFT) { + Channel |= AV_CH_SIDE_LEFT; + } + if (ChannelLayout & SIDE_RIGHT) { + Channel |= AV_CH_SIDE_RIGHT; + } + if (ChannelLayout & TOP_CENTER) { + Channel |= AV_CH_TOP_CENTER; + } + if (ChannelLayout & TOP_FRONT_LEFT) { + Channel |= AV_CH_TOP_FRONT_LEFT; + } + if (ChannelLayout & TOP_FRONT_CENTER) { + Channel |= AV_CH_TOP_FRONT_CENTER; + } + if (ChannelLayout & TOP_FRONT_RIGHT) { + Channel |= AV_CH_TOP_FRONT_RIGHT; + } + if (ChannelLayout & TOP_BACK_LEFT) { + Channel |= AV_CH_TOP_BACK_LEFT; + } + if (ChannelLayout & TOP_BACK_CENTER) { + Channel |= AV_CH_TOP_BACK_CENTER; + } + if (ChannelLayout & TOP_BACK_RIGHT) { + Channel |= AV_CH_TOP_BACK_RIGHT; + } + if (ChannelLayout & STEREO_LEFT) { + Channel |= AV_CH_STEREO_LEFT; + } + if (ChannelLayout & STEREO_RIGHT) { + Channel |= AV_CH_STEREO_RIGHT; + } + if (ChannelLayout & WIDE_LEFT) { + Channel |= AV_CH_WIDE_LEFT; + } + if (ChannelLayout & WIDE_RIGHT) { + Channel |= AV_CH_WIDE_RIGHT; + } + if (ChannelLayout & SURROUND_DIRECT_LEFT) { + Channel |= AV_CH_SURROUND_DIRECT_LEFT; + } + if (ChannelLayout & SURROUND_DIRECT_RIGHT) { + Channel |= AV_CH_SURROUND_DIRECT_RIGHT; + } + if (ChannelLayout & LOW_FREQUENCY_2) { + Channel |= AV_CH_LOW_FREQUENCY_2; + } + if (ChannelLayout & NATIVE) { + Channel |= AV_CH_LAYOUT_NATIVE; + } + if (ChannelLayout & MONO) { + Channel |= AV_CH_LAYOUT_MONO; + } + if (ChannelLayout & STEREO) { + Channel |= AV_CH_LAYOUT_STEREO; + } + if (ChannelLayout & _2POINT1) { + Channel |= AV_CH_LAYOUT_2POINT1; + } + if (ChannelLayout & _2_1) { + Channel |= AV_CH_LAYOUT_2_1; + } + if (ChannelLayout & SURROUND) { + Channel |= AV_CH_LAYOUT_SURROUND; + } + if (ChannelLayout & _3POINT1) { + Channel |= AV_CH_LAYOUT_3POINT1; + } + if (ChannelLayout & _4POINT0) { + Channel |= AV_CH_LAYOUT_4POINT0; + } + if (ChannelLayout & _4POINT1) { + Channel |= AV_CH_LAYOUT_4POINT1; + } + if (ChannelLayout & _2_2) { + Channel |= AV_CH_LAYOUT_2_2; + } + if (ChannelLayout & QUAD) { + Channel |= AV_CH_LAYOUT_QUAD; + } + if (ChannelLayout & _5POINT0) { + Channel |= AV_CH_LAYOUT_5POINT0; + } + if (ChannelLayout & _5POINT1) { + Channel |= AV_CH_LAYOUT_5POINT1; + } + if (ChannelLayout & _5POINT0_BACK) { + Channel |= AV_CH_LAYOUT_5POINT0_BACK; + } + if (ChannelLayout & _5POINT1_BACK) { + Channel |= AV_CH_LAYOUT_5POINT1_BACK; + } + if (ChannelLayout & _6POINT0) { + Channel |= AV_CH_LAYOUT_6POINT0; + } + if (ChannelLayout & _6POINT0_FRONT) { + Channel |= AV_CH_LAYOUT_6POINT0_FRONT; + } + if (ChannelLayout & HEXAGONAL) { + Channel |= AV_CH_LAYOUT_HEXAGONAL; + } + if (ChannelLayout & _6POINT1) { + Channel |= AV_CH_LAYOUT_6POINT1; + } + if (ChannelLayout & _6POINT1_BACK) { + Channel |= AV_CH_LAYOUT_6POINT1_BACK; + } + if (ChannelLayout & _6POINT1_FRONT) { + Channel |= AV_CH_LAYOUT_6POINT1_FRONT; + } + if (ChannelLayout & _7POINT0) { + Channel |= AV_CH_LAYOUT_7POINT0; + } + if (ChannelLayout & _7POINT0_FRONT) { + Channel |= AV_CH_LAYOUT_7POINT0_FRONT; + } + if (ChannelLayout & _7POINT1) { + Channel |= AV_CH_LAYOUT_7POINT1; + } + if (ChannelLayout & _7POINT1_WIDE) { + Channel |= AV_CH_LAYOUT_7POINT1_WIDE; + } + if (ChannelLayout & _7POINT1_WIDE_BACK) { + Channel |= AV_CH_LAYOUT_7POINT1_WIDE_BACK; + } + if (ChannelLayout & OCTAGONAL) { + Channel |= AV_CH_LAYOUT_OCTAGONAL; + } + if (ChannelLayout & HEXADECAGONAL) { + Channel |= AV_CH_LAYOUT_HEXADECAGONAL; + } + if (ChannelLayout & STEREO_DOWNMIX) { + Channel |= AV_CH_LAYOUT_STEREO_DOWNMIX; + } + return Channel; + } + + // Perfect Logic :) + static uint64_t intoChannelLayoutID(uint64_t ChannelLayout) { + uint64_t Channel = 0; + if ((ChannelLayout & AV_CH_FRONT_LEFT) == AV_CH_FRONT_LEFT) { + Channel |= FRONT_LEFT; + } + if ((ChannelLayout & AV_CH_FRONT_RIGHT) == AV_CH_FRONT_RIGHT) { + Channel |= FRONT_RIGHT; + } + if ((ChannelLayout & AV_CH_FRONT_CENTER) == AV_CH_FRONT_CENTER) { + Channel |= FRONT_CENTER; + } + if ((ChannelLayout & AV_CH_LOW_FREQUENCY) == AV_CH_LOW_FREQUENCY) { + Channel |= LOW_FREQUENCY; + } + if ((ChannelLayout & AV_CH_BACK_LEFT) == AV_CH_BACK_LEFT) { + Channel |= BACK_LEFT; + } + if ((ChannelLayout & AV_CH_BACK_RIGHT) == AV_CH_BACK_RIGHT) { + Channel |= BACK_RIGHT; + } + if ((ChannelLayout & AV_CH_FRONT_LEFT_OF_CENTER) == + AV_CH_FRONT_LEFT_OF_CENTER) { + Channel |= FRONT_LEFT_OF_CENTER; + } + if ((ChannelLayout & AV_CH_FRONT_RIGHT_OF_CENTER) == + AV_CH_FRONT_RIGHT_OF_CENTER) { + Channel |= FRONT_RIGHT_OF_CENTER; + } + if ((ChannelLayout & AV_CH_BACK_CENTER) == AV_CH_BACK_CENTER) { + Channel |= BACK_CENTER; + } + if ((ChannelLayout & AV_CH_SIDE_LEFT) == AV_CH_SIDE_LEFT) { + Channel |= SIDE_LEFT; + } + if ((ChannelLayout & AV_CH_SIDE_RIGHT) == AV_CH_SIDE_RIGHT) { + Channel |= SIDE_RIGHT; + } + if ((ChannelLayout & AV_CH_TOP_CENTER) == AV_CH_TOP_CENTER) { + Channel |= TOP_CENTER; + } + if ((ChannelLayout & AV_CH_TOP_FRONT_LEFT) == AV_CH_TOP_FRONT_LEFT) { + Channel |= TOP_FRONT_LEFT; + } + if ((ChannelLayout & AV_CH_TOP_FRONT_CENTER) == AV_CH_TOP_FRONT_CENTER) { + Channel |= TOP_FRONT_CENTER; + } + if ((ChannelLayout & AV_CH_TOP_FRONT_RIGHT) == AV_CH_TOP_FRONT_RIGHT) { + Channel |= TOP_FRONT_RIGHT; + } + if ((ChannelLayout & AV_CH_TOP_BACK_LEFT) == AV_CH_TOP_BACK_LEFT) { + Channel |= TOP_BACK_LEFT; + } + if ((ChannelLayout & AV_CH_TOP_BACK_CENTER) == AV_CH_TOP_BACK_CENTER) { + Channel |= TOP_BACK_CENTER; + } + if ((ChannelLayout & AV_CH_TOP_BACK_RIGHT) == AV_CH_TOP_BACK_RIGHT) { + Channel |= TOP_BACK_RIGHT; + } + if ((ChannelLayout & AV_CH_STEREO_LEFT) == AV_CH_STEREO_LEFT) { + Channel |= STEREO_LEFT; + } + if ((ChannelLayout & AV_CH_STEREO_RIGHT) == AV_CH_STEREO_RIGHT) { + Channel |= STEREO_RIGHT; + } + if ((ChannelLayout & AV_CH_WIDE_LEFT) == AV_CH_WIDE_LEFT) { + Channel |= WIDE_LEFT; + } + if ((ChannelLayout & AV_CH_WIDE_RIGHT) == AV_CH_WIDE_RIGHT) { + Channel |= WIDE_RIGHT; + } + if ((ChannelLayout & AV_CH_SURROUND_DIRECT_LEFT) == + AV_CH_SURROUND_DIRECT_LEFT) { + Channel |= SURROUND_DIRECT_LEFT; + } + if ((ChannelLayout & AV_CH_SURROUND_DIRECT_RIGHT) == + AV_CH_SURROUND_DIRECT_RIGHT) { + Channel |= SURROUND_DIRECT_RIGHT; + } + if ((ChannelLayout & AV_CH_LOW_FREQUENCY_2) == AV_CH_LOW_FREQUENCY_2) { + Channel |= LOW_FREQUENCY_2; + } + + // Channel Mask C; + if ((ChannelLayout & AV_CH_LAYOUT_NATIVE) == AV_CH_LAYOUT_NATIVE) { + Channel |= NATIVE; + } + if ((ChannelLayout & AV_CH_LAYOUT_MONO) == AV_CH_LAYOUT_MONO) { + Channel |= MONO; + } + if ((ChannelLayout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO) { + Channel |= STEREO; + } + if ((ChannelLayout & AV_CH_LAYOUT_2POINT1) == AV_CH_LAYOUT_2POINT1) { + Channel |= _2POINT1; + } + if ((ChannelLayout & AV_CH_LAYOUT_2_1) == AV_CH_LAYOUT_2_1) { + Channel |= _2_1; + } + if ((ChannelLayout & AV_CH_LAYOUT_SURROUND) == AV_CH_LAYOUT_SURROUND) { + Channel |= SURROUND; + } + if ((ChannelLayout & AV_CH_LAYOUT_3POINT1) == AV_CH_LAYOUT_3POINT1) { + Channel |= _3POINT1; + } + if ((ChannelLayout & AV_CH_LAYOUT_4POINT0) == AV_CH_LAYOUT_4POINT0) { + Channel |= _4POINT0; + } + if ((ChannelLayout & AV_CH_LAYOUT_4POINT1) == AV_CH_LAYOUT_4POINT1) { + Channel |= _4POINT1; + } + if ((ChannelLayout & AV_CH_LAYOUT_2_2) == AV_CH_LAYOUT_2_2) { + Channel |= _2_2; + } + if ((ChannelLayout & AV_CH_LAYOUT_QUAD) == AV_CH_LAYOUT_QUAD) { + Channel |= QUAD; + } + if ((ChannelLayout & AV_CH_LAYOUT_5POINT0) == AV_CH_LAYOUT_5POINT0) { + Channel |= _5POINT0; + } + if ((ChannelLayout & AV_CH_LAYOUT_5POINT1) == AV_CH_LAYOUT_5POINT1) { + Channel |= _5POINT1; + } + if ((ChannelLayout & AV_CH_LAYOUT_5POINT0_BACK) == + AV_CH_LAYOUT_5POINT0_BACK) { + Channel |= _5POINT0_BACK; + } + if ((ChannelLayout & AV_CH_LAYOUT_5POINT1_BACK) == + AV_CH_LAYOUT_5POINT1_BACK) { + Channel |= _5POINT1_BACK; + } + if ((ChannelLayout & AV_CH_LAYOUT_6POINT0) == AV_CH_LAYOUT_6POINT0) { + Channel |= _6POINT0; + } + if ((ChannelLayout & AV_CH_LAYOUT_6POINT0_FRONT) == + AV_CH_LAYOUT_6POINT0_FRONT) { + Channel |= _6POINT0_FRONT; + } + if ((ChannelLayout & AV_CH_LAYOUT_HEXAGONAL) == AV_CH_LAYOUT_HEXAGONAL) { + Channel |= HEXAGONAL; + } + if ((ChannelLayout & AV_CH_LAYOUT_6POINT1) == AV_CH_LAYOUT_6POINT1) { + Channel |= _6POINT1; + } + if ((ChannelLayout & AV_CH_LAYOUT_6POINT1_BACK) == + AV_CH_LAYOUT_6POINT1_BACK) { + Channel |= _6POINT1_BACK; + } + if ((ChannelLayout & AV_CH_LAYOUT_6POINT1_FRONT) == + AV_CH_LAYOUT_6POINT1_FRONT) { + Channel |= _6POINT1_FRONT; + } + if ((ChannelLayout & AV_CH_LAYOUT_7POINT0) == AV_CH_LAYOUT_7POINT0) { + Channel |= _7POINT0; + } + if ((ChannelLayout & AV_CH_LAYOUT_7POINT0_FRONT) == + AV_CH_LAYOUT_7POINT0_FRONT) { + Channel |= _7POINT0_FRONT; + } + if ((ChannelLayout & AV_CH_LAYOUT_7POINT1) == AV_CH_LAYOUT_7POINT1) { + Channel |= _7POINT1; + } + if ((ChannelLayout & AV_CH_LAYOUT_7POINT1_WIDE) == + AV_CH_LAYOUT_7POINT1_WIDE) { + Channel |= _7POINT1_WIDE; + } + if ((ChannelLayout & AV_CH_LAYOUT_7POINT1_WIDE_BACK) == + AV_CH_LAYOUT_7POINT1_WIDE_BACK) { + Channel |= _7POINT1_WIDE_BACK; + } + if ((ChannelLayout & AV_CH_LAYOUT_OCTAGONAL) == AV_CH_LAYOUT_OCTAGONAL) { + Channel |= OCTAGONAL; + } + if ((ChannelLayout & AV_CH_LAYOUT_HEXADECAGONAL) == + AV_CH_LAYOUT_HEXADECAGONAL) { + Channel |= HEXADECAGONAL; + } + if ((ChannelLayout & AV_CH_LAYOUT_STEREO_DOWNMIX) == + AV_CH_LAYOUT_STEREO_DOWNMIX) { + Channel |= STEREO_DOWNMIX; + } + return Channel; + } +}; + +class SWRFilterType { +public: + uint32_t fromSwrFilterType(SwrFilterType FilterType) { + switch (FilterType) { + case SWR_FILTER_TYPE_CUBIC: + return 1; + case SWR_FILTER_TYPE_BLACKMAN_NUTTALL: + return 2; + case SWR_FILTER_TYPE_KAISER: + return 3; + default: + return 1; + } + } + + SwrFilterType intoSwrFilterType(uint32_t FilterID) { + switch (FilterID) { + case 1: + return SWR_FILTER_TYPE_CUBIC; + case 2: + return SWR_FILTER_TYPE_BLACKMAN_NUTTALL; + case 3: + return SWR_FILTER_TYPE_KAISER; + default: + return SWR_FILTER_TYPE_CUBIC; + } + } +}; + +class SWREngine { +public: + SwrEngine intoSwrEngine(uint32_t EngineId) { + switch (EngineId) { + case 1: + return SWR_ENGINE_SWR; + case 2: + return SWR_ENGINE_SOXR; + default: + return SWR_ENGINE_SWR; + } + } + + uint32_t fromSwrEngine(SwrEngine Engine) { + switch (Engine) { + case SWR_ENGINE_SWR: + return 1; + case SWR_ENGINE_SOXR: + return 2; + case SWR_ENGINE_NB: + return 3; + default: + return SWR_ENGINE_SWR; + } + } +}; + +class SWRDitherType { +public: + SwrDitherType intoSwrDitherType(uint32_t SwrDitherId) { + switch (SwrDitherId) { + case 0: + return SWR_DITHER_NONE; + case 1: + return SWR_DITHER_RECTANGULAR; + case 2: + return SWR_DITHER_TRIANGULAR; + case 3: + return SWR_DITHER_TRIANGULAR_HIGHPASS; + case 64: + return SWR_DITHER_NS; + case 4: + return SWR_DITHER_NS_LIPSHITZ; + case 5: + return SWR_DITHER_NS_F_WEIGHTED; + case 6: + return SWR_DITHER_NS_MODIFIED_E_WEIGHTED; + case 7: + return SWR_DITHER_NS_IMPROVED_E_WEIGHTED; + case 8: + return SWR_DITHER_NS_SHIBATA; + case 9: + return SWR_DITHER_NS_LOW_SHIBATA; + case 10: + return SWR_DITHER_NS_HIGH_SHIBATA; + case 11: + return SWR_DITHER_NB; + default: + return SWR_DITHER_NONE; + } + } + + uint32_t fromSwrDitherType(SwrDitherType SwrDitherType) { + switch (SwrDitherType) { + case SWR_DITHER_NONE: + return 0; + case SWR_DITHER_RECTANGULAR: + return 1; + case SWR_DITHER_TRIANGULAR: + return 2; + case SWR_DITHER_TRIANGULAR_HIGHPASS: + return 3; + case SWR_DITHER_NS: + return 64; + case SWR_DITHER_NS_LIPSHITZ: + return 4; + case SWR_DITHER_NS_F_WEIGHTED: + return 5; + case SWR_DITHER_NS_MODIFIED_E_WEIGHTED: + return 6; + case SWR_DITHER_NS_IMPROVED_E_WEIGHTED: + return 7; + case SWR_DITHER_NS_SHIBATA: + return 8; + case SWR_DITHER_NS_LOW_SHIBATA: + return 9; + case SWR_DITHER_NS_HIGH_SHIBATA: + return 10; + case SWR_DITHER_NB: + return 11; + default: + return 0; + } + } +}; + +class ChromaLocation { +public: + static AVChromaLocation intoAVChromaLocation(int32_t ChromaLocationId) { + switch (ChromaLocationId) { + case 0: + return AVCHROMA_LOC_UNSPECIFIED; + case 1: + return AVCHROMA_LOC_LEFT; + case 2: + return AVCHROMA_LOC_CENTER; + case 3: + return AVCHROMA_LOC_TOPLEFT; + case 4: + return AVCHROMA_LOC_TOP; + case 5: + return AVCHROMA_LOC_BOTTOMLEFT; + case 6: + return AVCHROMA_LOC_BOTTOM; + default: + return AVCHROMA_LOC_UNSPECIFIED; + } + } + + static int32_t fromAVChromaLocation(AVChromaLocation ChromaLocation) { + switch (ChromaLocation) { + case AVCHROMA_LOC_UNSPECIFIED: + return 0; + case AVCHROMA_LOC_LEFT: + return 1; + case AVCHROMA_LOC_CENTER: + return 2; + case AVCHROMA_LOC_TOPLEFT: + return 3; + case AVCHROMA_LOC_TOP: + return 4; + case AVCHROMA_LOC_BOTTOMLEFT: + return 5; + case AVCHROMA_LOC_BOTTOM: + return 6; + default: + return 0; + } + } +}; + +class Rounding { + +public: + static AVRounding intoAVRounding(int32_t RoundingId) { + switch (RoundingId) { + case 0: + return AV_ROUND_ZERO; + case 1: + return AV_ROUND_INF; + case 2: + return AV_ROUND_DOWN; + case 3: + return AV_ROUND_UP; + case 4: + return AV_ROUND_NEAR_INF; + case 5: + return AV_ROUND_PASS_MINMAX; + default: + return AV_ROUND_ZERO; + } + } + + static int32_t fromAVRounding(AVRounding Rounding) { + switch (Rounding) { + case AV_ROUND_ZERO: + return 0; + case AV_ROUND_INF: + return 1; + case AV_ROUND_DOWN: + return 2; + case AV_ROUND_UP: + return 3; + case AV_ROUND_NEAR_INF: + return 4; + case AV_ROUND_PASS_MINMAX: + return 5; + default: + return 0; + } + } +}; + +class OptionType { + +public: + static AVOptionType intoAVOptionType(int32_t RoundingId) { + switch (RoundingId) { + case 0: + return AV_OPT_TYPE_FLAGS; + case 1: + return AV_OPT_TYPE_INT; + case 2: + return AV_OPT_TYPE_INT64; + case 3: + return AV_OPT_TYPE_DOUBLE; + case 4: + return AV_OPT_TYPE_FLOAT; + case 5: + return AV_OPT_TYPE_STRING; + case 6: + return AV_OPT_TYPE_RATIONAL; + case 7: + return AV_OPT_TYPE_BINARY; + case 8: + return AV_OPT_TYPE_DICT; + case 9: + return AV_OPT_TYPE_CONST; + case 10: + return AV_OPT_TYPE_IMAGE_SIZE; + case 11: + return AV_OPT_TYPE_PIXEL_FMT; + case 12: + return AV_OPT_TYPE_SAMPLE_FMT; + case 13: + return AV_OPT_TYPE_VIDEO_RATE; + case 14: + return AV_OPT_TYPE_DURATION; + case 15: + return AV_OPT_TYPE_COLOR; + case 16: + return AV_OPT_TYPE_CHANNEL_LAYOUT; + case 17: + return AV_OPT_TYPE_UINT64; + case 18: + return AV_OPT_TYPE_BOOL; + case 19: + return AV_OPT_TYPE_CHLAYOUT; + default: + return AV_OPT_TYPE_FLAGS; + } + } + + static int32_t fromAVOptionType(AVOptionType OptionType) { + switch (OptionType) { + case AV_OPT_TYPE_FLAGS: + return 0; + case AV_OPT_TYPE_INT: + return 1; + case AV_OPT_TYPE_INT64: + return 2; + case AV_OPT_TYPE_DOUBLE: + return 3; + case AV_OPT_TYPE_FLOAT: + return 4; + case AV_OPT_TYPE_STRING: + return 5; + case AV_OPT_TYPE_RATIONAL: + return 6; + case AV_OPT_TYPE_BINARY: + return 7; + case AV_OPT_TYPE_DICT: + return 8; + case AV_OPT_TYPE_CONST: + return 9; + case AV_OPT_TYPE_IMAGE_SIZE: + return 10; + case AV_OPT_TYPE_PIXEL_FMT: + return 11; + case AV_OPT_TYPE_SAMPLE_FMT: + return 12; + case AV_OPT_TYPE_VIDEO_RATE: + return 13; + case AV_OPT_TYPE_DURATION: + return 14; + case AV_OPT_TYPE_COLOR: + return 15; + case AV_OPT_TYPE_CHANNEL_LAYOUT: + return 16; + case AV_OPT_TYPE_UINT64: + return 17; + case AV_OPT_TYPE_BOOL: + return 18; + case AV_OPT_TYPE_CHLAYOUT: + return 19; + default: + return 0; + } + } +}; + +class PictureType { +public: + static AVPictureType intoAVPictureType(int32_t PictureId) { + switch (PictureId) { + case 0: + return AV_PICTURE_TYPE_NONE; + case 1: + return AV_PICTURE_TYPE_I; + case 2: + return AV_PICTURE_TYPE_P; + case 3: + return AV_PICTURE_TYPE_B; + case 4: + return AV_PICTURE_TYPE_S; + case 5: + return AV_PICTURE_TYPE_SI; + case 6: + return AV_PICTURE_TYPE_SP; + case 7: + return AV_PICTURE_TYPE_BI; + default: + return AV_PICTURE_TYPE_NONE; + } + }; + + static int32_t fromAVPictureType(AVPictureType PictureType) { + switch (PictureType) { + case AV_PICTURE_TYPE_NONE: + return 0; + case AV_PICTURE_TYPE_I: + return 1; + case AV_PICTURE_TYPE_P: + return 2; + case AV_PICTURE_TYPE_B: + return 3; + case AV_PICTURE_TYPE_S: + return 4; + case AV_PICTURE_TYPE_SI: + return 5; + case AV_PICTURE_TYPE_SP: + return 6; + case AV_PICTURE_TYPE_BI: + return 7; + default: + return 0; + } + } +}; + +// Direct mapping in rust. Not required. Can be used for decoupling (Clean +// Code). +// +// class ColorTransferCharacteristic { +// +// static AVColorTransferCharacteristic +// intoColorTransferCharacteristic(uint32_t ColorTransferCharacteristicId) { +// switch (ColorTransferCharacteristicId) { +// case 0: +// return AVCOL_TRC_RESERVED0; +// case 1: +// return AVCOL_TRC_BT709; +// case 2: +// return AVCOL_TRC_UNSPECIFIED; +// case 3: +// return AVCOL_TRC_RESERVED; +// case 4: +// return AVCOL_TRC_GAMMA22; +// case 5: +// return AVCOL_TRC_GAMMA28; +// case 6: +// return AVCOL_TRC_SMPTE170M; +// case 7: +// return AVCOL_TRC_SMPTE240M; +// case 8: +// return AVCOL_TRC_LINEAR; +// case 9: +// return AVCOL_TRC_LOG; +// case 10: +// return AVCOL_TRC_LOG_SQRT; +// case 11: +// return AVCOL_TRC_IEC61966_2_4; +// case 12: +// return AVCOL_TRC_BT1361_ECG; +// case 13: +// return AVCOL_TRC_IEC61966_2_1; +// case 14: +// return AVCOL_TRC_BT2020_10; +// case 15: +// return AVCOL_TRC_BT2020_12; +// case 16: +// return AVCOL_TRC_SMPTE2084; +// case 17: +// return AVCOL_TRC_SMPTE428; +// case 18: +// return AVCOL_TRC_ARIB_STD_B67; +// case 19: +// return AVCOL_TRC_NB; +// default: +// return AVCOL_TRC_RESERVED0; +// } +// }; +// +// static uint32_t +// fromColorTransferCharacteristic(uint32_t ColorTransferCharacteristic) { +// switch (ColorTransferCharacteristic) { +// case AVCOL_TRC_RESERVED0: +// return 0; +// case AVCOL_TRC_BT709: +// return 1; +// case AVCOL_TRC_UNSPECIFIED: +// return 2; +// case AVCOL_TRC_RESERVED: +// return 3; +// case AVCOL_TRC_GAMMA22: +// return 4; +// case AVCOL_TRC_GAMMA28: +// return 5; +// case AVCOL_TRC_SMPTE170M: +// return 6; +// case AVCOL_TRC_SMPTE240M: +// return 7; +// case AVCOL_TRC_LINEAR: +// return 8; +// case AVCOL_TRC_LOG: +// return 9; +// case AVCOL_TRC_LOG_SQRT: +// return 10; +// case AVCOL_TRC_IEC61966_2_4: +// return 11; +// case AVCOL_TRC_BT1361_ECG: +// return 12; +// case AVCOL_TRC_IEC61966_2_1: +// return 13; +// case AVCOL_TRC_BT2020_10: +// return 14; +// case AVCOL_TRC_BT2020_12: +// return 15; +// case AVCOL_TRC_SMPTE2084: +// return 16; +// case AVCOL_TRC_SMPTE428: +// return 17; +// case AVCOL_TRC_ARIB_STD_B67: +// return 18; +// case AVCOL_TRC_NB: +// return 19; +// default: +// return 0; +// } +// }; +//}; + +// We can keep or remove the binding. +class ColorSpace { + +public: + static AVColorSpace intoAVColorSpace(int32_t ColorSpaceId) { + + switch (ColorSpaceId) { + case 0: + return AVCOL_SPC_RGB; + case 1: + return AVCOL_SPC_BT709; + case 2: + return AVCOL_SPC_UNSPECIFIED; + case 3: + return AVCOL_SPC_RESERVED; + case 4: + return AVCOL_SPC_FCC; + case 5: + return AVCOL_SPC_BT470BG; + case 6: + return AVCOL_SPC_SMPTE170M; + case 7: + return AVCOL_SPC_SMPTE240M; + case 8: + return AVCOL_SPC_YCGCO; + case 9: + return AVCOL_SPC_BT2020_NCL; + case 10: + return AVCOL_SPC_BT2020_CL; + case 11: + return AVCOL_SPC_SMPTE2085; + case 12: + return AVCOL_SPC_CHROMA_DERIVED_NCL; + case 13: + return AVCOL_SPC_CHROMA_DERIVED_CL; + case 14: + return AVCOL_SPC_ICTCP; + default: + return AVCOL_SPC_RGB; + } + }; + + static int32_t fromAVColorSpace(AVColorSpace ColorSpace) { + + switch (ColorSpace) { + case AVCOL_SPC_RGB: + return 0; + case AVCOL_SPC_BT709: + return 1; + case AVCOL_SPC_UNSPECIFIED: + return 2; + case AVCOL_SPC_RESERVED: + return 3; + case AVCOL_SPC_FCC: + return 4; + case AVCOL_SPC_BT470BG: + return 5; + case AVCOL_SPC_SMPTE170M: + return 6; + case AVCOL_SPC_SMPTE240M: + return 7; + case AVCOL_SPC_YCGCO: + return 8; + case AVCOL_SPC_BT2020_NCL: + return 9; + case AVCOL_SPC_BT2020_CL: + return 10; + case AVCOL_SPC_SMPTE2085: + return 11; + case AVCOL_SPC_CHROMA_DERIVED_NCL: + return 12; + case AVCOL_SPC_CHROMA_DERIVED_CL: + return 13; + case AVCOL_SPC_ICTCP: + return 14; + default: + return 0; + } + }; +}; + +class FieldOrder { +public: + static AVFieldOrder intoAVFieldOrder(int32_t FieldOrderId) { + switch (FieldOrderId) { + case 0: + return AV_FIELD_UNKNOWN; + case 1: + return AV_FIELD_PROGRESSIVE; + case 2: + return AV_FIELD_TT; + case 3: + return AV_FIELD_BB; + case 4: + return AV_FIELD_TB; + case 5: + return AV_FIELD_BT; + default: + return AV_FIELD_UNKNOWN; + } + } + + static int32_t fromAVFieldOrder(AVFieldOrder FieldOrder) { + switch (FieldOrder) { + case AV_FIELD_UNKNOWN: + return 0; + case AV_FIELD_PROGRESSIVE: + return 1; + case AV_FIELD_TT: + return 2; + case AV_FIELD_BB: + return 3; + case AV_FIELD_TB: + return 4; + case AV_FIELD_BT: + return 5; + default: + return 0; + } + } +}; + +class ColorPrimaries { + +public: + static AVColorPrimaries intoAVColorPrimaries(int32_t ColorPrimariesId) { + switch (ColorPrimariesId) { + case 0: + return AVCOL_PRI_RESERVED0; + case 1: + return AVCOL_PRI_BT709; + case 2: + return AVCOL_PRI_UNSPECIFIED; + case 3: + return AVCOL_PRI_RESERVED; + case 4: + return AVCOL_PRI_BT470M; + case 5: + return AVCOL_PRI_BT470BG; + case 6: + return AVCOL_PRI_SMPTE170M; + case 7: + return AVCOL_PRI_SMPTE240M; + case 8: + return AVCOL_PRI_FILM; + case 9: + return AVCOL_PRI_BT2020; + case 10: + return AVCOL_PRI_SMPTE428; + case 11: + return AVCOL_PRI_SMPTE431; + case 12: + return AVCOL_PRI_SMPTE432; + case 13: + return AVCOL_PRI_JEDEC_P22; + case 14: + return AVCOL_PRI_EBU3213; + default: + return AVCOL_PRI_RESERVED0; + } + }; + + static int32_t fromAVColorPrimaries(AVColorPrimaries ColorPrimaries) { + switch (ColorPrimaries) { + case AVCOL_PRI_RESERVED0: + return 0; + case AVCOL_PRI_BT709: + return 1; + case AVCOL_PRI_UNSPECIFIED: + return 2; + case AVCOL_PRI_RESERVED: + return 3; + case AVCOL_PRI_BT470M: + return 4; + case AVCOL_PRI_BT470BG: + return 5; + case AVCOL_PRI_SMPTE170M: + return 6; + case AVCOL_PRI_SMPTE240M: + return 7; + case AVCOL_PRI_FILM: + return 8; + case AVCOL_PRI_BT2020: + return 9; + case AVCOL_PRI_SMPTE428: + return 10; + case AVCOL_PRI_SMPTE431: + return 11; + case AVCOL_PRI_SMPTE432: + return 12; + // #[cfg(not(feature = "ffmpeg_4_3"))] + // case AVCOL_PRI_JEDEC_P22: + // return 13; + case AVCOL_PRI_EBU3213: + return 14; + default: + return 0; + } + }; +}; + +} // namespace FFmpegUtils +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/ffmpeg_base.h b/plugins/wasmedge_ffmpeg/ffmpeg_base.h new file mode 100644 index 000000000000..faac0e3d3b7a --- /dev/null +++ b/plugins/wasmedge_ffmpeg/ffmpeg_base.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_env.h" + +#include "runtime/callingframe.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +template <typename T> class HostFunction : public Runtime::HostFunction<T> { +public: + HostFunction(std::shared_ptr<WasmEdgeFFmpegEnv> HostEnv) + : Runtime::HostFunction<T>(0), Env(HostEnv) {} + +protected: + std::shared_ptr<WasmEdgeFFmpegEnv> Env; +}; + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/ffmpeg_env.cpp b/plugins/wasmedge_ffmpeg/ffmpeg_env.cpp new file mode 100644 index 000000000000..14ded24c08b1 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/ffmpeg_env.cpp @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avcodec/module.h" +#include "avdevice/module.h" +#include "avfilter/module.h" +#include "avformat/module.h" +#include "avutil/module.h" +#include "swresample/module.h" +#include "swscale/module.h" + +#include "ffmpeg_env.h" + +namespace WasmEdge { +namespace Host { +namespace { + +Runtime::Instance::ModuleInstance * +createAVCodec(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new WasmEdgeFFmpeg::AVcodec::WasmEdgeFFmpegAVCodecModule( + WasmEdgeFFmpeg::WasmEdgeFFmpegEnv::getInstance()); +} + +Runtime::Instance::ModuleInstance * +createAVDevice(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new WasmEdgeFFmpeg::AVDevice::WasmEdgeFFmpegAVDeviceModule( + WasmEdgeFFmpeg::WasmEdgeFFmpegEnv::getInstance()); +} + +Runtime::Instance::ModuleInstance * +createAVFilter(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new WasmEdgeFFmpeg::AVFilter::WasmEdgeFFmpegAVFilterModule( + WasmEdgeFFmpeg::WasmEdgeFFmpegEnv::getInstance()); +} + +Runtime::Instance::ModuleInstance * +createAVFormat(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new WasmEdgeFFmpeg::AVFormat::WasmEdgeFFmpegAVFormatModule( + WasmEdgeFFmpeg::WasmEdgeFFmpegEnv::getInstance()); +} + +Runtime::Instance::ModuleInstance * +createAVUtil(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new WasmEdgeFFmpeg::AVUtil::WasmEdgeFFmpegAVUtilModule( + WasmEdgeFFmpeg::WasmEdgeFFmpegEnv::getInstance()); +} + +Runtime::Instance::ModuleInstance * +createSWResample(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new WasmEdgeFFmpeg::SWResample::WasmEdgeFFmpegSWResampleModule( + WasmEdgeFFmpeg::WasmEdgeFFmpegEnv::getInstance()); +} + +Runtime::Instance::ModuleInstance * +createSWScale(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new WasmEdgeFFmpeg::SWScale::WasmEdgeFFmpegSWScaleModule( + WasmEdgeFFmpeg::WasmEdgeFFmpegEnv::getInstance()); +} + +Plugin::Plugin::PluginDescriptor Descriptor{ + .Name = "wasmedge_ffmpeg", + .Description = "", + .APIVersion = Plugin::Plugin::CurrentAPIVersion, + .Version = {0, 0, 0, 1}, + .ModuleCount = 7, + .ModuleDescriptions = + (Plugin::PluginModule::ModuleDescriptor[]){ + { + .Name = "wasmedge_ffmpeg_avcodec", + .Description = "encoding/decoding library", + .Create = createAVCodec, + }, + { + .Name = "wasmedge_ffmpeg_avdevice", + .Description = "special devices muxing/demuxing library ", + .Create = createAVDevice, + }, + { + .Name = "wasmedge_ffmpeg_avfilter", + .Description = "graph-based frame editing library", + .Create = createAVFilter, + }, + { + .Name = "wasmedge_ffmpeg_avformat", + .Description = "I/O and muxing/demuxing library", + .Create = createAVFormat, + }, + { + .Name = "wasmedge_ffmpeg_avutil", + .Description = "utils utility library", + .Create = createAVUtil, + }, + { + .Name = "wasmedge_ffmpeg_swresample", + .Description = "audio resampling, format conversion and mixing", + .Create = createSWResample, + }, + { + .Name = "wasmedge_ffmpeg_swscale", + .Description = "color conversion and scaling library", + .Create = createSWScale, + }}, + .AddOptions = nullptr, +}; + +EXPORT_GET_DESCRIPTOR(Descriptor) + +} // namespace + +std::weak_ptr<WasmEdgeFFmpeg::WasmEdgeFFmpegEnv> + WasmEdgeFFmpeg::WasmEdgeFFmpegEnv::Instance = + std::make_shared<WasmEdgeFFmpeg::WasmEdgeFFmpegEnv>(); + +std::shared_mutex WasmEdgeFFmpeg::WasmEdgeFFmpegEnv::Mutex; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/ffmpeg_env.h b/plugins/wasmedge_ffmpeg/ffmpeg_env.h new file mode 100644 index 000000000000..c2ad46b7391a --- /dev/null +++ b/plugins/wasmedge_ffmpeg/ffmpeg_env.h @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "bindings.h" +#include "plugin/plugin.h" + +#include <memory> +#include <vector> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +class WasmEdgeFFmpegEnv { +public: + // Singleton + static std::shared_ptr<WasmEdgeFFmpegEnv> getInstance() noexcept { + std::unique_lock Lock(Mutex); + std::shared_ptr<WasmEdgeFFmpegEnv> EnvPtr = Instance.lock(); + if (!EnvPtr) { + EnvPtr.reset(new WasmEdgeFFmpegEnv()); + Instance = EnvPtr; + } + return EnvPtr; + } + + // Avoid copy constructor and overloading functions. + WasmEdgeFFmpegEnv(const WasmEdgeFFmpegEnv &) = delete; + void operator=(const WasmEdgeFFmpegEnv &) = delete; + + void alloc(void *Data, uint32_t *DataPtr) { + FfmpegPtrMap[FfmpegPtrAllocateKey++] = Data; + *DataPtr = FfmpegPtrAllocateKey - 1; + } + + void *fetchData(const size_t Index) { + if (Index >= FfmpegPtrAllocateKey) { + return nullptr; + } + // Check this condition. + if (FfmpegPtrMap[Index] == nullptr) { + return nullptr; + } + + return FfmpegPtrMap[Index]; + } + + void dealloc(size_t Index) { + + if (Index >= FfmpegPtrAllocateKey) { + return; + } + + FfmpegPtrMap.erase(Index); + } + + WasmEdgeFFmpegEnv() noexcept {} + +private: + // Using zero as NULL Value. + uint32_t FfmpegPtrAllocateKey = 1; + // Can update this to uint64_t to get more memory. + std::map<uint32_t, void *> FfmpegPtrMap; + static std::weak_ptr<WasmEdgeFFmpegEnv> Instance; + static std::shared_mutex Mutex; +}; + +// Utils functions. +#define MEMINST_CHECK(Out, CallFrame, Index) \ + auto *Out = CallFrame.getMemoryByIndex(Index); \ + if (unlikely(Out == nullptr)) { \ + spdlog::error("[WasmEdge-FFmpeg] Memory instance not found."sv); \ + return static_cast<int32_t>(ErrNo::MissingMemory); \ + } + +#define FFMPEG_PTR_FETCH(StructPtr, FFmpegStructId, Type) \ + Type *StructPtr = nullptr; \ + if (FFmpegStructId != 0) \ + StructPtr = static_cast<Type *>(Env.get()->fetchData(FFmpegStructId)); + +#define MEM_SPAN_CHECK(OutSpan, MemInst, Type, BufPtr, BufLen, Message) \ + auto OutSpan = MemInst->getSpan<Type>(BufPtr, BufLen); \ + if (unlikely(OutSpan.size() != BufLen)) { \ + spdlog::error("[WasmEdge-FFmpeg] "sv Message); \ + return static_cast<uint32_t>(ErrNo::MissingMemory); \ + } + +#define FFMPEG_PTR_STORE(StructPtr, FFmpegStructId) \ + Env.get()->alloc(StructPtr, FFmpegStructId); + +#define FFMPEG_PTR_DELETE(FFmpegStructId) Env.get()->dealloc(FFmpegStructId); + +#define MEM_PTR_CHECK(OutPtr, MemInst, Type, Offset, Message) \ + Type *OutPtr = MemInst->getPointerOrNull<Type *>(Offset); \ + if (unlikely(OutPtr == nullptr)) { \ + spdlog::error("[WasmEdge-FFmpeg] "sv Message); \ + return static_cast<int32_t>(ErrNo::MissingMemory); \ + } + +// Starting from 200 because, posix codes take values till 131. +// Hence using 200. +enum class ErrNo : int32_t { + Success = 0, // No error occurred. + MissingMemory = -201, // Caller module is missing a memory export. + NullStructId = -202, // Rust Sdk Passes null id. + InternalError = -203, + UnImplemented = -204 // Unimplemented funcs. +}; + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/swresample/module.cpp b/plugins/wasmedge_ffmpeg/swresample/module.cpp new file mode 100644 index 000000000000..5b5f9867ff63 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swresample/module.cpp @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "module.h" +#include "swresample_func.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWResample { + +WasmEdgeFFmpegSWResampleModule::WasmEdgeFFmpegSWResampleModule( + std::shared_ptr<WasmEdgeFFmpegEnv> Env) + : ModuleInstance("wasmedge_ffmpeg_swresample") { + addHostFunc("wasmedge_ffmpeg_swresample_swresample_version", + std::make_unique<SWResampleVersion>(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swr_get_delay", + std::make_unique<SWRGetDelay>(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swr_init", + std::make_unique<SWRInit>(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swr_alloc_set_opts", + std::make_unique<SWRAllocSetOpts>(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_av_opt_set_dict", + std::make_unique<AVOptSetDict>(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swr_convert_frame", + std::make_unique<SWRConvertFrame>(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swr_free", + std::make_unique<SWRFree>(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swresample_configuration_length", + std::make_unique<SWResampleConfigurationLength>(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swresample_configuration", + std::make_unique<SWResampleConfiguration>(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swresample_license_length", + std::make_unique<SWResampleLicenseLength>(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swresample_license", + std::make_unique<SWResampleLicense>(Env)); +} + +} // namespace SWResample +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/swresample/module.h b/plugins/wasmedge_ffmpeg/swresample/module.h new file mode 100644 index 000000000000..00d4c839a785 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swresample/module.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_env.h" + +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWResample { + +class WasmEdgeFFmpegSWResampleModule + : public Runtime::Instance::ModuleInstance { +public: + WasmEdgeFFmpegSWResampleModule(std::shared_ptr<WasmEdgeFFmpegEnv> Env); +}; + +} // namespace SWResample +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/swresample/swresample_func.cpp b/plugins/wasmedge_ffmpeg/swresample/swresample_func.cpp new file mode 100644 index 000000000000..3c81578caec4 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swresample/swresample_func.cpp @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "swresample_func.h" + +extern "C" { +#include "libavutil/avutil.h" +#include "libavutil/opt.h" +#include "libswresample/swresample.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWResample { + +Expect<uint32_t> SWResampleVersion::body(const Runtime::CallingFrame &) { + return swresample_version(); +} + +Expect<int64_t> SWRGetDelay::body(const Runtime::CallingFrame &, + uint32_t SWRContextId, int64_t Base) { + FFMPEG_PTR_FETCH(SWRContext, SWRContextId, SwrContext); + return swr_get_delay(SWRContext, Base); +} + +Expect<int32_t> SWRInit::body(const Runtime::CallingFrame &, + uint32_t SWRContextId) { + FFMPEG_PTR_FETCH(SWRContext, SWRContextId, SwrContext); + return swr_init(SWRContext); +} + +Expect<int32_t> +SWRAllocSetOpts::body(const Runtime::CallingFrame &Frame, uint32_t SwrCtxPtr, + uint32_t SWRContextId, uint64_t OutChLayoutId, + uint32_t OutSampleFmtId, int32_t OutSampleRate, + uint64_t InChLayoutId, uint32_t InSampleFmtId, + int32_t InSampleRate, int32_t LogOffset) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(SwrCtxId, MemInst, uint32_t, SwrCtxPtr, "") + FFMPEG_PTR_FETCH(CurrSwrCtx, *SwrCtxId, SwrContext); + FFMPEG_PTR_FETCH(ExistSWRContext, SWRContextId, SwrContext); + + uint64_t const OutChLayout = + FFmpegUtils::ChannelLayout::fromChannelLayoutID(OutChLayoutId); + AVSampleFormat const OutSampleFmt = + FFmpegUtils::SampleFmt::fromSampleID(OutSampleFmtId); + uint64_t const InChLayout = + FFmpegUtils::ChannelLayout::fromChannelLayoutID(InChLayoutId); + AVSampleFormat const InSampleFmt = + FFmpegUtils::SampleFmt::fromSampleID(InSampleFmtId); + CurrSwrCtx = swr_alloc_set_opts( + ExistSWRContext, OutChLayout, OutSampleFmt, OutSampleRate, InChLayout, + InSampleFmt, InSampleRate, LogOffset, + nullptr); // Always being used as null in rust sdk. + FFMPEG_PTR_STORE(CurrSwrCtx, SwrCtxId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> AVOptSetDict::body(const Runtime::CallingFrame &, + uint32_t SWRContextId, uint32_t DictId) { + FFMPEG_PTR_FETCH(SWRContext, SWRContextId, SwrContext); + FFMPEG_PTR_FETCH(AvDictionary, DictId, AVDictionary *); + return av_opt_set_dict(SWRContext, AvDictionary); +} + +Expect<int32_t> SWRConvertFrame::body(const Runtime::CallingFrame &, + uint32_t SWRContextId, + uint32_t FrameOutputId, + uint32_t FrameInputId) { + FFMPEG_PTR_FETCH(SWRContext, SWRContextId, SwrContext); + FFMPEG_PTR_FETCH(OuputFrame, FrameOutputId, AVFrame); + FFMPEG_PTR_FETCH(InputFrame, FrameInputId, AVFrame); + + return swr_convert_frame(SWRContext, OuputFrame, InputFrame); +} + +Expect<int32_t> SWRFree::body(const Runtime::CallingFrame &, + uint32_t SWRContextId) { + FFMPEG_PTR_FETCH(SWRContext, SWRContextId, SwrContext); + swr_close(SWRContext); + FFMPEG_PTR_DELETE(SWRContextId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> +SWResampleConfigurationLength::body(const Runtime::CallingFrame &) { + const char *Config = swresample_configuration(); + return strlen(Config); +} + +Expect<int32_t> +SWResampleConfiguration::body(const Runtime::CallingFrame &Frame, + uint32_t ConfigPtr, uint32_t ConfigLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(ConfigBuf, MemInst, char, ConfigPtr, ConfigLen, ""); + + const char *Config = swresample_configuration(); + std::copy_n(Config, ConfigLen, ConfigBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SWResampleLicenseLength::body(const Runtime::CallingFrame &) { + const char *License = swresample_license(); + return strlen(License); +} + +Expect<int32_t> SWResampleLicense::body(const Runtime::CallingFrame &Frame, + uint32_t LicensePtr, + uint32_t LicenseLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(LicenseBuf, MemInst, char, LicensePtr, LicenseLen, ""); + + const char *License = swresample_license(); + std::copy_n(License, LicenseLen, LicenseBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace SWResample +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/swresample/swresample_func.h b/plugins/wasmedge_ffmpeg/swresample/swresample_func.h new file mode 100644 index 000000000000..61104d7049bf --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swresample/swresample_func.h @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWResample { + +class SWResampleVersion : public HostFunction<SWResampleVersion> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame); +}; + +class SWRGetDelay : public HostFunction<SWRGetDelay> { +public: + using HostFunction::HostFunction; + Expect<int64_t> body(const Runtime::CallingFrame &Frame, + uint32_t SWRContextId, int64_t Base); +}; + +class SWRInit : public HostFunction<SWRInit> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SWRContextId); +}; + +class SWRAllocSetOpts : public HostFunction<SWRAllocSetOpts> { +public: + using HostFunction::HostFunction; + + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t SwrCtxPtr, + uint32_t SWRContextId, uint64_t OutChLayout, + uint32_t OutSampleFmtId, int32_t OutSampleRate, + uint64_t InChLayout, uint32_t InSampleFmtId, + int32_t InSampleRate, int32_t LogOffset); +}; + +class AVOptSetDict : public HostFunction<AVOptSetDict> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SWRContextId, uint32_t DictId); +}; + +class SWRConvertFrame : public HostFunction<SWRConvertFrame> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SWRContextId, uint32_t FrameOutputId, + uint32_t FrameInputId); +}; + +class SWRFree : public HostFunction<SWRFree> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SWRContextId); +}; + +class SWResampleConfigurationLength + : public HostFunction<SWResampleConfigurationLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class SWResampleConfiguration : public HostFunction<SWResampleConfiguration> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class SWResampleLicenseLength : public HostFunction<SWResampleLicenseLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class SWResampleLicense : public HostFunction<SWResampleLicense> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t LicensePtr, + uint32_t LicenseLen); +}; + +} // namespace SWResample +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/swscale/module.cpp b/plugins/wasmedge_ffmpeg/swscale/module.cpp new file mode 100644 index 000000000000..da84ee065aa2 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swscale/module.cpp @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "module.h" +#include "swscale_func.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWScale { + +WasmEdgeFFmpegSWScaleModule::WasmEdgeFFmpegSWScaleModule( + std::shared_ptr<WasmEdgeFFmpegEnv> Env) + : ModuleInstance("wasmedge_ffmpeg_swscale") { + addHostFunc("wasmedge_ffmpeg_swscale_swscale_version", + std::make_unique<SwscaleVersion>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_swscale_configuration_length", + std::make_unique<SwscaleConfigurationLength>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_swscale_configuration", + std::make_unique<SwscaleConfiguration>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_swscale_license_length", + std::make_unique<SwscaleLicenseLength>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_swscale_license", + std::make_unique<SwscaleLicense>(Env)); + + // SwsContext + addHostFunc("wasmedge_ffmpeg_swscale_sws_getContext", + std::make_unique<SwsGetContext>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_freeContext", + std::make_unique<SwsFreeContext>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_scale", + std::make_unique<SwsScale>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getCachedContext", + std::make_unique<SwsGetCachedContext>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_isSupportedInput", + std::make_unique<SwsIsSupportedInput>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_isSupportedOutput", + std::make_unique<SwsIsSupportedOutput>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_isSupportedEndiannessConversion", + std::make_unique<SwsIsSupportedEndiannessConversion>(Env)); + + // SwsFilter + addHostFunc("wasmedge_ffmpeg_swscale_sws_getDefaultFilter", + std::make_unique<SwsGetDefaultFilter>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getLumaH", + std::make_unique<SwsGetLumaH>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getLumaV", + std::make_unique<SwsGetLumaV>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getChromaH", + std::make_unique<SwsGetChromaH>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getChromaV", + std::make_unique<SwsGetChromaV>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_freeFilter", + std::make_unique<SwsFreeFilter>(Env)); + + // SwsVector + addHostFunc("wasmedge_ffmpeg_swscale_sws_allocVec", + std::make_unique<SwsAllocVec>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getGaussianVec", + std::make_unique<SwsGetGaussianVec>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_scaleVec", + std::make_unique<SwsScaleVec>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_normalizeVec", + std::make_unique<SwsNormalizeVec>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getCoeffVecLength", + std::make_unique<SwsGetCoeffVecLength>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getCoeff", + std::make_unique<SwsGetCoeff>(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_freeVec", + std::make_unique<SwsFreeVec>(Env)); +} + +} // namespace SWScale +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/swscale/module.h b/plugins/wasmedge_ffmpeg/swscale/module.h new file mode 100644 index 000000000000..e9ca104def5b --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swscale/module.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_env.h" + +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWScale { + +class WasmEdgeFFmpegSWScaleModule : public Runtime::Instance::ModuleInstance { +public: + WasmEdgeFFmpegSWScaleModule(std::shared_ptr<WasmEdgeFFmpegEnv> Env); +}; + +} // namespace SWScale +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/swscale/swscale_func.cpp b/plugins/wasmedge_ffmpeg/swscale/swscale_func.cpp new file mode 100644 index 000000000000..5da058cca984 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swscale/swscale_func.cpp @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "swscale_func.h" + +extern "C" { +#include "libavutil/frame.h" +#include "libswscale/swscale.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWScale { + +Expect<int32_t> +SwsGetContext::body(const Runtime::CallingFrame &Frame, uint32_t SwsCtxPtr, + uint32_t SrcW, uint32_t SrcH, uint32_t SrcPixFormatId, + uint32_t DesW, uint32_t DesH, uint32_t DesPixFormatId, + int32_t Flags, uint32_t SrcFilterId, uint32_t DesFilterId) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(SwsCtxId, MemInst, uint32_t, SwsCtxPtr, + "Failed when accessing the return SWSContext Memory"sv) + + FFMPEG_PTR_FETCH(SwsCtx, *SwsCtxId, SwsContext) + FFMPEG_PTR_FETCH(SrcSwsFilter, SrcFilterId, SwsFilter) + FFMPEG_PTR_FETCH(DesSwsFilter, DesFilterId, SwsFilter) + + AVPixelFormat const SrcPixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(SrcPixFormatId); + AVPixelFormat const DestPixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(DesPixFormatId); + SwsCtx = sws_getContext(SrcW, SrcH, SrcPixelFormat, DesW, DesH, + DestPixelFormat, Flags, SrcSwsFilter, DesSwsFilter, + nullptr); // Not using param anywhere in Rust SDK. + if (SwsCtx == nullptr) { + return static_cast<int32_t>(ErrNo::InternalError); + } + FFMPEG_PTR_STORE(SwsCtx, SwsCtxId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsFreeContext::body(const Runtime::CallingFrame &, + uint32_t SwsCtxId) { + FFMPEG_PTR_FETCH(SwsCtx, SwsCtxId, SwsContext) + sws_freeContext(SwsCtx); + FFMPEG_PTR_DELETE(SwsCtxId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsScale::body(const Runtime::CallingFrame &, uint32_t SwsCtxId, + uint32_t InputFrameId, int32_t SrcSliceY, + int32_t SrcSliceH, uint32_t OutputFrameId) { + FFMPEG_PTR_FETCH(SwsCtx, SwsCtxId, SwsContext); + FFMPEG_PTR_FETCH(InputFrame, InputFrameId, AVFrame); + FFMPEG_PTR_FETCH(OutputFrame, OutputFrameId, AVFrame); + return sws_scale(SwsCtx, InputFrame->data, InputFrame->linesize, SrcSliceY, + SrcSliceH, OutputFrame->data, OutputFrame->linesize); +} + +Expect<int32_t> SwsGetCachedContext::body( + const Runtime::CallingFrame &Frame, uint32_t SwsCachedCtxPtr, + uint32_t SwsCtxId, uint32_t SrcW, uint32_t SrcH, uint32_t SrcPixFormatId, + uint32_t DesW, uint32_t DesH, uint32_t DesPixFormatId, int32_t Flags, + uint32_t SrcFilterId, uint32_t DesFilterId) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(SwsCachedCtxId, MemInst, uint32_t, SwsCachedCtxPtr, "") + + FFMPEG_PTR_FETCH(SwsCachedCtx, *SwsCachedCtxId, SwsContext); + FFMPEG_PTR_FETCH(SwsCtx, SwsCtxId, SwsContext); + FFMPEG_PTR_FETCH(SrcSwsFilter, SrcFilterId, SwsFilter) + FFMPEG_PTR_FETCH(DesSwsFilter, DesFilterId, SwsFilter) + + AVPixelFormat const SrcPixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(SrcPixFormatId); + AVPixelFormat const DestPixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(DesPixFormatId); + SwsCachedCtx = sws_getCachedContext(SwsCtx, SrcW, SrcH, SrcPixelFormat, DesW, + DesH, DestPixelFormat, Flags, + SrcSwsFilter, DesSwsFilter, nullptr); + if (SwsCachedCtx == nullptr) { + return static_cast<int32_t>(ErrNo::InternalError); + } + + FFMPEG_PTR_STORE(SwsCachedCtx, SwsCachedCtxId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsIsSupportedInput::body(const Runtime::CallingFrame &, + uint32_t PixFormatId) { + AVPixelFormat const PixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(PixFormatId); + return sws_isSupportedInput(PixelFormat); +} + +Expect<int32_t> SwsIsSupportedOutput::body(const Runtime::CallingFrame &, + uint32_t PixFormatId) { + AVPixelFormat const PixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(PixFormatId); + return sws_isSupportedOutput(PixelFormat); +} + +Expect<int32_t> +SwsIsSupportedEndiannessConversion::body(const Runtime::CallingFrame &, + uint32_t PixFormatId) { + AVPixelFormat const PixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(PixFormatId); + return sws_isSupportedEndiannessConversion(PixelFormat); +} + +Expect<int32_t> SwsGetDefaultFilter::body( + const Runtime::CallingFrame &Frame, uint32_t SwsFilterPtr, float LumaGBlur, + float ChromaGBlur, float LumaSharpen, float ChromaSharpen, + float ChromaHShift, float ChromaVShift, int32_t Verbose) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(SwsFilterId, MemInst, uint32_t, SwsFilterPtr, "") + + SwsFilter *Filter = + sws_getDefaultFilter(LumaGBlur, ChromaGBlur, LumaSharpen, ChromaSharpen, + ChromaHShift, ChromaVShift, Verbose); + if (Filter == nullptr) { + return static_cast<int32_t>(ErrNo::InternalError); + } + FFMPEG_PTR_STORE(Filter, SwsFilterId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsGetLumaH::body(const Runtime::CallingFrame &Frame, + uint32_t SwsFilterId, uint32_t SwsVectorPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(SwsVectorId, MemInst, uint32_t, SwsVectorPtr, "") + FFMPEG_PTR_FETCH(Filter, SwsFilterId, SwsFilter); + + SwsVector *Vector = Filter->lumH; + FFMPEG_PTR_STORE(Vector, SwsVectorId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsGetLumaV::body(const Runtime::CallingFrame &Frame, + uint32_t SwsFilterId, uint32_t SwsVectorPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(SwsVectorId, MemInst, uint32_t, SwsVectorPtr, "") + FFMPEG_PTR_FETCH(Filter, SwsFilterId, SwsFilter); + + SwsVector *Vector = Filter->lumV; + FFMPEG_PTR_STORE(Vector, SwsVectorId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsGetChromaH::body(const Runtime::CallingFrame &Frame, + uint32_t SwsFilterId, + uint32_t SwsVectorPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(SwsVectorId, MemInst, uint32_t, SwsVectorPtr, "") + FFMPEG_PTR_FETCH(Filter, SwsFilterId, SwsFilter); + + SwsVector *Vector = Filter->chrH; + FFMPEG_PTR_STORE(Vector, SwsVectorId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsGetChromaV::body(const Runtime::CallingFrame &Frame, + uint32_t SwsFilterId, + uint32_t SwsVectorPtr) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(SwsVectorId, MemInst, uint32_t, SwsVectorPtr, "") + FFMPEG_PTR_FETCH(Filter, SwsFilterId, SwsFilter); + + SwsVector *Vector = Filter->chrV; + FFMPEG_PTR_STORE(Vector, SwsVectorId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsFreeFilter::body(const Runtime::CallingFrame &, + uint32_t SwsFilterId) { + FFMPEG_PTR_FETCH(Filter, SwsFilterId, SwsFilter); + sws_freeFilter(Filter); + FFMPEG_PTR_DELETE(SwsFilterId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsAllocVec::body(const Runtime::CallingFrame &Frame, + uint32_t SwsVectorPtr, int32_t Length) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(SwsVectorId, MemInst, uint32_t, SwsVectorPtr, "") + + SwsVector *Vector = sws_allocVec(Length); + FFMPEG_PTR_STORE(Vector, SwsVectorId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsGetGaussianVec::body(const Runtime::CallingFrame &Frame, + uint32_t SwsVectorPtr, double Variance, + double Quality) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_PTR_CHECK(SwsVectorId, MemInst, uint32_t, SwsVectorPtr, "") + + SwsVector *Vector = sws_getGaussianVec(Variance, Quality); + FFMPEG_PTR_STORE(Vector, SwsVectorId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsScaleVec::body(const Runtime::CallingFrame &, + uint32_t SwsVectorId, double Scalar) { + FFMPEG_PTR_FETCH(Vector, SwsVectorId, SwsVector); + sws_scaleVec(Vector, Scalar); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsNormalizeVec::body(const Runtime::CallingFrame &, + uint32_t SwsVectorId, double Height) { + FFMPEG_PTR_FETCH(Vector, SwsVectorId, SwsVector); + sws_normalizeVec(Vector, Height); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsGetCoeffVecLength::body(const Runtime::CallingFrame &, + uint32_t SwsVectorId) { + FFMPEG_PTR_FETCH(Vector, SwsVectorId, SwsVector); + return Vector->length * + sizeof(double); // Getting the size in uint_8* (Cuz Passing uint8_t* + // array from Rust SDK). +} + +Expect<int32_t> SwsGetCoeff::body(const Runtime::CallingFrame &Frame, + uint32_t SwsVectorId, uint32_t CoeffBufPtr, + uint32_t Len) { + MEMINST_CHECK(MemInst, Frame, 0) + MEM_SPAN_CHECK(Buffer, MemInst, uint8_t, CoeffBufPtr, Len, ""); + FFMPEG_PTR_FETCH(Vector, SwsVectorId, SwsVector); + + double *Coeff = Vector->coeff; + std::copy_n(Coeff, Len, Buffer.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwsFreeVec::body(const Runtime::CallingFrame &, + uint32_t SwsVectorId) { + FFMPEG_PTR_FETCH(Vector, SwsVectorId, SwsVector); + sws_freeVec(Vector); + FFMPEG_PTR_DELETE(SwsVectorId); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<uint32_t> SwscaleVersion::body(const Runtime::CallingFrame &) { + return swscale_version(); +} + +Expect<int32_t> +SwscaleConfigurationLength::body(const Runtime::CallingFrame &) { + const char *Config = swscale_configuration(); + return strlen(Config); +} + +Expect<int32_t> SwscaleConfiguration::body(const Runtime::CallingFrame &Frame, + uint32_t ConfigPtr, + uint32_t ConfigLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(ConfigBuf, MemInst, char, ConfigPtr, ConfigLen, ""); + + const char *Config = swscale_configuration(); + std::copy_n(Config, ConfigLen, ConfigBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +Expect<int32_t> SwscaleLicenseLength::body(const Runtime::CallingFrame &) { + const char *License = swscale_license(); + return strlen(License); +} + +Expect<int32_t> SwscaleLicense::body(const Runtime::CallingFrame &Frame, + uint32_t LicensePtr, uint32_t LicenseLen) { + MEMINST_CHECK(MemInst, Frame, 0); + MEM_SPAN_CHECK(LicenseBuf, MemInst, char, LicensePtr, LicenseLen, ""); + + const char *License = swscale_license(); + std::copy_n(License, LicenseLen, LicenseBuf.data()); + return static_cast<int32_t>(ErrNo::Success); +} + +} // namespace SWScale +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/swscale/swscale_func.h b/plugins/wasmedge_ffmpeg/swscale/swscale_func.h new file mode 100644 index 000000000000..12edd64387da --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swscale/swscale_func.h @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "ffmpeg_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWScale { + +class SwsGetContext : public HostFunction<SwsGetContext> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t SwsCtxPtr, + uint32_t SrcW, uint32_t SrcH, uint32_t SrcPixFormatId, + uint32_t DesW, uint32_t DesH, uint32_t DesPixFormatId, + int32_t Flags, uint32_t SrcFilterId, + uint32_t DesFilterId); +}; + +class SwsFreeContext : public HostFunction<SwsFreeContext> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t SwsCtxId); +}; + +class SwsScale : public HostFunction<SwsScale> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t SwsCtxId, + uint32_t InputFrameId, int32_t SrcSliceY, + int32_t SrcSliceH, uint32_t OutputFrameId); +}; + +class SwsGetCachedContext : public HostFunction<SwsGetCachedContext> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SwsCachedCtxPtr, uint32_t SwsCtxPtr, + uint32_t SrcW, uint32_t SrcH, uint32_t SrcPixFormatId, + uint32_t DesW, uint32_t DesH, uint32_t DesPixFormatId, + int32_t Flags, uint32_t SrcFilterId, + uint32_t DesFilterId); +}; + +class SwsIsSupportedInput : public HostFunction<SwsIsSupportedInput> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId); +}; + +class SwsIsSupportedOutput : public HostFunction<SwsIsSupportedOutput> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId); +}; + +class SwsIsSupportedEndiannessConversion + : public HostFunction<SwsIsSupportedEndiannessConversion> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId); +}; + +class SwsGetDefaultFilter : public HostFunction<SwsGetDefaultFilter> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SwsFilterPtr, float LumaGBlur, + float ChromaGBlur, float LumaSharpen, + float ChromaSharpen, float ChromaHShift, + float ChromaVShift, int32_t Verbose); +}; + +class SwsGetLumaH : public HostFunction<SwsGetLumaH> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t SwsFilterId, + uint32_t SwsVectorPtr); +}; + +class SwsGetLumaV : public HostFunction<SwsGetLumaV> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t SwsFilterId, + uint32_t SwsVectorPtr); +}; + +class SwsGetChromaH : public HostFunction<SwsGetChromaH> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t SwsFilterId, + uint32_t SwsVectorPtr); +}; + +class SwsGetChromaV : public HostFunction<SwsGetChromaV> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t SwsFilterId, + uint32_t SwsVectorPtr); +}; + +class SwsFreeFilter : public HostFunction<SwsFreeFilter> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SwsFilterId); +}; + +class SwsAllocVec : public HostFunction<SwsAllocVec> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SwsVectorPtr, int32_t Length); +}; + +class SwsGetGaussianVec : public HostFunction<SwsGetGaussianVec> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SwsVectorPtr, double Variance, double Quality); +}; + +class SwsScaleVec : public HostFunction<SwsScaleVec> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t SwsVectorId, + double Scalar); +}; + +class SwsNormalizeVec : public HostFunction<SwsNormalizeVec> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t SwsVectorId, + double Height); +}; + +class SwsGetCoeffVecLength : public HostFunction<SwsGetCoeffVecLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t SwsVectorId); +}; + +class SwsGetCoeff : public HostFunction<SwsGetCoeff> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &, uint32_t SwsVectorId, + uint32_t CoeffBuf, uint32_t Len); +}; + +class SwsFreeVec : public HostFunction<SwsFreeVec> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, + uint32_t SwsVectorId); +}; + +class SwscaleVersion : public HostFunction<SwscaleVersion> { +public: + using HostFunction::HostFunction; + Expect<uint32_t> body(const Runtime::CallingFrame &Frame); +}; + +class SwscaleConfigurationLength + : public HostFunction<SwscaleConfigurationLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class SwscaleConfiguration : public HostFunction<SwscaleConfiguration> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class SwscaleLicenseLength : public HostFunction<SwscaleLicenseLength> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame); +}; + +class SwscaleLicense : public HostFunction<SwscaleLicense> { +public: + using HostFunction::HostFunction; + Expect<int32_t> body(const Runtime::CallingFrame &Frame, uint32_t LicensePtr, + uint32_t LicenseLen); +}; + +} // namespace SWScale +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_image/CMakeLists.txt b/plugins/wasmedge_image/CMakeLists.txt index 01762dbba14a..8360a40de490 100644 --- a/plugins/wasmedge_image/CMakeLists.txt +++ b/plugins/wasmedge_image/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_library(wasmedgePluginWasmEdgeImage SHARED @@ -140,4 +140,7 @@ else() ) endif() -install(TARGETS wasmedgePluginWasmEdgeImage DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge) +install( + TARGETS wasmedgePluginWasmEdgeImage + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) diff --git a/plugins/wasmedge_image/image_base.h b/plugins/wasmedge_image/image_base.h index 733cdf18e585..47f501b2a590 100644 --- a/plugins/wasmedge_image/image_base.h +++ b/plugins/wasmedge_image/image_base.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_image/image_env.cpp b/plugins/wasmedge_image/image_env.cpp index 022787ca2b17..12ab8886668c 100644 --- a/plugins/wasmedge_image/image_env.cpp +++ b/plugins/wasmedge_image/image_env.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "image_env.h" #include "image_module.h" @@ -32,9 +32,8 @@ Plugin::Plugin::PluginDescriptor Descriptor{ .AddOptions = nullptr, }; -} // namespace - -Plugin::PluginRegister WasmEdgeImage::ImgEnv::Register(&Descriptor); +EXPORT_GET_DESCRIPTOR(Descriptor) +} // namespace } // namespace Host } // namespace WasmEdge diff --git a/plugins/wasmedge_image/image_env.h b/plugins/wasmedge_image/image_env.h index 0eea7ba5eb44..837b70864200 100644 --- a/plugins/wasmedge_image/image_env.h +++ b/plugins/wasmedge_image/image_env.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once @@ -23,9 +23,7 @@ enum class DataType : uint32_t { BGR32F = 3, }; -struct ImgEnv { - static Plugin::PluginRegister Register; -}; +struct ImgEnv {}; } // namespace WasmEdgeImage } // namespace Host diff --git a/plugins/wasmedge_image/image_func.cpp b/plugins/wasmedge_image/image_func.cpp index 58d626493257..785a81632340 100644 --- a/plugins/wasmedge_image/image_func.cpp +++ b/plugins/wasmedge_image/image_func.cpp @@ -1,10 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "image_func.h" -#include "common/log.h" #include "common/span.h" +#include "common/spdlog.h" #include <boost/gil.hpp> #include <boost/gil/extension/io/jpeg.hpp> diff --git a/plugins/wasmedge_image/image_func.h b/plugins/wasmedge_image/image_func.h index 099aa1a47cf7..9b18c3d24ec3 100644 --- a/plugins/wasmedge_image/image_func.h +++ b/plugins/wasmedge_image/image_func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_image/image_module.cpp b/plugins/wasmedge_image/image_module.cpp index 89ad74c55ff7..745cbb564884 100644 --- a/plugins/wasmedge_image/image_module.cpp +++ b/plugins/wasmedge_image/image_module.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "image_module.h" #include "image_func.h" diff --git a/plugins/wasmedge_image/image_module.h b/plugins/wasmedge_image/image_module.h index a23b05f083c9..8d4f42b4b784 100644 --- a/plugins/wasmedge_image/image_module.h +++ b/plugins/wasmedge_image/image_module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_llmc/CMakeLists.txt b/plugins/wasmedge_llmc/CMakeLists.txt new file mode 100644 index 000000000000..7e9e4c59d5ff --- /dev/null +++ b/plugins/wasmedge_llmc/CMakeLists.txt @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +wasmedge_add_library(wasmedgePluginWasmEdgeLLMC + SHARED + llmc_func.cpp + llmc_module.cpp + llmc_env.cpp +) + +option(WASMEDGE_PLUGIN_LLMC_CUDA "Training GPT2 with CUDA" OFF) + +message(STATUS "Start fetching llm.c source") +include(FetchContent) + +if (WASMEDGE_PLUGIN_LLMC_CUDA) + set(CUDALIB ON) + message(STATUS "Build wasmedge_llmc with CUDA backend") +else() + message(STATUS "Build wasmedge_llmc with CPU backend") +endif() + +FetchContent_Declare( + llmc + GIT_REPOSITORY https://github.com/WasmEdge/llm.c +) +FetchContent_MakeAvailable(llmc) + +if (WASMEDGE_PLUGIN_LLMC_CUDA) + target_link_libraries(wasmedgePluginWasmEdgeLLMC PRIVATE + train_gpt2_cuda + ) +else() + target_link_libraries(wasmedgePluginWasmEdgeLLMC PRIVATE + train_gpt2_cpu + ) +endif() + +target_compile_options(wasmedgePluginWasmEdgeLLMC + PUBLIC + -DWASMEDGE_PLUGIN +) + +target_include_directories(wasmedgePluginWasmEdgeLLMC + PUBLIC + $<TARGET_PROPERTY:wasmedgePlugin,INCLUDE_DIRECTORIES> + ${CMAKE_CURRENT_SOURCE_DIR} +) + +if(WASMEDGE_LINK_PLUGINS_STATIC) + target_link_libraries(wasmedgePluginWasmEdgeLLMC + PRIVATE + wasmedgeCAPI + ) +else() + target_link_libraries(wasmedgePluginWasmEdgeLLMC + PRIVATE + wasmedge_shared + ) +endif() + +install( + TARGETS wasmedgePluginWasmEdgeLLMC + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) diff --git a/plugins/wasmedge_llmc/llmc_base.h b/plugins/wasmedge_llmc/llmc_base.h new file mode 100644 index 000000000000..6af0d36a6157 --- /dev/null +++ b/plugins/wasmedge_llmc/llmc_base.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "llmc_env.h" + +#include "common/errcode.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeLLMC { + +template <typename T> class HostFunction : public Runtime::HostFunction<T> { +public: + HostFunction(LLMCEnv &E) : Runtime::HostFunction<T>(0), Env(E) {} + +protected: + static constexpr uint32_t castErrNo(ErrNo E) noexcept { + return static_cast<uint32_t>(E); + } + LLMCEnv &Env; +}; + +} // namespace WasmEdgeLLMC +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_llmc/llmc_env.cpp b/plugins/wasmedge_llmc/llmc_env.cpp new file mode 100644 index 000000000000..a960ec168f44 --- /dev/null +++ b/plugins/wasmedge_llmc/llmc_env.cpp @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "llmc_env.h" +#include "llmc_fwd.h" +#include "llmc_module.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeLLMC { + +uint32_t LLMCEnv::addModel(GPT2 *M) noexcept { + Models.push_back(M); + return Models.size() - 1; +} + +GPT2 *LLMCEnv::getModel(uint32_t Id) noexcept { + assert(Id < Models.size() && "Out of bounds"); + return Models[Id]; +} + +uint32_t LLMCEnv::addTokenizer(Tokenizer *T) noexcept { + Tokenizers.push_back(T); + return Tokenizers.size() - 1; +} + +Tokenizer *LLMCEnv::getTokenizer(uint32_t Id) noexcept { + assert(Id < Tokenizers.size() && "Out of bounds"); + return Tokenizers[Id]; +} + +uint32_t LLMCEnv::addDataLoader(DataLoader *D) noexcept { + DataLoaders.push_back(D); + return DataLoaders.size() - 1; +} + +DataLoader *LLMCEnv::getDataLoader(uint32_t Id) noexcept { + assert(Id < DataLoaders.size() && "Out of bounds"); + return DataLoaders[Id]; +} + +LLMCEnv::~LLMCEnv() { + for (GPT2 *M : Models) { + gpt2_destroy(M); + } + for (DataLoader *DL : DataLoaders) { + dataloader_destroy(DL); + } + for (Tokenizer *T : Tokenizers) { + tokenizer_destroy(T); + } +} + +namespace { +Runtime::Instance::ModuleInstance * +create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new WasmEdgeLLMCModule; +} + +static Plugin::PluginModule::ModuleDescriptor MD[] = { + { + /* Name */ "wasmedge_llmc", + /* Description */ "", + /* Create */ create, + }, +}; + +Plugin::Plugin::PluginDescriptor Descriptor{ + /* Name */ "wasmedge_llmc", + /* Description */ "", + /* APIVersion */ Plugin::Plugin::CurrentAPIVersion, + /* Version */ {0, 1, 0, 0}, + /* ModuleCount */ 1, + /* ModuleDescriptions */ MD, + /* ComponentCount */ 0, + /* ComponentDescriptions */ nullptr, + /*AddOptions*/ nullptr, +}; +} // namespace + +EXPORT_GET_DESCRIPTOR(Descriptor) + +} // namespace WasmEdgeLLMC +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_llmc/llmc_env.h b/plugins/wasmedge_llmc/llmc_env.h new file mode 100644 index 000000000000..66b9b8c13eb0 --- /dev/null +++ b/plugins/wasmedge_llmc/llmc_env.h @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "plugin/plugin.h" + +#include <cstdint> +#include <functional> +#include <vector> + +extern "C" { +struct GPT2; +struct Tokenizer; +struct DataLoader; +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeLLMC { + +enum class ErrNo : uint32_t { + Success = 0, + InvalidArgument = 1, + MissingMemory = 2, +}; + +class LLMCEnv { + std::vector<GPT2 *> Models; + std::vector<Tokenizer *> Tokenizers; + std::vector<DataLoader *> DataLoaders; + +public: + uint32_t addModel(GPT2 *M) noexcept; + + GPT2 *getModel(uint32_t Id) noexcept; + + size_t getModelSize() const noexcept { return Models.size(); } + + uint32_t addTokenizer(Tokenizer *T) noexcept; + + Tokenizer *getTokenizer(uint32_t Id) noexcept; + + size_t getTokenizerSize() const noexcept { return Tokenizers.size(); } + + uint32_t addDataLoader(DataLoader *D) noexcept; + + DataLoader *getDataLoader(uint32_t Id) noexcept; + + size_t getDataLoaderSize() const noexcept { return DataLoaders.size(); } + + ~LLMCEnv(); +}; + +} // namespace WasmEdgeLLMC +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_llmc/llmc_func.cpp b/plugins/wasmedge_llmc/llmc_func.cpp new file mode 100644 index 000000000000..b90fba78fe38 --- /dev/null +++ b/plugins/wasmedge_llmc/llmc_func.cpp @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "llmc_func.h" +#include "llmc_fwd.h" + +#include "common/errcode.h" +#include "common/spdlog.h" + +#include <string> +#include <string_view> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeLLMC { + +Expect<ErrNo> ModelCreate::bodyImpl(const Runtime::CallingFrame &Frame, + uint32_t CheckPointPath, + uint32_t CheckPointPathLen, + uint32_t ModelIdPtr) { + auto *MemInst = Frame.getMemoryByIndex(0); + if (MemInst == nullptr) { + spdlog::error("[WasmEdge-LLMC] Memory instance not found."sv); + return ErrNo::MissingMemory; + } + auto CheckPointPathSpan = + MemInst->getSpan<char>(CheckPointPath, CheckPointPathLen); + if (unlikely(CheckPointPathSpan.size() != CheckPointPathLen)) { + spdlog::error( + "[WasmEdge-LLMC] Failed when accessing the input checkpoint path memory."sv); + return ErrNo::MissingMemory; + } + + auto *ModelId = MemInst->getPointer<uint32_t *>(ModelIdPtr); + if (unlikely(ModelId == nullptr)) { + spdlog::error( + "[WasmEdge-LLMC] Failed when accessing the return model memory."sv); + return ErrNo::InvalidArgument; + } + std::string CheckPointPathStr = + std::string(CheckPointPathSpan.begin(), + CheckPointPathSpan.begin() + CheckPointPathSpan.size()); + GPT2 *Model = gpt2_create(CheckPointPathStr.data()); + *ModelId = Env.addModel(Model); + return ErrNo::Success; +} + +Expect<ErrNo> DataLoaderCreate::bodyImpl( + const Runtime::CallingFrame &Frame, uint32_t DataPath, uint32_t DataPathLen, + uint32_t B, uint32_t T, uint32_t ProcessRank, uint32_t NumProcesses, + int32_t ShouldShuffle, uint32_t DataLoaderIdPtr) { + auto *MemInst = Frame.getMemoryByIndex(0); + if (MemInst == nullptr) { + spdlog::error("[WasmEdge-LLMC] Memory instance not found."sv); + return ErrNo::MissingMemory; + } + auto DataPathSpan = MemInst->getSpan<char>(DataPath, DataPathLen); + if (unlikely(DataPathSpan.size() != DataPathLen)) { + spdlog::error( + "[WasmEdge-LLMC] Failed when accessing the input dataloader path memory."sv); + return ErrNo::MissingMemory; + } + + auto *DataLoaderId = MemInst->getPointer<uint32_t *>(DataLoaderIdPtr); + if (unlikely(DataLoaderId == nullptr)) { + spdlog::error( + "[WasmEdge-LLMC] Failed when accessing the return dataloader memory."sv); + return ErrNo::InvalidArgument; + } + + std::string DataPathStr = std::string( + DataPathSpan.begin(), DataPathSpan.begin() + DataPathSpan.size()); + DataLoader *D = dataloader_create(DataPathStr.data(), B, T, ProcessRank, + NumProcesses, ShouldShuffle); + *DataLoaderId = Env.addDataLoader(D); + return ErrNo::Success; +} + +Expect<ErrNo> TokenizerCreate::bodyImpl(const Runtime::CallingFrame &Frame, + uint32_t FilePath, uint32_t FilePathLen, + uint32_t TokenizerIdPtr) { + auto *MemInst = Frame.getMemoryByIndex(0); + if (MemInst == nullptr) { + spdlog::error("[WasmEdge-LLMC] Memory instance not found."sv); + return ErrNo::MissingMemory; + } + auto FilePathSpan = MemInst->getSpan<char>(FilePath, FilePathLen); + if (unlikely(FilePathSpan.size() != FilePathLen)) { + spdlog::error( + "[WasmEdge-LLMC] Failed when accessing the input tokenizer path memory."sv); + return ErrNo::MissingMemory; + } + + auto *TokenizerId = MemInst->getPointer<uint32_t *>(TokenizerIdPtr); + if (unlikely(TokenizerId == nullptr)) { + spdlog::error( + "[WasmEdge-LLMC] Failed when accessing the return tokenizer memory."sv); + return ErrNo::InvalidArgument; + } + std::string FilePathStr = std::string( + FilePathSpan.begin(), FilePathSpan.begin() + FilePathSpan.size()); + Tokenizer *T = tokenizer_create(FilePathStr.data()); + *TokenizerId = Env.addTokenizer(T); + return ErrNo::Success; +} + +Expect<ErrNo> ModelTrain::bodyImpl(const Runtime::CallingFrame &Frame, + uint32_t ModelId, uint32_t TrainDataLoaderId, + uint32_t ValDataLoaderId, + uint32_t TokenizerId, uint32_t B, uint32_t T, + float Lr, uint32_t Epoch) { + auto *MemInst = Frame.getMemoryByIndex(0); + if (MemInst == nullptr) { + spdlog::error("[WasmEdge-LLMC] Memory instance not found."sv); + return ErrNo::MissingMemory; + } + GPT2 *Model = Env.getModel(ModelId); + DataLoader *TrainDataLoader = Env.getDataLoader(TrainDataLoaderId); + DataLoader *ValDataLoader = Env.getDataLoader(ValDataLoaderId); + Tokenizer *Tokenizer = Env.getTokenizer(TokenizerId); + gpt2_train(Model, TrainDataLoader, ValDataLoader, Tokenizer, B, T, Lr, Epoch); + return ErrNo::Success; +} + +} // namespace WasmEdgeLLMC +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_llmc/llmc_func.h b/plugins/wasmedge_llmc/llmc_func.h new file mode 100644 index 000000000000..4bae88fb0b6c --- /dev/null +++ b/plugins/wasmedge_llmc/llmc_func.h @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "llmc_base.h" +#include "llmc_env.h" + +#include "runtime/callingframe.h" + +#include <cstdint> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeLLMC { + +class ModelCreate : public HostFunction<ModelCreate> { +public: + explicit ModelCreate(LLMCEnv &Env) : HostFunction(Env) {} + + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, + uint32_t CheckPointPath, uint32_t CheckPointPathLen, + uint32_t ModelIdPtr) { + return bodyImpl(Frame, CheckPointPath, CheckPointPathLen, ModelIdPtr) + .map(castErrNo); + } + +private: + Expect<ErrNo> bodyImpl(const Runtime::CallingFrame &Frame, + uint32_t CheckPointPath, uint32_t CheckPointPathLen, + uint32_t ModelIdPtr); +}; + +class DataLoaderCreate : public HostFunction<DataLoaderCreate> { +public: + explicit DataLoaderCreate(LLMCEnv &Env) : HostFunction(Env) {} + + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, uint32_t DataPath, + uint32_t DataPathLen, uint32_t B, uint32_t T, + uint32_t ProcessRank, uint32_t NumProcesses, + int32_t ShouldShuffle, uint32_t DataLoaderIdPtr) { + return bodyImpl(Frame, DataPath, DataPathLen, B, T, ProcessRank, + NumProcesses, ShouldShuffle, DataLoaderIdPtr) + .map(castErrNo); + } + +private: + Expect<ErrNo> bodyImpl(const Runtime::CallingFrame &Frame, uint32_t DataPath, + uint32_t DataPathLen, uint32_t B, uint32_t T, + uint32_t ProcessRank, uint32_t NumProcesses, + int32_t ShouldShuffle, uint32_t DataLoaderIdPtr); +}; + +class TokenizerCreate : public HostFunction<TokenizerCreate> { +public: + explicit TokenizerCreate(LLMCEnv &Env) : HostFunction(Env) {} + + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, uint32_t FilePath, + uint32_t FilePathLen, uint32_t TokenizerIdPtr) { + return bodyImpl(Frame, FilePath, FilePathLen, TokenizerIdPtr) + .map(castErrNo); + } + +private: + Expect<ErrNo> bodyImpl(const Runtime::CallingFrame &Frame, uint32_t FilePath, + uint32_t FilePathLen, uint32_t TokenizerIdPtr); +}; + +class ModelTrain : public HostFunction<ModelTrain> { +public: + explicit ModelTrain(LLMCEnv &Env) : HostFunction(Env) {} + + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, uint32_t ModelId, + uint32_t TrainDataLoaderId, uint32_t ValDataLoaderId, + uint32_t TokenizerId, uint32_t B, uint32_t T, float Lr, + uint32_t Epoch) { + return bodyImpl(Frame, ModelId, TrainDataLoaderId, ValDataLoaderId, + TokenizerId, B, T, Lr, Epoch) + .map(castErrNo); + } + +private: + Expect<ErrNo> bodyImpl(const Runtime::CallingFrame &Frame, uint32_t ModelId, + uint32_t TrainDataLoaderId, uint32_t ValDataLoaderId, + uint32_t TokenizerId, uint32_t B, uint32_t T, float Lr, + uint32_t Epoch); +}; + +} // namespace WasmEdgeLLMC +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_llmc/llmc_fwd.h b/plugins/wasmedge_llmc/llmc_fwd.h new file mode 100644 index 000000000000..afa39f10e8d9 --- /dev/null +++ b/plugins/wasmedge_llmc/llmc_fwd.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "llmc_env.h" + +extern "C" { + +struct GPT2; +struct Tokenizer; +struct DataLoader; + +GPT2 *gpt2_create(const char *checkpoint_path); + +void gpt2_destroy(GPT2 *model); + +DataLoader *dataloader_create(const char *filename_pattern, size_t B, size_t T, + int process_rank, int num_processes, + int should_shuffle); +void dataloader_destroy(DataLoader *loader); + +Tokenizer *tokenizer_create(const char *filename); + +void tokenizer_destroy(Tokenizer *tokenizer); + +void gpt2_train(GPT2 *model, DataLoader *train_loader, DataLoader *val_loader, + Tokenizer *tokenizer, int B, int T, float lr, int epoch); +} diff --git a/plugins/wasmedge_llmc/llmc_module.cpp b/plugins/wasmedge_llmc/llmc_module.cpp new file mode 100644 index 000000000000..8914eb039b50 --- /dev/null +++ b/plugins/wasmedge_llmc/llmc_module.cpp @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "llmc_module.h" +#include "llmc_func.h" + +namespace WasmEdge { +namespace Host { + +WasmEdgeLLMCModule::WasmEdgeLLMCModule() : ModuleInstance("wasmedge_llmc") { + addHostFunc("model_create", std::make_unique<WasmEdgeLLMC::ModelCreate>(Env)); + addHostFunc("dataloader_create", + std::make_unique<WasmEdgeLLMC::DataLoaderCreate>(Env)); + addHostFunc("tokenizer_create", + std::make_unique<WasmEdgeLLMC::TokenizerCreate>(Env)); + addHostFunc("model_train", std::make_unique<WasmEdgeLLMC::ModelTrain>(Env)); +} + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_llmc/llmc_module.h b/plugins/wasmedge_llmc/llmc_module.h new file mode 100644 index 000000000000..86a923c3af75 --- /dev/null +++ b/plugins/wasmedge_llmc/llmc_module.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "llmc_env.h" + +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { + +class WasmEdgeLLMCModule : public Runtime::Instance::ModuleInstance { +public: + WasmEdgeLLMCModule(); + +private: + WasmEdgeLLMC::LLMCEnv Env; +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ocr/CMakeLists.txt b/plugins/wasmedge_ocr/CMakeLists.txt new file mode 100644 index 000000000000..e3139149b155 --- /dev/null +++ b/plugins/wasmedge_ocr/CMakeLists.txt @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +add_library(wasmedgePluginWasmEdgeOCR + SHARED + ocr_env.cpp + ocr_func.cpp + ocr_module.cpp +) + +target_compile_options(wasmedgePluginWasmEdgeOCR + PUBLIC + -DWASMEDGE_PLUGIN +) + +target_include_directories(wasmedgePluginWasmEdgeOCR + PUBLIC + $<TARGET_PROPERTY:wasmedgePlugin,INCLUDE_DIRECTORIES> + ${CMAKE_CURRENT_SOURCE_DIR} +) + +if(WASMEDGE_LINK_PLUGINS_STATIC) + target_link_libraries(wasmedgePluginWasmEdgeOCR + PRIVATE + wasmedgeCAPI + ) +else() + target_link_libraries(wasmedgePluginWasmEdgeOCR + PRIVATE + wasmedge_shared + ) +endif() + +install( + TARGETS wasmedgePluginWasmEdgeOCR + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) + +message(STATUS "WASI-OCR: Build Tesseract backend for WASI-OCR") +find_package(PkgConfig REQUIRED) +pkg_search_module(TESSERACT REQUIRED tesseract) +pkg_search_module(LEPTONICA REQUIRED lept) + +target_include_directories(wasmedgePluginWasmEdgeOCR + PUBLIC + ${TESSERACT_INCLUDE_DIRS} + ${LEPTONICA_INCLUDE_DIRS} +) + +target_link_libraries(wasmedgePluginWasmEdgeOCR + PUBLIC + ${TESSERACT_LIBRARIES} + ${LEPTONICA_LIBRARIES} +) diff --git a/plugins/wasmedge_ocr/ocr_base.h b/plugins/wasmedge_ocr/ocr_base.h new file mode 100644 index 000000000000..dc525dd25019 --- /dev/null +++ b/plugins/wasmedge_ocr/ocr_base.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#pragma once + +#include "ocr_env.h" + +#include "common/errcode.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeOCR { + +template <typename T> class HostFunction : public Runtime::HostFunction<T> { +public: + HostFunction(OCREnv &HostEnv) : Runtime::HostFunction<T>(0), Env(HostEnv) {} + +protected: + OCREnv &Env; +}; + +} // namespace WasmEdgeOCR +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ocr/ocr_env.cpp b/plugins/wasmedge_ocr/ocr_env.cpp new file mode 100644 index 000000000000..111b5136547a --- /dev/null +++ b/plugins/wasmedge_ocr/ocr_env.cpp @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#include "ocr_env.h" +#include "ocr_module.h" + +namespace WasmEdge { +namespace Host { +namespace { + +Runtime::Instance::ModuleInstance * +create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new WasmEdgeOCRModule; +} + +Plugin::Plugin::PluginDescriptor Descriptor{ + .Name = "wasmedge_ocr", + .Description = "A WasmEdge Plugin for Optical Character Recognition (OCR) " + "powered by the Tesseract API.", + .APIVersion = Plugin::Plugin::CurrentAPIVersion, + .Version = {0, 10, 1, 0}, + .ModuleCount = 1, + .ModuleDescriptions = + (Plugin::PluginModule::ModuleDescriptor[]){ + { + .Name = "wasmedge_ocr", + .Description = + "A WasmEdge Plugin for Optical Character Recognition (OCR) " + "powered by the Tesseract API.", + .Create = create, + }, + }, + .AddOptions = nullptr, +}; + +EXPORT_GET_DESCRIPTOR(Descriptor) + +} // namespace +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ocr/ocr_env.h b/plugins/wasmedge_ocr/ocr_env.h new file mode 100644 index 000000000000..e4a0ddf4ae7d --- /dev/null +++ b/plugins/wasmedge_ocr/ocr_env.h @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#pragma once + +#include "common/spdlog.h" +#include "plugin/plugin.h" + +#include <leptonica/allheaders.h> +#include <tesseract/baseapi.h> + +#include <cstdint> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeOCR { + +enum class ErrNo : uint32_t { + Success = 0, // No error occurred. + InvalidArgument = 1, // Caller module passed an invalid argument. + MissingMemory = 2, // Caller module is missing a memory export. + Busy = 3 // Device or resource busy. +}; + +class OCREnv { +public: + OCREnv() noexcept { + // check Tesseract API by initializing tesseract-ocr with English, without + // specifying tessdata path + if (TesseractApi->Init(NULL, "eng")) { + spdlog::error( + "[WasmEdge-OCR] Error occurred when initializing tesseract."); + } + } + ~OCREnv() noexcept { + if (TesseractApi) { + TesseractApi->End(); + ; + } + } + tesseract::TessBaseAPI *TesseractApi = new tesseract::TessBaseAPI(); + + static Plugin::PluginRegister Register; +}; + +} // namespace WasmEdgeOCR +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ocr/ocr_func.cpp b/plugins/wasmedge_ocr/ocr_func.cpp new file mode 100644 index 000000000000..e75ef40fdb3b --- /dev/null +++ b/plugins/wasmedge_ocr/ocr_func.cpp @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#include "ocr_func.h" + +#include "common/spdlog.h" + +#include <algorithm> +#include <string> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeOCR { + +Expect<uint32_t> NumOfExtractions::body(const Runtime::CallingFrame &Frame, + uint32_t ImagePathPtr, + uint32_t ImagePathLen) { + // Check memory instance from module. + auto *MemInst = Frame.getMemoryByIndex(0); + if (MemInst == nullptr) { + return Unexpect(ErrCode::Value::HostFuncError); + } + auto ImagePtr = MemInst->getSpan<char>(ImagePathPtr, ImagePathLen); + if (unlikely(ImagePtr.size() != ImagePathLen)) { + return Unexpect(ErrCode::Value::HostFuncError); + } + Pix *image = pixRead(ImagePtr.data()); + + Env.TesseractApi->SetImage(image); + Env.TesseractApi->Recognize(0); + + tesseract::PageIteratorLevel level = tesseract::RIL_WORD; + const char *outText = Env.TesseractApi->GetTSVText(level); + + uint32_t length = strlen(outText); + pixDestroy(&image); + return static_cast<uint32_t>(length); +} + +Expect<uint32_t> GetOutput::body(const Runtime::CallingFrame &Frame, + uint32_t OutBufferPtr [[maybe_unused]], + uint32_t OutBufferMaxSize [[maybe_unused]]) { + // Check memory instance from module. + auto *MemInst = Frame.getMemoryByIndex(0); + if (MemInst == nullptr) { + return Unexpect(ErrCode::Value::HostFuncError); + } + + // Check the return value: OutBufferPtr should be valid. + auto Buf = MemInst->getSpan<char>(OutBufferPtr, OutBufferMaxSize); + if (unlikely(Buf.empty())) { + spdlog::error( + "[WasmEdge-OCR] Failed when accessing the return OutBufferPtr memory."); + return static_cast<uint32_t>(ErrNo::InvalidArgument); + } + + tesseract::PageIteratorLevel level = tesseract::RIL_WORD; + std::unique_ptr<const char[]> outText = Env.TesseractApi->GetTSVText(level); + std::copy_n(outText, std::min<size_t>(std::strlen(outText.get()), Buf.size()), + Buf.begin()); + + // remaining free and deltee memory stuff + Env.TesseractApi->End(); + + return static_cast<uint32_t>(ErrNo::Success); + // return outText; +} + +} // namespace WasmEdgeOCR +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ocr/ocr_func.h b/plugins/wasmedge_ocr/ocr_func.h new file mode 100644 index 000000000000..b00f191d35a8 --- /dev/null +++ b/plugins/wasmedge_ocr/ocr_func.h @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#pragma once + +#include "ocr_base.h" + +#include "runtime/callingframe.h" + +#include <cstdint> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeOCR { + +class NumOfExtractions : public HostFunction<NumOfExtractions> { +public: + NumOfExtractions(OCREnv &HostEnv) : HostFunction(HostEnv) {} + Expect<uint32_t> body(const Runtime::CallingFrame &, uint32_t ImagePathPtr, + uint32_t ImagePathLen); +}; + +class GetOutput : public HostFunction<GetOutput> { +public: + GetOutput(OCREnv &HostEnv) : HostFunction(HostEnv) {} + Expect<uint32_t> body(const Runtime::CallingFrame &, uint32_t OutBufferPtr, + uint32_t OutBufferMaxSize); +}; + +} // namespace WasmEdgeOCR +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ocr/ocr_module.cpp b/plugins/wasmedge_ocr/ocr_module.cpp new file mode 100644 index 000000000000..667c69c18c38 --- /dev/null +++ b/plugins/wasmedge_ocr/ocr_module.cpp @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#include "ocr_module.h" +#include "ocr_func.h" + +namespace WasmEdge { +namespace Host { + +WasmEdgeOCRModule::WasmEdgeOCRModule() : ModuleInstance("wasmedge_ocr") { + addHostFunc("num_of_extractions", + std::make_unique<WasmEdgeOCR::NumOfExtractions>(Env)); + addHostFunc("get_output", std::make_unique<WasmEdgeOCR::GetOutput>(Env)); +} + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ocr/ocr_module.h b/plugins/wasmedge_ocr/ocr_module.h new file mode 100644 index 000000000000..4f2b64c15141 --- /dev/null +++ b/plugins/wasmedge_ocr/ocr_module.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#pragma once + +#include "ocr_env.h" + +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { + +class WasmEdgeOCRModule : public Runtime::Instance::ModuleInstance { +public: + WasmEdgeOCRModule(); + + WasmEdgeOCR::OCREnv &getEnv() { return Env; } + +private: + WasmEdgeOCR::OCREnv Env; +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_opencvmini/CMakeLists.txt b/plugins/wasmedge_opencvmini/CMakeLists.txt index 6949132d7669..eaec200919a8 100644 --- a/plugins/wasmedge_opencvmini/CMakeLists.txt +++ b/plugins/wasmedge_opencvmini/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2023 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC find_package(OpenCV 4 REQUIRED) @@ -36,4 +36,7 @@ else() ) endif() -install(TARGETS wasmedgePluginWasmEdgeOpenCVMini DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge) +install( + TARGETS wasmedgePluginWasmEdgeOpenCVMini + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) diff --git a/plugins/wasmedge_opencvmini/opencvmini_base.h b/plugins/wasmedge_opencvmini/opencvmini_base.h index 1a4dba74ccb1..c9bc9d64f3bb 100644 --- a/plugins/wasmedge_opencvmini/opencvmini_base.h +++ b/plugins/wasmedge_opencvmini/opencvmini_base.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_opencvmini/opencvmini_env.cpp b/plugins/wasmedge_opencvmini/opencvmini_env.cpp index c205d7f4c8f5..499c69e0b313 100644 --- a/plugins/wasmedge_opencvmini/opencvmini_env.cpp +++ b/plugins/wasmedge_opencvmini/opencvmini_env.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "opencvmini_env.h" #include "opencvmini_module.h" @@ -33,9 +33,8 @@ Plugin::Plugin::PluginDescriptor Descriptor{ .AddOptions = nullptr, }; -} // namespace - -Plugin::PluginRegister WasmEdgeOpenCVMiniEnvironment::Register(&Descriptor); +EXPORT_GET_DESCRIPTOR(Descriptor) +} // namespace } // namespace Host } // namespace WasmEdge diff --git a/plugins/wasmedge_opencvmini/opencvmini_env.h b/plugins/wasmedge_opencvmini/opencvmini_env.h index 9ab004ea2ab1..98c8b7855659 100644 --- a/plugins/wasmedge_opencvmini/opencvmini_env.h +++ b/plugins/wasmedge_opencvmini/opencvmini_env.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once @@ -16,8 +16,6 @@ class WasmEdgeOpenCVMiniEnvironment { public: WasmEdgeOpenCVMiniEnvironment() noexcept; - static Plugin::PluginRegister Register; - std::map<uint32_t, cv::Mat> MatPool; Expect<cv::Mat> getMat(uint32_t MatKey) { diff --git a/plugins/wasmedge_opencvmini/opencvmini_func.cpp b/plugins/wasmedge_opencvmini/opencvmini_func.cpp index 7173a0edc6d2..112d2a08f6d4 100644 --- a/plugins/wasmedge_opencvmini/opencvmini_func.cpp +++ b/plugins/wasmedge_opencvmini/opencvmini_func.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "opencvmini_func.h" #include "common/defines.h" diff --git a/plugins/wasmedge_opencvmini/opencvmini_func.h b/plugins/wasmedge_opencvmini/opencvmini_func.h index 80953b7fe387..e2c80d763e42 100644 --- a/plugins/wasmedge_opencvmini/opencvmini_func.h +++ b/plugins/wasmedge_opencvmini/opencvmini_func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_opencvmini/opencvmini_module.cpp b/plugins/wasmedge_opencvmini/opencvmini_module.cpp index 5aac89dbeca4..b4c60ed545a8 100644 --- a/plugins/wasmedge_opencvmini/opencvmini_module.cpp +++ b/plugins/wasmedge_opencvmini/opencvmini_module.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "opencvmini_module.h" #include "opencvmini_func.h" diff --git a/plugins/wasmedge_opencvmini/opencvmini_module.h b/plugins/wasmedge_opencvmini/opencvmini_module.h index 0175110dd54e..3d9296a2110c 100644 --- a/plugins/wasmedge_opencvmini/opencvmini_module.h +++ b/plugins/wasmedge_opencvmini/opencvmini_module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2023 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_process/CMakeLists.txt b/plugins/wasmedge_process/CMakeLists.txt index 0355b9058bf0..819a64d76eaf 100644 --- a/plugins/wasmedge_process/CMakeLists.txt +++ b/plugins/wasmedge_process/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_library(wasmedgePluginWasmEdgeProcess SHARED @@ -31,4 +31,7 @@ else() ) endif() -install(TARGETS wasmedgePluginWasmEdgeProcess DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge) +install( + TARGETS wasmedgePluginWasmEdgeProcess + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) diff --git a/plugins/wasmedge_process/processbase.h b/plugins/wasmedge_process/processbase.h index 12c393571247..f7d9fe6e91f8 100644 --- a/plugins/wasmedge_process/processbase.h +++ b/plugins/wasmedge_process/processbase.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_process/processenv.cpp b/plugins/wasmedge_process/processenv.cpp index 8c769a336426..774989d62464 100644 --- a/plugins/wasmedge_process/processenv.cpp +++ b/plugins/wasmedge_process/processenv.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "processenv.h" #include "processmodule.h" @@ -56,9 +56,8 @@ Plugin::Plugin::PluginDescriptor Descriptor{ .AddOptions = addOptions, }; -} // namespace - -Plugin::PluginRegister WasmEdgeProcessEnvironment::Register(&Descriptor); +EXPORT_GET_DESCRIPTOR(Descriptor) +} // namespace } // namespace Host } // namespace WasmEdge diff --git a/plugins/wasmedge_process/processenv.h b/plugins/wasmedge_process/processenv.h index f1b4ddbc4ecb..9b3626dd5cb8 100644 --- a/plugins/wasmedge_process/processenv.h +++ b/plugins/wasmedge_process/processenv.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once @@ -46,7 +46,6 @@ class WasmEdgeProcessEnvironment { static PO::List<std::string> AllowCmd; static PO::Option<PO::Toggle> AllowCmdAll; - static Plugin::PluginRegister Register; }; } // namespace Host diff --git a/plugins/wasmedge_process/processfunc.cpp b/plugins/wasmedge_process/processfunc.cpp index fe4e85b7625f..ded6e971ce9f 100644 --- a/plugins/wasmedge_process/processfunc.cpp +++ b/plugins/wasmedge_process/processfunc.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "processfunc.h" diff --git a/plugins/wasmedge_process/processfunc.h b/plugins/wasmedge_process/processfunc.h index f23a4c416d99..9746d4332c7a 100644 --- a/plugins/wasmedge_process/processfunc.h +++ b/plugins/wasmedge_process/processfunc.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_process/processmodule.cpp b/plugins/wasmedge_process/processmodule.cpp index 163a1cf25652..613be81d6dd3 100644 --- a/plugins/wasmedge_process/processmodule.cpp +++ b/plugins/wasmedge_process/processmodule.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "processmodule.h" #include "processfunc.h" diff --git a/plugins/wasmedge_process/processmodule.h b/plugins/wasmedge_process/processmodule.h index 0a8e5bac7a33..6482ee6860d0 100644 --- a/plugins/wasmedge_process/processmodule.h +++ b/plugins/wasmedge_process/processmodule.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_rustls/CMakeLists.txt b/plugins/wasmedge_rustls/CMakeLists.txt deleted file mode 100644 index 56069740f2ea..000000000000 --- a/plugins/wasmedge_rustls/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set(CARGO_CMD cargo build) - set(TARGET_DIR "debug") -else() - set(CARGO_CMD cargo build --release) - set(TARGET_DIR "release") -endif() - -set(RS_SO ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_DIR}/libwasmedge_rustls${CMAKE_SHARED_LIBRARY_SUFFIX}) - -set(WASMEDGE_LIB_DIR ${CMAKE_CURRENT_BINARY_DIR}/../../lib/api) - -add_custom_target(wasmedge_rustls ALL - COMMAND WASMEDGE_LIB_DIR=${WASMEDGE_LIB_DIR} LD_LIBARAY_PATH=${WASMEDGE_LIB_DIR} CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR} ${CARGO_CMD} - COMMAND cp ${RS_SO} ${CMAKE_CURRENT_BINARY_DIR} - COMMAND rm -rf ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_DIR} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS wasmedge_shared -) diff --git a/plugins/wasmedge_rustls/Cargo.toml b/plugins/wasmedge_rustls/Cargo.toml deleted file mode 100644 index 1e97c526d1d2..000000000000 --- a/plugins/wasmedge_rustls/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "wasmedge_rustls_plugin" -version = "0.2.0" -edition = "2021" - -[lib] -name = "wasmedge_rustls" -path = "src/lib.rs" -crate-type = ["cdylib"] - -[dependencies] -libc = "0.2" -rustls = "0.20" -bytes = "1" -webpki-roots = "0.22" -wasmedge_plugin_sdk = "0.2.0" -log = "0.4" -thiserror = "1" diff --git a/plugins/wasmedge_rustls/src/lib.rs b/plugins/wasmedge_rustls/src/lib.rs deleted file mode 100644 index d32e84c21b52..000000000000 --- a/plugins/wasmedge_rustls/src/lib.rs +++ /dev/null @@ -1,703 +0,0 @@ -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum TlsError { - #[error("{0}")] - Tls(#[from] rustls::Error), - #[error("{0}")] - IO(#[from] std::io::Error), - #[error("ParamError")] - ParamError, -} - -impl TlsError { - pub fn error_code(&self) -> i32 { - match self { - TlsError::ParamError => -1, - TlsError::Tls(tls_err) => match tls_err { - rustls::Error::InappropriateMessage { .. } => -2, - rustls::Error::InappropriateHandshakeMessage { .. } => -3, - rustls::Error::CorruptMessage => -4, - rustls::Error::CorruptMessagePayload(_) => -5, - rustls::Error::NoCertificatesPresented => -6, - rustls::Error::UnsupportedNameType => -7, - rustls::Error::DecryptError => -8, - rustls::Error::EncryptError => -9, - rustls::Error::PeerIncompatibleError(_) => -10, - rustls::Error::PeerMisbehavedError(_) => -11, - rustls::Error::AlertReceived(_) => -12, - rustls::Error::InvalidCertificateEncoding => -13, - rustls::Error::InvalidCertificateSignatureType => -14, - rustls::Error::InvalidCertificateSignature => -15, - rustls::Error::InvalidCertificateData(_) => -16, - rustls::Error::InvalidSct(_) => -17, - rustls::Error::General(_) => -18, - rustls::Error::FailedToGetCurrentTime => -19, - rustls::Error::FailedToGetRandomBytes => -20, - rustls::Error::HandshakeNotComplete => -21, - rustls::Error::PeerSentOversizedRecord => -22, - rustls::Error::NoApplicationProtocol => -23, - rustls::Error::BadMaxFragmentSize => -24, - }, - TlsError::IO(io_err) if io_err.kind() == std::io::ErrorKind::WouldBlock => -25, - TlsError::IO(_) => -26, - } - } -} - -#[repr(C)] -pub struct TlsIoState { - tls_bytes_to_write: u32, - plaintext_bytes_to_read: u32, - peer_has_closed: bool, -} - -impl From<rustls::IoState> for TlsIoState { - fn from(value: rustls::IoState) -> Self { - TlsIoState { - tls_bytes_to_write: value.tls_bytes_to_write() as u32, - plaintext_bytes_to_read: value.plaintext_bytes_to_read() as u32, - peer_has_closed: value.peer_has_closed(), - } - } -} - -mod tls_client { - use std::{ - io::{Read, Write}, - sync::Arc, - }; - - use bytes::{Buf, BufMut}; - use rustls::{OwnedTrustAnchor, RootCertStore}; - - use crate::TlsError; - use crate::TlsIoState; - - pub struct Ctx { - pub client_configs: Vec<Option<Arc<rustls::ClientConfig>>>, - pub client_codec: Vec<Option<ClientCodec>>, - } - - impl Ctx { - pub fn new() -> Ctx { - let mut root_store = RootCertStore::empty(); - root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map( - |ta| { - OwnedTrustAnchor::from_subject_spki_name_constraints( - ta.subject, - ta.spki, - ta.name_constraints, - ) - }, - )); - let config = rustls::ClientConfig::builder() - .with_safe_defaults() - .with_root_certificates(root_store) - .with_no_client_auth(); - - Ctx { - client_configs: vec![Some(Arc::new(config))], - client_codec: Vec::with_capacity(1024), - } - } - - pub fn default_client_config(&mut self) -> usize { - 0 - } - - pub fn new_codec( - &mut self, - server_name: &str, - config_id: usize, - ) -> Result<usize, TlsError> { - let config = self - .client_configs - .get(config_id) - .ok_or(TlsError::ParamError)? - .clone() - .ok_or(TlsError::ParamError)?; - - let name = server_name.try_into().map_err(|_| TlsError::ParamError)?; - let new_codec = rustls::ClientConnection::new(config, name)?; - let new_codec = ClientCodec(new_codec); - - if let Some((id, item)) = self - .client_codec - .iter_mut() - .enumerate() - .find(|(_, item)| item.is_none()) - { - debug_assert!(item.is_none()); - let _ = item.insert(new_codec); - Ok(id) - } else { - let id = self.client_codec.len(); - self.client_codec.push(Some(new_codec)); - Ok(id) - } - } - - pub fn delete_codec(&mut self, codec_id: usize) { - if let Some(codec) = self.client_codec.get_mut(codec_id) { - let _ = codec.take(); - } - } - } - - #[derive(Debug)] - pub struct ClientCodec(pub rustls::ClientConnection); - - impl ClientCodec { - pub fn is_handshaking(&self) -> bool { - self.0.is_handshaking() - } - - pub fn process_new_packets(&mut self) -> Result<TlsIoState, TlsError> { - Ok(self.0.process_new_packets()?.into()) - } - - pub fn send_close_notify(&mut self) { - self.0.send_close_notify(); - } - - pub fn write_raw(&mut self, raw_buf: &[u8]) -> Result<usize, TlsError> { - let conn = &mut self.0; - Ok(conn.writer().write(raw_buf)?) - } - - pub fn write_tls(&mut self, tls_buf: &mut [u8]) -> Result<usize, TlsError> { - let conn = &mut self.0; - Ok(conn.write_tls(&mut tls_buf.writer())?) - } - - pub fn read_raw(&mut self, raw_buf: &mut [u8]) -> Result<usize, TlsError> { - let conn = &mut self.0; - Ok(conn.reader().read(raw_buf)?) - } - - pub fn read_tls(&mut self, tls_buf: &[u8]) -> Result<usize, TlsError> { - let conn = &mut self.0; - Ok(conn.read_tls(&mut tls_buf.reader())?) - } - } - - #[cfg(test)] - mod tls_client_test { - use super::*; - #[test] - fn test_ctx() { - let mut ctx = Ctx::new(); - let config_id = ctx.default_client_config(); - assert_eq!(config_id, 0); - - let codec_id_0 = ctx.new_codec("httpbin.org", config_id).unwrap(); - assert_eq!(codec_id_0, 0); - let codec_id_1 = ctx.new_codec("httpbin.org", config_id).unwrap(); - assert_eq!(codec_id_1, 1); - ctx.delete_codec(codec_id_0); - println!("{:?}", ctx.client_codec); - let codec_id_0 = ctx.new_codec("httpbin.org", config_id).unwrap(); - assert_eq!(codec_id_0, 0); - } - } -} - -mod wasmedge_client_plugin { - - use wasmedge_plugin_sdk::{ - error::CoreError, - memory::Memory, - module::{PluginModule, SyncInstanceRef}, - types::{ValType, WasmVal}, - }; - - use crate::{tls_client::*, TlsError}; - - macro_rules! match_value { - ($expression:expr, $t:path, $error:expr) => { - match $expression { - $t(v) => v, - _ => return Err($error), - } - }; - } - - fn default_config( - _inst: &mut SyncInstanceRef, - _memory: &mut Memory, - ctx: &mut Ctx, - _args: Vec<WasmVal>, - ) -> Result<Vec<WasmVal>, CoreError> { - let config_id = ctx.default_client_config(); - Ok(vec![WasmVal::I32(config_id as i32)]) - } - - fn new_client_codec( - _inst: &mut SyncInstanceRef, - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<Vec<WasmVal>, CoreError> { - #[inline] - fn new_client_codec_inner( - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<WasmVal, TlsError> { - let config_id = args[0].clone(); - let server_ptr = args[1].clone(); - let server_len = args[2].clone(); - - if let (WasmVal::I32(config_id), WasmVal::I32(server_ptr), WasmVal::I32(server_len)) = - (config_id, server_ptr, server_len) - { - let server_name = memory.data_pointer(server_ptr as usize, server_len as usize); - let server_name = server_name - .and_then(|bs| std::str::from_utf8(bs).ok()) - .ok_or(TlsError::ParamError)?; - let r = ctx.new_codec(server_name, config_id as usize)?; - Ok(WasmVal::I32(r as i32)) - } else { - Err(TlsError::ParamError) - } - } - match new_client_codec_inner(memory, ctx, args) { - Ok(ok) => Ok(vec![ok]), - Err(e) => Ok(vec![WasmVal::I32(e.error_code())]), - } - } - - fn is_handshaking( - _inst: &mut SyncInstanceRef, - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<Vec<WasmVal>, CoreError> { - #[inline] - fn is_handshaking_inner( - _memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<WasmVal, TlsError> { - let codec_id = match_value!(args[0].clone(), WasmVal::I32, TlsError::ParamError); - let codec = ctx - .client_codec - .get(codec_id as usize) - .ok_or(TlsError::ParamError)? - .as_ref() - .ok_or(TlsError::ParamError)?; - - if codec.is_handshaking() { - Ok(WasmVal::I32(1)) - } else { - Ok(WasmVal::I32(0)) - } - } - - match is_handshaking_inner(memory, ctx, args) { - Ok(ok) => Ok(vec![ok]), - Err(e) => Ok(vec![WasmVal::I32(e.error_code())]), - } - } - - fn wants( - _inst: &mut SyncInstanceRef, - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<Vec<WasmVal>, CoreError> { - #[inline] - fn wants_inner( - _memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<WasmVal, TlsError> { - let codec_id = match_value!(args[0].clone(), WasmVal::I32, TlsError::ParamError); - let codec = ctx - .client_codec - .get(codec_id as usize) - .ok_or(TlsError::ParamError)? - .as_ref() - .ok_or(TlsError::ParamError)?; - match (codec.0.wants_write(), codec.0.wants_read()) { - (true, true) => Ok(WasmVal::I32(0b11)), - (true, false) => Ok(WasmVal::I32(0b10)), - (false, true) => Ok(WasmVal::I32(0b01)), - (false, false) => Ok(WasmVal::I32(0)), - } - } - - match wants_inner(memory, ctx, args) { - Ok(ok) => Ok(vec![ok]), - Err(e) => Ok(vec![WasmVal::I32(e.error_code())]), - } - } - - fn delete_codec( - _inst: &mut SyncInstanceRef, - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<Vec<WasmVal>, CoreError> { - #[inline] - fn delete_codec_inner( - _memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<WasmVal, TlsError> { - let codec_id = match_value!(args[0].clone(), WasmVal::I32, TlsError::ParamError); - ctx.delete_codec(codec_id as usize); - Ok(WasmVal::I32(0)) - } - - match delete_codec_inner(memory, ctx, args) { - Ok(ok) => Ok(vec![ok]), - Err(e) => Ok(vec![WasmVal::I32(e.error_code())]), - } - } - - fn process_new_packets( - _inst: &mut SyncInstanceRef, - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<Vec<WasmVal>, CoreError> { - #[inline] - fn process_new_packets_inner( - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<WasmVal, TlsError> { - let codec_id = match_value!(args[0].clone(), WasmVal::I32, TlsError::ParamError); - let result_ptr = match_value!(args[1].clone(), WasmVal::I32, TlsError::ParamError); - - let codec = ctx - .client_codec - .get_mut(codec_id as usize) - .ok_or(TlsError::ParamError)? - .as_mut() - .ok_or(TlsError::ParamError)?; - let io_state = codec.process_new_packets()?; - - memory - .write_data((result_ptr as usize).into(), io_state) - .ok_or(TlsError::ParamError)?; - - Ok(WasmVal::I32(0 as i32)) - } - match process_new_packets_inner(memory, ctx, args) { - Ok(ok) => Ok(vec![ok]), - Err(e) => Ok(vec![WasmVal::I32(e.error_code())]), - } - } - - fn send_close_notify( - _inst: &mut SyncInstanceRef, - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<Vec<WasmVal>, CoreError> { - #[inline] - fn send_close_notify_inner( - _memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<WasmVal, TlsError> { - let codec_id = match_value!(args[0].clone(), WasmVal::I32, TlsError::ParamError); - let codec = ctx - .client_codec - .get_mut(codec_id as usize) - .ok_or(TlsError::ParamError)? - .as_mut() - .ok_or(TlsError::ParamError)?; - codec.send_close_notify(); - Ok(WasmVal::I32(0)) - } - - match send_close_notify_inner(memory, ctx, args) { - Ok(ok) => Ok(vec![ok]), - Err(e) => Ok(vec![WasmVal::I32(e.error_code())]), - } - } - - fn write_raw( - _inst: &mut SyncInstanceRef, - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<Vec<WasmVal>, CoreError> { - #[inline] - fn write_raw_inner( - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<WasmVal, TlsError> { - let codec_id = match_value!(args[0].clone(), WasmVal::I32, TlsError::ParamError); - let raw_buf_ptr = match_value!(args[1].clone(), WasmVal::I32, TlsError::ParamError); - let raw_len = match_value!(args[2].clone(), WasmVal::I32, TlsError::ParamError); - - let codec = ctx - .client_codec - .get_mut(codec_id as usize) - .ok_or(TlsError::ParamError)? - .as_mut() - .ok_or(TlsError::ParamError)?; - - let raw_buf = memory - .data_pointer(raw_buf_ptr as usize, raw_len as usize) - .ok_or(TlsError::ParamError)?; - - let n = codec.write_raw(raw_buf)?; - Ok(WasmVal::I32(n as i32)) - } - match write_raw_inner(memory, ctx, args) { - Ok(ok) => Ok(vec![ok]), - Err(e) => Ok(vec![WasmVal::I32(e.error_code())]), - } - } - - fn write_tls( - _inst: &mut SyncInstanceRef, - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<Vec<WasmVal>, CoreError> { - #[inline] - fn write_tls_inner( - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<WasmVal, TlsError> { - let codec_id = match_value!(args[0].clone(), WasmVal::I32, TlsError::ParamError); - let tls_buf_ptr = match_value!(args[1].clone(), WasmVal::I32, TlsError::ParamError); - let tls_len = match_value!(args[2].clone(), WasmVal::I32, TlsError::ParamError); - - let codec = ctx - .client_codec - .get_mut(codec_id as usize) - .ok_or(TlsError::ParamError)? - .as_mut() - .ok_or(TlsError::ParamError)?; - - let raw_buf = memory - .data_pointer_mut(tls_buf_ptr as usize, tls_len as usize) - .ok_or(TlsError::ParamError)?; - - let n = codec.write_tls(raw_buf)?; - Ok(WasmVal::I32(n as i32)) - } - match write_tls_inner(memory, ctx, args) { - Ok(ok) => Ok(vec![ok]), - Err(e) => Ok(vec![WasmVal::I32(e.error_code())]), - } - } - - fn read_raw( - _inst: &mut SyncInstanceRef, - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<Vec<WasmVal>, CoreError> { - #[inline] - fn read_raw_inner( - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<WasmVal, TlsError> { - let codec_id = match_value!(args[0].clone(), WasmVal::I32, TlsError::ParamError); - let raw_buf_ptr = match_value!(args[1].clone(), WasmVal::I32, TlsError::ParamError); - let raw_len = match_value!(args[2].clone(), WasmVal::I32, TlsError::ParamError); - - let codec = ctx - .client_codec - .get_mut(codec_id as usize) - .ok_or(TlsError::ParamError)? - .as_mut() - .ok_or(TlsError::ParamError)?; - - let raw_buf = memory - .data_pointer_mut(raw_buf_ptr as usize, raw_len as usize) - .ok_or(TlsError::ParamError)?; - - let n = codec.read_raw(raw_buf); - let n = n?; - Ok(WasmVal::I32(n as i32)) - } - match read_raw_inner(memory, ctx, args) { - Ok(ok) => Ok(vec![ok]), - Err(e) => Ok(vec![WasmVal::I32(e.error_code())]), - } - } - - fn read_tls( - _inst: &mut SyncInstanceRef, - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<Vec<WasmVal>, CoreError> { - #[inline] - fn read_tls_inner( - memory: &mut Memory, - ctx: &mut Ctx, - args: Vec<WasmVal>, - ) -> Result<WasmVal, TlsError> { - let codec_id = match_value!(args[0].clone(), WasmVal::I32, TlsError::ParamError); - let tls_buf_ptr = match_value!(args[1].clone(), WasmVal::I32, TlsError::ParamError); - let tls_len = match_value!(args[2].clone(), WasmVal::I32, TlsError::ParamError); - - let codec = ctx - .client_codec - .get_mut(codec_id as usize) - .ok_or(TlsError::ParamError)? - .as_mut() - .ok_or(TlsError::ParamError)?; - - let raw_buf = memory - .data_pointer(tls_buf_ptr as usize, tls_len as usize) - .ok_or(TlsError::ParamError)?; - - let n = codec.read_tls(raw_buf)?; - Ok(WasmVal::I32(n as i32)) - } - match read_tls_inner(memory, ctx, args) { - Ok(ok) => Ok(vec![ok]), - Err(e) => Ok(vec![WasmVal::I32(e.error_code())]), - } - } - - pub fn create_module() -> PluginModule<Ctx> { - let mut module = PluginModule::create("rustls_client", Ctx::new()).unwrap(); - module - .add_func( - "default_config", - (vec![], vec![ValType::I32]), - default_config, - ) - .unwrap(); - - module - .add_func( - "new_codec", - ( - vec![ValType::I32, ValType::I32, ValType::I32], - vec![ValType::I32], - ), - new_client_codec, - ) - .unwrap(); - - module - .add_func( - "codec_is_handshaking", - (vec![ValType::I32], vec![ValType::I32]), - is_handshaking, - ) - .unwrap(); - - module - .add_func( - "codec_wants", - (vec![ValType::I32], vec![ValType::I32]), - wants, - ) - .unwrap(); - - module - .add_func( - "delete_codec", - (vec![ValType::I32], vec![ValType::I32]), - delete_codec, - ) - .unwrap(); - - module - .add_func( - "send_close_notify", - (vec![ValType::I32], vec![ValType::I32]), - send_close_notify, - ) - .unwrap(); - - module - .add_func( - "process_new_packets", - (vec![ValType::I32, ValType::I32], vec![ValType::I32]), - process_new_packets, - ) - .unwrap(); - - module - .add_func( - "write_raw", - ( - vec![ - ValType::I32, //codec_id - ValType::I32, // buf - ValType::I32, // buf_len - ], - vec![ValType::I32], - ), - write_raw, - ) - .unwrap(); - - module - .add_func( - "write_tls", - ( - vec![ - ValType::I32, //codec_id - ValType::I32, // buf - ValType::I32, // buf_len - ], - vec![ValType::I32], - ), - write_tls, - ) - .unwrap(); - - module - .add_func( - "read_raw", - ( - vec![ - ValType::I32, //codec_id - ValType::I32, // buf - ValType::I32, // buf_len - ], - vec![ValType::I32], - ), - read_raw, - ) - .unwrap(); - - module - .add_func( - "read_tls", - ( - vec![ - ValType::I32, //codec_id - ValType::I32, // buf - ValType::I32, // buf_len - ], - vec![ValType::I32], - ), - read_tls, - ) - .unwrap(); - - module - } -} - -use wasmedge_client_plugin::create_module; - -wasmedge_plugin_sdk::plugin::register_plugin!( - plugin_name="rustls", - plugin_description="rustls plugin", - version=(0,0,1,0), - modules=[ - {"rustls_client","rustls client module",create_module} - ] -); diff --git a/plugins/wasmedge_stablediffusion/CMakeLists.txt b/plugins/wasmedge_stablediffusion/CMakeLists.txt new file mode 100644 index 000000000000..9936d3f618d6 --- /dev/null +++ b/plugins/wasmedge_stablediffusion/CMakeLists.txt @@ -0,0 +1,124 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + + +if(WASMEDGE_PLUGIN_STABLEDIFFUSION_CUBLAS) + message(STATUS "Stable diffusion plugin: Enable SD_CUBLAS") + set(SD_CUBLAS ON CACHE BOOL "Stable diffusion plugin: Enable SD_CUBLAS") +else() + message(STATUS "Stable diffusion plugin: Disable SD_CUBLAS") + set(SD_CUBLAS OFF CACHE BOOL "Stable diffusion plugin: Disable SD_CUBLAS") +endif() + +if(APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" AND WASMEDGE_PLUGIN_STABLEDIFFUSION_METAL) + message(STATUS "Stable diffusion plugin: Enable SD_METAL") + set(SD_METAL ON CACHE BOOL "Stable diffusion plugin: Enable SD_METAL") + set(GGML_METAL_EMBED_LIBRARY ON) +else() + message(STATUS "Stable diffusion plugin: Disable SD_METAL") + set(SD_METAL OFF CACHE BOOL "Stable diffusion plugin: Disable SD_METAL") +endif() + +# setup stable diffusion +message(STATUS "Downloading stable diffusion source") +FetchContent_Declare( + stable-diffusion + GIT_REPOSITORY https://github.com/leejet/stable-diffusion.cpp.git + GIT_TAG master-e71ddce + GIT_SHALLOW TRUE +) +FetchContent_MakeAvailable(stable-diffusion) +set_property(TARGET stable-diffusion PROPERTY POSITION_INDEPENDENT_CODE ON) +if(APPLE AND CMAKE_SYSTEM_VERSION VERSION_LESS 23) + # `cblas_sgemm()` introduced in macOS 13.3. + set(GGML_NO_ACCELERATE ON CACHE INTERNAL "Stable diffusion plugin: Turn off accelerate") +endif() +get_target_property(SD_DEPS stable-diffusion LINK_LIBRARIES) +foreach(dep ${SD_DEPS}) + if(TARGET ${dep}) + set_target_properties(${dep} PROPERTIES + POSITION_INDEPENDENT_CODE ON + ) + endif() +endforeach() + +wasmedge_add_library(wasmedgePluginWasmEdgeStableDiffusion + SHARED + sd_env.cpp + sd_func.cpp + sd_module.cpp +) + +target_link_libraries(wasmedgePluginWasmEdgeStableDiffusion + PRIVATE + stable-diffusion + ${CMAKE_THREAD_LIBS_INIT} +) + +target_compile_options(wasmedgePluginWasmEdgeStableDiffusion + PUBLIC + -DWASMEDGE_PLUGIN +) + +if(WASMEDGE_LINK_PLUGINS_STATIC) + target_link_libraries(wasmedgePluginWasmEdgeStableDiffusion + PRIVATE + wasmedgeCAPI + ) +else() + target_link_libraries(wasmedgePluginWasmEdgeStableDiffusion + PRIVATE + wasmedge_shared + ) +endif() + +target_include_directories(wasmedgePluginWasmEdgeStableDiffusion + PUBLIC + $<TARGET_PROPERTY:wasmedgePlugin,INCLUDE_DIRECTORIES> + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_include_directories(wasmedgePluginWasmEdgeStableDiffusion + SYSTEM + PRIVATE + "${stable-diffusion_SOURCE_DIR}/thirdparty" +) + +if (MSVC) + target_compile_options( + stable-diffusion + PRIVATE + /wd4459 + /wd4100 + /wd4127 + /wd4701 + ) +else() + target_compile_options( + stable-diffusion + PRIVATE + -Wno-unused-function + -Wno-unused-variable + -Wno-unused-parameter + -Wno-missing-field-initializers + -Wno-deprecated-declarations + -Wno-braced-scalar-init + -Wno-unused-value + -Wno-uninitialized + -Wno-format + ) +endif() + +if(WASMEDGE_PLUGIN_STABLEDIFFUSION_METAL) + add_custom_command( + TARGET wasmedgePluginWasmEdgeStableDiffusion + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${stable-diffusion_SOURCE_DIR}/ggml/src/ggml-metal.metal ggml-metal.metal + COMMAND ${CMAKE_COMMAND} -E copy ${stable-diffusion_SOURCE_DIR}/ggml/src/ggml-common.h ggml-common.h + ) +endif() + +install( + TARGETS wasmedgePluginWasmEdgeStableDiffusion + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) diff --git a/plugins/wasmedge_stablediffusion/sd_base.h b/plugins/wasmedge_stablediffusion/sd_base.h new file mode 100644 index 000000000000..5ba7441cd8ec --- /dev/null +++ b/plugins/wasmedge_stablediffusion/sd_base.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "sd_env.h" + +#include "common/errcode.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { +namespace StableDiffusion { + +template <typename T> class Func : public Runtime::HostFunction<T> { +public: + Func(SDEnviornment &HostEnv) : Runtime::HostFunction<T>(0), Env(HostEnv) {} + +protected: + static constexpr uint32_t castErrNo(StableDiffusion::ErrNo E) noexcept { + return static_cast<uint32_t>(E); + } + SDEnviornment &Env; +}; + +} // namespace StableDiffusion +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_stablediffusion/sd_env.cpp b/plugins/wasmedge_stablediffusion/sd_env.cpp new file mode 100644 index 000000000000..73c618fa4ec5 --- /dev/null +++ b/plugins/wasmedge_stablediffusion/sd_env.cpp @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "sd_env.h" +#include "sd_module.h" + +namespace WasmEdge { +namespace Host { +namespace { + +Runtime::Instance::ModuleInstance * +create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new SDModule; +} + +Plugin::Plugin::PluginDescriptor Descriptor{ + .Name = "wasmedge_stablediffusion", + .Description = "Stable Diffusion plug-in for WasmEdge.", + .APIVersion = Plugin::Plugin::CurrentAPIVersion, + .Version = {0, 1, 0, 0}, + .ModuleCount = 1, + .ModuleDescriptions = + (Plugin::PluginModule::ModuleDescriptor[]){ + { + .Name = "wasmedge_stablediffusion", + .Description = + "This module contains Stable Diffusion host functions.", + .Create = create, + }, + }, + .AddOptions = nullptr, +}; + +EXPORT_GET_DESCRIPTOR(Descriptor) + +} // namespace + +namespace StableDiffusion { + +uint32_t SDEnviornment::addContext(sd_ctx_t *Ctx) noexcept { + Contexts.push_back(Ctx); + return Contexts.size() - 1; +} + +sd_ctx_t *SDEnviornment::getContext(const uint32_t Id) noexcept { + return Contexts[Id]; +} + +void SBLog(enum sd_log_level_t Level, const char *Log, void *) { + if (!Log) { + return; + } + std::string LevelStr; + switch (Level) { + case SD_LOG_DEBUG: + LevelStr = "DEBUG"; + break; + case SD_LOG_INFO: + LevelStr = "INFO"; + break; + case SD_LOG_WARN: + LevelStr = "WARN"; + break; + case SD_LOG_ERROR: + LevelStr = "ERROR"; + break; + default: + LevelStr = "?????"; + break; + } + + spdlog::info("[WasmEdge-StableDiffusion] SD-log: [{}] {}", LevelStr, Log); +} + +} // namespace StableDiffusion +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_stablediffusion/sd_env.h b/plugins/wasmedge_stablediffusion/sd_env.h new file mode 100644 index 000000000000..4c3a278cf940 --- /dev/null +++ b/plugins/wasmedge_stablediffusion/sd_env.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "stable-diffusion.h" + +#include "plugin/plugin.h" +#include <vector> + +namespace WasmEdge { +namespace Host { +namespace StableDiffusion { + +void SBLog(enum sd_log_level_t Level, const char *Log, void *); + +enum class ErrNo : uint32_t { + Success = 0, // No error occurred. + InvalidArgument = 1, // Caller module passed an invalid argument. + InvalidEncoding = 2, // Invalid encoding. + MissingMemory = 3, // Caller module is missing a memory export. + Busy = 4, // Device or resource busy. + RuntimeError = 5, // Runtime Error. +}; + +class SDEnviornment { +public: + SDEnviornment() noexcept { + if (EnableSDLog) { + sd_set_log_callback(SBLog, nullptr); + } + }; + uint32_t addContext(sd_ctx_t *Ctx) noexcept; + sd_ctx_t *getContext(const uint32_t Id) noexcept; + size_t getContextSize() noexcept { return Contexts.size(); } + +private: + std::vector<sd_ctx_t *> Contexts; + bool EnableSDLog = false; +}; + +} // namespace StableDiffusion +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_stablediffusion/sd_func.cpp b/plugins/wasmedge_stablediffusion/sd_func.cpp new file mode 100644 index 000000000000..f8879122e054 --- /dev/null +++ b/plugins/wasmedge_stablediffusion/sd_func.cpp @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "sd_func.h" +#include "common/spdlog.h" +#include "sd_env.h" +#include "spdlog/spdlog.h" +#include "stable-diffusion.h" + +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_STATIC +#include "stb_image.h" + +#define STB_IMAGE_WRITE_IMPLEMENTATION +#define STB_IMAGE_WRITE_STATIC +#include "stb_image_write.h" + +namespace WasmEdge { +namespace Host { +namespace StableDiffusion { + +#define MEMINST_CHECK(Out, CallFrame, Index) \ + auto *Out = CallFrame.getMemoryByIndex(Index); \ + if (unlikely(Out == nullptr)) { \ + spdlog::error("[WasmEdge-StableDiffusion] Memory instance not found."sv); \ + return static_cast<uint32_t>(ErrNo::MissingMemory); \ + } + +#define SESSION_CHECK(Out, SessionID, Message, ErrNo) \ + auto *Out = Env.getContext(SessionID); \ + if (unlikely(Out == nullptr)) { \ + spdlog::error("[WasmEdge-StableDiffusion] "sv Message); \ + return static_cast<uint32_t>(ErrNo); \ + } + +#define MEM_SPAN_CHECK(OutSpan, MemInst, Type, BufPtr, BufLen, Message) \ + auto OutSpan = MemInst->getSpan<Type>(BufPtr, BufLen); \ + if (unlikely(OutSpan.size() != BufLen)) { \ + spdlog::error("[WasmEdge-StableDiffusion] "sv Message); \ + return static_cast<uint32_t>(ErrNo::MissingMemory); \ + } + +#define MEM_SV_CHECK(OutSV, MemInst, BufPtr, BufLen, Message) \ + auto OutSV = MemInst->getStringView(BufPtr, BufLen); \ + if (unlikely(OutSV.size() != BufLen)) { \ + spdlog::error("[WasmEdge-StableDiffusion] "sv Message); \ + return static_cast<uint32_t>(ErrNo::MissingMemory); \ + } + +#define MEM_PTR_CHECK(OutPtr, MemInst, Type, Offset, Message) \ + Type *OutPtr = MemInst->getPointer<Type *>(Offset); \ + if (unlikely(OutPtr == nullptr)) { \ + spdlog::error("[WasmEdge-StableDiffusion] "sv Message); \ + return static_cast<uint32_t>(ErrNo::MissingMemory); \ + } + +bool parameterCheck(SDEnviornment &Env, uint32_t Width, uint32_t Height, + uint32_t SessionId) { + if (SessionId >= Env.getContextSize()) { + spdlog::error("[WasmEdge-StableDiffusion] Session ID is invalid."); + return false; + } + if (Width % 64 != 0) { + spdlog::error("[WasmEdge-StableDiffusion] Width must be a multiple of 64 " + "and greater than 0."); + return false; + } + if (Height % 64 != 0) { + spdlog::error("[WasmEdge-StableDiffusion] Height must be a multiple of 64 " + "and greater than 0."); + return false; + } + return true; +} + +sd_image_t *readControlImage(Span<uint8_t> ControlImage, + uint8_t *ControlImageBuf, int Width, int Height, + bool CannyPreprocess) { + sd_image_t *ControlImg = nullptr; + int Channel = 0; + std::string ControlImagePath(ControlImage.begin(), ControlImage.end()); + + if (ControlImagePath.substr(0, 5) == "path:"sv) { + ControlImageBuf = stbi_load(ControlImagePath.substr(5).data(), &Width, + &Height, &Channel, 3); + } else { + ControlImageBuf = stbi_load_from_memory( + ControlImage.data(), ControlImage.size(), &Width, &Height, &Channel, 3); + } + + if (ControlImageBuf == nullptr) { + spdlog::error( + "[WasmEdge-StableDiffusion] Load image from control image failed."sv); + return nullptr; + } + ControlImg = + new sd_image_t{static_cast<uint32_t>(Width), + static_cast<uint32_t>(Height), 3, ControlImageBuf}; + if (CannyPreprocess) { // apply preprocessor + ControlImg->data = + preprocess_canny(ControlImg->data, ControlImg->width, + ControlImg->height, 0.08f, 0.08f, 0.8f, 1.0f, false); + } + return ControlImg; +} + +Expect<uint32_t> SDConvert::body(const Runtime::CallingFrame &Frame, + uint32_t ModelPathPtr, uint32_t ModelPathLen, + uint32_t VaeModelPathPtr, + uint32_t VaeModelPathLen, + uint32_t OutputPathPtr, uint32_t OutputPathLen, + uint32_t WType) { + // Check memory instance from module. + MEMINST_CHECK(MemInst, Frame, 0) + + // Check the input parameter value. + MEM_SPAN_CHECK(ModelPathSpan, MemInst, char, ModelPathPtr, ModelPathLen, + "Failed when accessing the input model path memory."sv) + MEM_SPAN_CHECK(VaeModelPathSpan, MemInst, char, VaeModelPathPtr, + VaeModelPathLen, + "Failed when accessing the input vae model path memory."sv) + MEM_SPAN_CHECK(OutputPathSpan, MemInst, char, OutputPathPtr, OutputPathLen, + "Failed when accessing the output path memory."sv) + std::string ModelPath = std::string( + ModelPathSpan.begin(), ModelPathSpan.begin() + ModelPathSpan.size()); + std::string VaeModelPath = + std::string(VaeModelPathSpan.begin(), + VaeModelPathSpan.begin() + VaeModelPathSpan.size()); + std::string OutputPath = std::string( + OutputPathSpan.begin(), OutputPathSpan.begin() + OutputPathSpan.size()); + + spdlog::info("[WasmEdge-StableDiffusion] Convert model: {} to {}."sv, + ModelPath.data(), OutputPath.data()); + std::ifstream Fin(ModelPath.data(), std::ios::in | std::ios::binary); + if (!Fin) { + Fin.close(); + spdlog::error("[WasmEdge-StableDiffusion] Model not found."); + return static_cast<uint32_t>(ErrNo::InvalidArgument); + } + Fin.close(); + // Convert model. + bool Ret = ::convert(ModelPath.data(), VaeModelPath.data(), OutputPath.data(), + static_cast<sd_type_t>(WType)); + if (!Ret) { + spdlog::error("[WasmEdge-StableDiffusion] Failed to convert model."); + return static_cast<uint32_t>(ErrNo::InvalidArgument); + } + + return static_cast<uint32_t>(ErrNo::Success); +} + +Expect<uint32_t> SDCreateContext::body( + const Runtime::CallingFrame &Frame, uint32_t ModelPathPtr, + uint32_t ModelPathLen, uint32_t clipLPathPtr, uint32_t clipLPathLen, + uint32_t t5xxlPathPtr, uint32_t t5xxlPathLen, + uint32_t diffusionModelPathPtr, uint32_t diffusionModelPathLen, + uint32_t VaePathPtr, uint32_t VaePathLen, uint32_t TaesdPathPtr, + uint32_t TaesdPathLen, uint32_t ControlNetPathPtr, + uint32_t ControlNetPathLen, uint32_t LoraModelDirPtr, + uint32_t LoraModelDirLen, uint32_t EmbedDirPtr, uint32_t EmbedDirLen, + uint32_t IdEmbedDirPtr, uint32_t IdEmbedDirLen, uint32_t VaeDecodeOnly, + uint32_t VaeTiling, int32_t NThreads, uint32_t Wtype, uint32_t RngType, + uint32_t Schedule, uint32_t ClipOnCpu, uint32_t ControlNetCpu, + uint32_t VaeOnCpu, uint32_t SessiontIdPtr) { + // Check memory instance from module. + MEMINST_CHECK(MemInst, Frame, 0) + + // Check the input model buffer. + MEM_SPAN_CHECK(ModelPathSpan, MemInst, char, ModelPathPtr, ModelPathLen, + "Failed when accessing the input model path memory."sv) + MEM_SPAN_CHECK(clipLPathSpan, MemInst, char, clipLPathPtr, clipLPathLen, + "Failed when accessing the input clipL path memory."sv) + MEM_SPAN_CHECK(t5xxlPathSpan, MemInst, char, t5xxlPathPtr, t5xxlPathLen, + "Failed when accessing the input t5xxl path memory."sv) + MEM_SPAN_CHECK( + diffusionModelPathSpan, MemInst, char, diffusionModelPathPtr, + diffusionModelPathLen, + "Failed when accessing the input diffusion model path memory."sv) + MEM_SPAN_CHECK(VaePathSpan, MemInst, char, VaePathPtr, VaePathLen, + "Failed when accessing the input vae path memory."sv) + MEM_SPAN_CHECK(ControlNetPathSpan, MemInst, char, ControlNetPathPtr, + ControlNetPathLen, + "Failed when accessing the input control net path memory."sv) + MEM_SPAN_CHECK(LoraModelDirSpan, MemInst, char, LoraModelDirPtr, + LoraModelDirLen, + "Failed when accessing the input lora model path memory."sv) + MEM_SPAN_CHECK(TaesdPathSpan, MemInst, char, TaesdPathPtr, TaesdPathLen, + "Failed when accessing the input taesd path memory."sv) + MEM_SPAN_CHECK(EmbedDirSpan, MemInst, char, EmbedDirPtr, EmbedDirLen, + "Failed when accessing the input embedded directory memory."sv) + MEM_SPAN_CHECK( + IdEmbedDirSpan, MemInst, char, IdEmbedDirPtr, IdEmbedDirLen, + "Failed when accessing the input id dembed directory memory."sv) + MEM_PTR_CHECK(SessionId, MemInst, uint32_t, SessiontIdPtr, + "Failed when accessing the return SessionID memory."sv) + + std::string ModelPath = + std::string(ModelPathSpan.begin(), ModelPathSpan.end()); + std::string VaePath = std::string(VaePathSpan.begin(), VaePathSpan.end()); + std::string TaesdPath = + std::string(TaesdPathSpan.begin(), TaesdPathSpan.end()); + std::string ControlNetPath = + std::string(ControlNetPathSpan.begin(), ControlNetPathSpan.end()); + std::string LoraModelDir = + std::string(LoraModelDirSpan.begin(), LoraModelDirSpan.end()); + std::string EmbedDir = std::string(EmbedDirSpan.begin(), EmbedDirSpan.end()); + std::string IdEmbedDir = + std::string(IdEmbedDirSpan.begin(), IdEmbedDirSpan.end()); + std::string clipLPath = + std::string(clipLPathSpan.begin(), clipLPathSpan.end()); + std::string t5xxlPath = + std::string(t5xxlPathSpan.begin(), t5xxlPathSpan.end()); + std::string diffusionModelPath = + std::string(diffusionModelPathSpan.begin(), diffusionModelPathSpan.end()); + if (NThreads == -1) { + NThreads = get_num_physical_cores(); + } + + spdlog::info("[WasmEdge-StableDiffusion] Create context."sv); + // Create context and import graph. + + sd_ctx_t *Ctx = new_sd_ctx( + ModelPath.data(), clipLPath.data(), t5xxlPath.data(), + diffusionModelPath.data(), VaePath.data(), TaesdPath.data(), + ControlNetPath.data(), LoraModelDir.data(), EmbedDir.data(), + IdEmbedDir.data(), static_cast<bool>(VaeDecodeOnly), + static_cast<bool>(VaeTiling), true, NThreads, + static_cast<sd_type_t>(Wtype), static_cast<rng_type_t>(RngType), + static_cast<schedule_t>(Schedule), ClipOnCpu, ControlNetCpu, VaeOnCpu); + if (Ctx == nullptr) { + spdlog::error("[WasmEdge-StableDiffusion] Failed to create context."); + return static_cast<uint32_t>(ErrNo::InvalidArgument); + } + *SessionId = Env.addContext(Ctx); + + return static_cast<uint32_t>(ErrNo::Success); +} + +Expect<uint32_t> SDTextToImage::body( + const Runtime::CallingFrame &Frame, uint32_t PromptPtr, uint32_t PromptLen, + uint32_t SessionId, uint32_t ControlImagePtr, uint32_t ControlImageLen, + uint32_t NegativePromptPtr, uint32_t NegativePromptLen, float Guidance, + uint32_t Width, uint32_t Height, int32_t ClipSkip, float CfgScale, + uint32_t SampleMethod, uint32_t SampleSteps, uint32_t Seed, + uint32_t BatchCount, float ControlStrength, float StyleRatio, + uint32_t NormalizeInput, uint32_t InputIdImagesDirPtr, + uint32_t InputIdImagesDirLen, uint32_t CannyPreprocess, uint32_t, uint32_t, + uint32_t, uint32_t OutputPathPtr, uint32_t OutputPathLen, + uint32_t OutBufferPtr, uint32_t OutBufferMaxSize, + uint32_t BytesWrittenPtr) { + // Check memory instance from module. + MEMINST_CHECK(MemInst, Frame, 0) + // Check the input model buffer. + MEM_SPAN_CHECK(PromptSpan, MemInst, char, PromptPtr, PromptLen, + "Failed when accessing the promp memory."sv) + MEM_SPAN_CHECK(NegativePromptSpan, MemInst, char, NegativePromptPtr, + NegativePromptLen, + "Failed when accessing the input negative prompt memory."sv) + MEM_SPAN_CHECK(InputIdImagesDirSpan, MemInst, char, InputIdImagesDirPtr, + InputIdImagesDirLen, + "Failed when accessing the input id images path memory."sv) + MEM_SPAN_CHECK(OutputBufferSpan, MemInst, uint8_t, OutBufferPtr, + OutBufferMaxSize, + "Failed when accessing the Output Buffer memory."sv) + MEM_PTR_CHECK(BytesWritten, MemInst, uint32_t, BytesWrittenPtr, + "Failed when accessing the return bytes written memory."sv) + MEM_SPAN_CHECK(OutputPathSpan, MemInst, char, OutputPathPtr, OutputPathLen, + "Failed when accessing the output path memory."sv) + std::string Prompt(PromptSpan.begin(), PromptSpan.end()); + std::string NegativePrompt(NegativePromptSpan.begin(), + NegativePromptSpan.end()); + std::string InputIdImagesDir(InputIdImagesDirSpan.begin(), + InputIdImagesDirSpan.end()); + std::string OutputPath(OutputPathSpan.begin(), OutputPathSpan.end()); + if (!parameterCheck(Env, Width, Height, SessionId)) { + return static_cast<uint32_t>(ErrNo::InvalidArgument); + } + sd_ctx_t *SDCtx = Env.getContext(SessionId); + sd_image_t *Results = nullptr; + sd_image_t *ControlImage = nullptr; + uint8_t *ControlImageBuffer = nullptr; + if (ControlImageLen != 0) { + MEM_SPAN_CHECK(ControlImageSpan, MemInst, uint8_t, ControlImagePtr, + ControlImageLen, + "Failed when accessing the control image memory."sv) + ControlImage = readControlImage(ControlImageSpan, ControlImageBuffer, Width, + Height, CannyPreprocess); + } + spdlog::info("[WasmEdge-StableDiffusion] Start to generate image."sv); + Results = + txt2img(SDCtx, Prompt.data(), NegativePrompt.data(), ClipSkip, CfgScale, + Guidance, Width, Height, sample_method_t(SampleMethod), + SampleSteps, Seed, BatchCount, ControlImage, ControlStrength, + StyleRatio, NormalizeInput, InputIdImagesDir.data()); + // TODO upscale image + int Len; + unsigned char *Png = stbi_write_png_to_mem( + reinterpret_cast<const unsigned char *>(Results->data), 0, Results->width, + Results->height, Results->channel, &Len, nullptr); + if (OutputPathLen != 0) { + stbi_write_png(OutputPath.data(), Results->width, Results->height, + Results->channel, Results->data, 0, nullptr); + } + *BytesWritten = Len; + if (OutBufferMaxSize < *BytesWritten) { + spdlog::error("[WasmEdge-StableDiffusion] Output buffer is not enough."sv); + free(Png); + free(Results); + free(ControlImageBuffer); + return static_cast<uint32_t>(ErrNo::RuntimeError); + } + std::copy_n(Png, *BytesWritten, OutputBufferSpan.data()); + free(Png); + free(Results); + free(ControlImageBuffer); + return static_cast<uint32_t>(ErrNo::Success); +} + +Expect<uint32_t> SDImageToImage::body( + const Runtime::CallingFrame &Frame, uint32_t ImagePtr, uint32_t ImageLen, + uint32_t SessionId, float Guidance, uint32_t Width, uint32_t Height, + uint32_t ControlImagePtr, uint32_t ControlImageLen, uint32_t PromptPtr, + uint32_t PromptLen, uint32_t NegativePromptPtr, uint32_t NegativePromptLen, + int32_t ClipSkip, float CfgScale, uint32_t SampleMethod, + uint32_t SampleSteps, float Strength, uint32_t Seed, uint32_t BatchCount, + float ControlStrength, float StyleRatio, uint32_t NormalizeInput, + uint32_t InputIdImagesDirPtr, uint32_t InputIdImagesDirLen, + uint32_t CannyPreprocess, uint32_t, uint32_t, uint32_t, + uint32_t OutputPathPtr, uint32_t OutputPathLen, uint32_t OutBufferPtr, + uint32_t OutBufferMaxSize, uint32_t BytesWrittenPtr) { + // Check memory instance from module. + MEMINST_CHECK(MemInst, Frame, 0) + + // Check the input parameter valid. + MEM_SPAN_CHECK(ImageSpan, MemInst, uint8_t, ImagePtr, ImageLen, + "Failed when accessing the input image memory."sv) + + MEM_SPAN_CHECK(PromptSpan, MemInst, char, PromptPtr, PromptLen, + "Failed when accessing the promp memory."sv) + MEM_SPAN_CHECK(NegativePromptSpan, MemInst, char, NegativePromptPtr, + NegativePromptLen, + "Failed when accessing the input negative prompt memory."sv) + MEM_SPAN_CHECK(InputIdImagesDirSpan, MemInst, char, InputIdImagesDirPtr, + InputIdImagesDirLen, + "Failed when accessing the input id images path memory."sv) + MEM_SPAN_CHECK(OutputBufferSpan, MemInst, uint8_t, OutBufferPtr, + OutBufferMaxSize, + "Failed when accessing the Output Buffer memory."sv) + MEM_PTR_CHECK(BytesWritten, MemInst, uint32_t, BytesWrittenPtr, + "Failed when accessing the return bytes written memory."sv) + MEM_SPAN_CHECK(OutputPathSpan, MemInst, char, OutputPathPtr, OutputPathLen, + "Failed when accessing the output path memory."sv) + if (!parameterCheck(Env, Width, Height, SessionId)) { + return static_cast<uint32_t>(ErrNo::InvalidArgument); + } + sd_ctx_t *SDCtx = Env.getContext(SessionId); + std::string Prompt(PromptSpan.begin(), PromptSpan.end()); + std::string NegativePrompt(NegativePromptSpan.begin(), + NegativePromptSpan.end()); + std::string InputIdImagesDir(InputIdImagesDirSpan.begin(), + InputIdImagesDirSpan.end()); + std::string OutputPath(OutputPathSpan.begin(), OutputPathSpan.end()); + uint8_t *InputImageBuffer = nullptr; + uint8_t *ControlImageBuffer = nullptr; + int Channel = 0; + int ImageWidth = 0; + int ImageHeight = 0; + std::string ImagePath(ImageSpan.begin(), ImageSpan.end()); + if (ImagePath.substr(0, 5) == "path:"sv) { + InputImageBuffer = stbi_load(ImagePath.substr(5).data(), &ImageWidth, + &ImageHeight, &Channel, 3); + if (InputImageBuffer == nullptr) { + spdlog::error( + "[WasmEdge-StableDiffusion] Load image from input image failed."sv); + return static_cast<uint32_t>(ErrNo::InvalidArgument); + } + } else { + InputImageBuffer = + stbi_load_from_memory(ImageSpan.data(), ImageSpan.size(), &ImageWidth, + &ImageHeight, &Channel, 3); + } + // TODO: Resize image when image size not matches width and height + sd_image_t InputImage = {Width, Height, 3, InputImageBuffer}; + sd_image_t *ControlImage = nullptr; + if (ControlImageLen != 0) { + MEM_SPAN_CHECK(ControlImageSpan, MemInst, uint8_t, ControlImagePtr, + ControlImageLen, + "Failed when accessing the control image memory."sv) + ControlImage = readControlImage(ControlImageSpan, ControlImageBuffer, Width, + Height, CannyPreprocess); + } + sd_image_t *Results = nullptr; + spdlog::info("[WasmEdge-StableDiffusion] Start to generate image."sv); + Results = img2img(SDCtx, InputImage, Prompt.data(), NegativePrompt.data(), + ClipSkip, CfgScale, Guidance, Width, Height, + sample_method_t(SampleMethod), SampleSteps, Strength, Seed, + BatchCount, ControlImage, ControlStrength, StyleRatio, + NormalizeInput, InputIdImagesDir.data()); + // TODO: upscale image + int Len; + unsigned char *Png = stbi_write_png_to_mem( + reinterpret_cast<const unsigned char *>(Results->data), 0, Results->width, + Results->height, Results->channel, &Len, nullptr); + if (OutputPathLen != 0) { + stbi_write_png(OutputPath.data(), Results->width, Results->height, + Results->channel, Results->data, 0, nullptr); + } + *BytesWritten = Len; + if (OutBufferMaxSize < *BytesWritten) { + spdlog::error("[WasmEdge-StableDiffusion] Output buffer is not enough."sv); + free(Png); + free(Results); + free(InputImageBuffer); + free(ControlImageBuffer); + return static_cast<uint32_t>(ErrNo::RuntimeError); + } + std::copy_n(Png, *BytesWritten, OutputBufferSpan.data()); + free(Png); + free(Results); + free(InputImageBuffer); + free(ControlImageBuffer); + return static_cast<uint32_t>(ErrNo::Success); +} + +} // namespace StableDiffusion +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_stablediffusion/sd_func.h b/plugins/wasmedge_stablediffusion/sd_func.h new file mode 100644 index 000000000000..70b9d83158a6 --- /dev/null +++ b/plugins/wasmedge_stablediffusion/sd_func.h @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "sd_base.h" + +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace StableDiffusion { + +class SDCreateContext : public StableDiffusion::Func<SDCreateContext> { +public: + SDCreateContext(StableDiffusion::SDEnviornment &HostEnv) : Func(HostEnv) {} + Expect<uint32_t> + body(const Runtime::CallingFrame &Frame, uint32_t ModelPathPtr, + uint32_t ModelPathLen, uint32_t clipLPathPtr, uint32_t clipLPathLen, + uint32_t t5xxlPathPtr, uint32_t t5xxlPathLen, + uint32_t diffusionModelPathPtr, uint32_t diffusionModelPathLen, + uint32_t VaePathPtr, uint32_t VaePathLen, uint32_t TaesdPathPtr, + uint32_t TaesdPathLen, uint32_t ControlNetPathPtr, + uint32_t ControlNetPathLen, uint32_t LoraModelDirPtr, + uint32_t LoraModelDirLen, uint32_t EmbedDirPtr, uint32_t EmbedDirLen, + uint32_t IdEmbedDirPtr, uint32_t IdEmbedDirLen, uint32_t VaeDecodeOnly, + uint32_t VaeTiling, int32_t NThreads, uint32_t Wtype, uint32_t RngType, + uint32_t Schedule, uint32_t ClipOnCpu, uint32_t ControlNetCpu, + uint32_t VaeOnCpu, uint32_t SessiontIdPtr); +}; + +class SDImageToImage : public StableDiffusion::Func<SDImageToImage> { +public: + SDImageToImage(StableDiffusion::SDEnviornment &HostEnv) : Func(HostEnv) {} + Expect<uint32_t> + body(const Runtime::CallingFrame &Frame, uint32_t ImagePtr, uint32_t ImageLen, + uint32_t SessionId, float Guidance, uint32_t Width, uint32_t Height, + uint32_t ControlImagePtr, uint32_t ControlImageLen, uint32_t PromptPtr, + uint32_t PromptLen, uint32_t NegativePromptPtr, + uint32_t NegativePromptLen, int32_t ClipSkip, float CfgScale, + uint32_t SampleMethod, uint32_t SampleSteps, float Strength, + uint32_t Seed, uint32_t BatchCount, float ControlStrength, + float StyleRatio, uint32_t NormalizeInput, uint32_t InputIdImagesDirPtr, + uint32_t InputIdImagesDirLen, uint32_t CannyPreprocess, + uint32_t UpscaleModelPathPtr, uint32_t UpscaleModelPathLen, + uint32_t UpscaleRepeats, uint32_t OutputPathPtr, uint32_t OutputPathLen, + uint32_t OutBufferPtr, uint32_t OutBufferMaxSize, + uint32_t BytesWrittenPtr); +}; + +class SDTextToImage : public StableDiffusion::Func<SDTextToImage> { +public: + SDTextToImage(StableDiffusion::SDEnviornment &HostEnv) : Func(HostEnv) {} + Expect<uint32_t> + body(const Runtime::CallingFrame &Frame, uint32_t PromptPtr, + uint32_t PromptLen, uint32_t SessionId, uint32_t ControlImagePtr, + uint32_t ControlImageLen, uint32_t NegativePromptPtr, + uint32_t NegativePromptLen, float Guidance, uint32_t Width, + uint32_t Height, int32_t ClipSkip, float CfgScale, uint32_t SampleMethod, + uint32_t SampleSteps, uint32_t Seed, uint32_t BatchCount, + float ControlStrength, float StyleRatio, uint32_t NormalizeInput, + uint32_t InputIdImagesDirPtr, uint32_t InputIdImagesDirLen, + uint32_t CannyPreprocess, uint32_t UpscaleModelPathPtr, + uint32_t UpscaleModelPathLen, uint32_t UpscaleRepeats, + uint32_t OutputPathPtr, uint32_t OutputPathLen, uint32_t OutBufferPtr, + uint32_t OutBufferMaxSize, uint32_t BytesWrittenPtr); +}; + +class SDConvert : public StableDiffusion::Func<SDConvert> { +public: + SDConvert(StableDiffusion::SDEnviornment &HostEnv) : Func(HostEnv) {} + Expect<uint32_t> body(const Runtime::CallingFrame &Frame, + uint32_t ModelPathPtr, uint32_t ModelPathLen, + uint32_t VaeModelPathPtr, uint32_t VaeModelPathLen, + uint32_t OutputPathPtr, uint32_t OutputPathLen, + uint32_t WType); +}; + +} // namespace StableDiffusion +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_stablediffusion/sd_module.cpp b/plugins/wasmedge_stablediffusion/sd_module.cpp new file mode 100644 index 000000000000..a568c4ab45cf --- /dev/null +++ b/plugins/wasmedge_stablediffusion/sd_module.cpp @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "sd_module.h" +#include "sd_func.h" + +namespace WasmEdge { +namespace Host { + +SDModule::SDModule() : ModuleInstance("wasmedge_stablediffusion") { + addHostFunc("create_context", + std::make_unique<StableDiffusion::SDCreateContext>(Env)); + addHostFunc("image_to_image", + std::make_unique<StableDiffusion::SDImageToImage>(Env)); + addHostFunc("text_to_image", + std::make_unique<StableDiffusion::SDTextToImage>(Env)); + addHostFunc("convert", std::make_unique<StableDiffusion::SDConvert>(Env)); +} + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_stablediffusion/sd_module.h b/plugins/wasmedge_stablediffusion/sd_module.h new file mode 100644 index 000000000000..bfc7ba728ea6 --- /dev/null +++ b/plugins/wasmedge_stablediffusion/sd_module.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "sd_env.h" + +#include "runtime/instance/module.h" + +namespace WasmEdge { +namespace Host { + +class SDModule : public Runtime::Instance::ModuleInstance { +public: + SDModule(); + StableDiffusion::SDEnviornment &getEnv() { return Env; } + +private: + StableDiffusion::SDEnviornment Env; +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_tensorflow/CMakeLists.txt b/plugins/wasmedge_tensorflow/CMakeLists.txt index ba93b1411756..96147ee76fb0 100644 --- a/plugins/wasmedge_tensorflow/CMakeLists.txt +++ b/plugins/wasmedge_tensorflow/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_library(wasmedgePluginWasmEdgeTensorflow SHARED @@ -34,4 +34,7 @@ endif() include(WASINNDeps) wasmedge_setup_tf_target(wasmedgePluginWasmEdgeTensorflow) -install(TARGETS wasmedgePluginWasmEdgeTensorflow DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge) +install( + TARGETS wasmedgePluginWasmEdgeTensorflow + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) diff --git a/plugins/wasmedge_tensorflow/tensorflow_base.h b/plugins/wasmedge_tensorflow/tensorflow_base.h index 566861108b10..fb17fec5aa14 100644 --- a/plugins/wasmedge_tensorflow/tensorflow_base.h +++ b/plugins/wasmedge_tensorflow/tensorflow_base.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_tensorflow/tensorflow_env.cpp b/plugins/wasmedge_tensorflow/tensorflow_env.cpp index 9a672863758f..98312b14852c 100644 --- a/plugins/wasmedge_tensorflow/tensorflow_env.cpp +++ b/plugins/wasmedge_tensorflow/tensorflow_env.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "tensorflow_env.h" #include "tensorflow_module.h" @@ -32,9 +32,8 @@ Plugin::Plugin::PluginDescriptor Descriptor{ .AddOptions = nullptr, }; -} // namespace - -Plugin::PluginRegister WasmEdgeTensorflow::TFEnv::Register(&Descriptor); +EXPORT_GET_DESCRIPTOR(Descriptor) +} // namespace } // namespace Host } // namespace WasmEdge diff --git a/plugins/wasmedge_tensorflow/tensorflow_env.h b/plugins/wasmedge_tensorflow/tensorflow_env.h index 8cfcd645f760..5fd4ef3c8986 100644 --- a/plugins/wasmedge_tensorflow/tensorflow_env.h +++ b/plugins/wasmedge_tensorflow/tensorflow_env.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once @@ -117,8 +117,6 @@ struct TFEnv { } } - static Plugin::PluginRegister Register; - private: std::unordered_set<uint32_t> RecycledIdx; std::vector<Context> TFContext; diff --git a/plugins/wasmedge_tensorflow/tensorflow_func.cpp b/plugins/wasmedge_tensorflow/tensorflow_func.cpp index eed2b4fc64ec..d86143f46968 100644 --- a/plugins/wasmedge_tensorflow/tensorflow_func.cpp +++ b/plugins/wasmedge_tensorflow/tensorflow_func.cpp @@ -1,10 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "tensorflow_func.h" -#include "common/log.h" #include "common/span.h" +#include "common/spdlog.h" #include "tensorflow/c/c_api.h" diff --git a/plugins/wasmedge_tensorflow/tensorflow_func.h b/plugins/wasmedge_tensorflow/tensorflow_func.h index 6a2786dc5bcd..54b5e76a593c 100644 --- a/plugins/wasmedge_tensorflow/tensorflow_func.h +++ b/plugins/wasmedge_tensorflow/tensorflow_func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_tensorflow/tensorflow_module.cpp b/plugins/wasmedge_tensorflow/tensorflow_module.cpp index 73b079c49bf4..f0703e450fa7 100644 --- a/plugins/wasmedge_tensorflow/tensorflow_module.cpp +++ b/plugins/wasmedge_tensorflow/tensorflow_module.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "tensorflow_module.h" #include "tensorflow_func.h" diff --git a/plugins/wasmedge_tensorflow/tensorflow_module.h b/plugins/wasmedge_tensorflow/tensorflow_module.h index ae60330eeeb0..dfb96f9d0975 100644 --- a/plugins/wasmedge_tensorflow/tensorflow_module.h +++ b/plugins/wasmedge_tensorflow/tensorflow_module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_tensorflowlite/CMakeLists.txt b/plugins/wasmedge_tensorflowlite/CMakeLists.txt index 62e4707edc90..3069500937d9 100644 --- a/plugins/wasmedge_tensorflowlite/CMakeLists.txt +++ b/plugins/wasmedge_tensorflowlite/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_library(wasmedgePluginWasmEdgeTensorflowLite SHARED @@ -34,4 +34,7 @@ endif() include(WASINNDeps) wasmedge_setup_tflite_target(wasmedgePluginWasmEdgeTensorflowLite) -install(TARGETS wasmedgePluginWasmEdgeTensorflowLite DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge) +install( + TARGETS wasmedgePluginWasmEdgeTensorflowLite + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) diff --git a/plugins/wasmedge_tensorflowlite/tensorflowlite_base.h b/plugins/wasmedge_tensorflowlite/tensorflowlite_base.h index 6b0765aebe52..075a46f75042 100644 --- a/plugins/wasmedge_tensorflowlite/tensorflowlite_base.h +++ b/plugins/wasmedge_tensorflowlite/tensorflowlite_base.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_tensorflowlite/tensorflowlite_env.cpp b/plugins/wasmedge_tensorflowlite/tensorflowlite_env.cpp index 47a3e037e760..12161a6d5da0 100644 --- a/plugins/wasmedge_tensorflowlite/tensorflowlite_env.cpp +++ b/plugins/wasmedge_tensorflowlite/tensorflowlite_env.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "tensorflowlite_env.h" #include "tensorflowlite_module.h" @@ -32,9 +32,8 @@ Plugin::Plugin::PluginDescriptor Descriptor{ .AddOptions = nullptr, }; -} // namespace - -Plugin::PluginRegister WasmEdgeTensorflowLite::TFLiteEnv::Register(&Descriptor); +EXPORT_GET_DESCRIPTOR(Descriptor) +} // namespace } // namespace Host } // namespace WasmEdge diff --git a/plugins/wasmedge_tensorflowlite/tensorflowlite_env.h b/plugins/wasmedge_tensorflowlite/tensorflowlite_env.h index f4f606f4872e..02da4069c711 100644 --- a/plugins/wasmedge_tensorflowlite/tensorflowlite_env.h +++ b/plugins/wasmedge_tensorflowlite/tensorflowlite_env.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once @@ -63,8 +63,6 @@ struct TFLiteEnv { } } - static Plugin::PluginRegister Register; - private: std::unordered_set<uint32_t> RecycledIdx; std::vector<Context> TFLiteContext; diff --git a/plugins/wasmedge_tensorflowlite/tensorflowlite_func.cpp b/plugins/wasmedge_tensorflowlite/tensorflowlite_func.cpp index 18af8a1bf892..487825928958 100644 --- a/plugins/wasmedge_tensorflowlite/tensorflowlite_func.cpp +++ b/plugins/wasmedge_tensorflowlite/tensorflowlite_func.cpp @@ -1,10 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "tensorflowlite_func.h" -#include "common/log.h" #include "common/span.h" +#include "common/spdlog.h" #include "tensorflow/lite/c/c_api.h" diff --git a/plugins/wasmedge_tensorflowlite/tensorflowlite_func.h b/plugins/wasmedge_tensorflowlite/tensorflowlite_func.h index d8e9d5b58b8e..90e29f0b6eac 100644 --- a/plugins/wasmedge_tensorflowlite/tensorflowlite_func.h +++ b/plugins/wasmedge_tensorflowlite/tensorflowlite_func.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_tensorflowlite/tensorflowlite_module.cpp b/plugins/wasmedge_tensorflowlite/tensorflowlite_module.cpp index 5f8802298c33..0681849aa69e 100644 --- a/plugins/wasmedge_tensorflowlite/tensorflowlite_module.cpp +++ b/plugins/wasmedge_tensorflowlite/tensorflowlite_module.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "tensorflowlite_module.h" #include "tensorflowlite_func.h" diff --git a/plugins/wasmedge_tensorflowlite/tensorflowlite_module.h b/plugins/wasmedge_tensorflowlite/tensorflowlite_module.h index a93545bb6c0d..1f5161b7d342 100644 --- a/plugins/wasmedge_tensorflowlite/tensorflowlite_module.h +++ b/plugins/wasmedge_tensorflowlite/tensorflowlite_module.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_zlib/CMakeLists.txt b/plugins/wasmedge_zlib/CMakeLists.txt index 30fa7d733d40..d75e577c25e4 100644 --- a/plugins/wasmedge_zlib/CMakeLists.txt +++ b/plugins/wasmedge_zlib/CMakeLists.txt @@ -1,19 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC -# Don't reply on System zlib -# find_package(ZLIB REQUIRED) +find_package(ZLIB REQUIRED) set(ZLIB_COMPAT ON) -set(ZLIBNG_ENABLE_TESTS OFF) - -FetchContent_Declare( - zlib - GIT_REPOSITORY "https://github.com/zlib-ng/zlib-ng.git" - GIT_TAG 2.0.7 - GIT_PROGRESS TRUE -) -FetchContent_MakeAvailable(zlib) wasmedge_add_library(wasmedgePluginWasmEdgeZlib SHARED @@ -37,14 +27,17 @@ if(WASMEDGE_LINK_PLUGINS_STATIC) target_link_libraries(wasmedgePluginWasmEdgeZlib PRIVATE wasmedgeCAPI - zlib + z ) else() target_link_libraries(wasmedgePluginWasmEdgeZlib PRIVATE wasmedge_shared - zlib + z ) endif() -install(TARGETS wasmedgePluginWasmEdgeZlib DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge) +install( + TARGETS wasmedgePluginWasmEdgeZlib + DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge +) diff --git a/plugins/wasmedge_zlib/zlibbase.h b/plugins/wasmedge_zlib/zlibbase.h index 11640a72d636..63b9a16e29f9 100644 --- a/plugins/wasmedge_zlib/zlibbase.h +++ b/plugins/wasmedge_zlib/zlibbase.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_zlib/zlibenv.cpp b/plugins/wasmedge_zlib/zlibenv.cpp index 45654a288e4b..f3e8eaa408a9 100644 --- a/plugins/wasmedge_zlib/zlibenv.cpp +++ b/plugins/wasmedge_zlib/zlibenv.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "zlibenv.h" #include "zlibmodule.h" @@ -31,9 +31,8 @@ Plugin::Plugin::PluginDescriptor Descriptor{ .AddOptions = nullptr, }; -} // namespace - -Plugin::PluginRegister WasmEdgeZlibEnvironment::Register(&Descriptor); +EXPORT_GET_DESCRIPTOR(Descriptor) +} // namespace } // namespace Host } // namespace WasmEdge diff --git a/plugins/wasmedge_zlib/zlibenv.h b/plugins/wasmedge_zlib/zlibenv.h index 97781a573b63..a677d98adb90 100644 --- a/plugins/wasmedge_zlib/zlibenv.h +++ b/plugins/wasmedge_zlib/zlibenv.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once @@ -42,9 +42,8 @@ struct WasmZStream { /* [Wasm Offset] private data object passed to zalloc and zfree */ uint32_t Opaque; - /* best guess about the data type: binary or text - for deflate, or the decoding state - for inflate */ + /* best guess about the data type: binary or text for deflate, or the decoding + state for inflate */ int32_t DataType; /* Adler-32 or CRC-32 value of the uncompressed data */ @@ -55,8 +54,8 @@ struct WasmZStream { static_assert(sizeof(WasmZStream) == 56, "WasmZStream should be 56 bytes"); /* - gzip header information passed to and from zlib routines. See RFC 1952 - for more details on the meanings of these fields. + gzip header information passed to and from zlib routines. See RFC 1952 for + more details on the meanings of these fields. */ struct WasmGZHeader { int32_t Text; /* true if compressed data believed to be text */ @@ -72,7 +71,7 @@ struct WasmGZHeader { uint32_t CommMax; /* space at comment (only when reading header) */ int32_t HCRC; /* true if there was or will be a header crc */ int32_t Done; /* true when done reading gzip header (not used - when writing a gzip file) */ + when writing a gzip file) */ }; static_assert(sizeof(WasmGZHeader) == 52, "WasmGZHeader should be 52 bytes"); @@ -91,9 +90,6 @@ class WasmEdgeZlibEnvironment { std::unordered_map<uint32_t, std::unique_ptr<z_stream>> ZStreamMap; std::map<uint32_t, std::unique_ptr<GZFile>, std::greater<uint32_t>> GZFileMap; std::unordered_map<uint32_t, GZStore> GZHeaderMap; - - /// Initial Configurations - static Plugin::PluginRegister Register; }; } // namespace Host diff --git a/plugins/wasmedge_zlib/zlibfunc.cpp b/plugins/wasmedge_zlib/zlibfunc.cpp index 04aeac05af0c..e2f7d3efb6cd 100644 --- a/plugins/wasmedge_zlib/zlibfunc.cpp +++ b/plugins/wasmedge_zlib/zlibfunc.cpp @@ -1,10 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "zlibfunc.h" #include <cstring> -#include <iostream> namespace WasmEdge { namespace Host { diff --git a/plugins/wasmedge_zlib/zlibfunc.h b/plugins/wasmedge_zlib/zlibfunc.h index d276462d05c7..b7ca1f05d251 100644 --- a/plugins/wasmedge_zlib/zlibfunc.h +++ b/plugins/wasmedge_zlib/zlibfunc.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/plugins/wasmedge_zlib/zlibmodule.cpp b/plugins/wasmedge_zlib/zlibmodule.cpp index ecd2fd6e969d..4e39eaa64fe8 100644 --- a/plugins/wasmedge_zlib/zlibmodule.cpp +++ b/plugins/wasmedge_zlib/zlibmodule.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "zlibmodule.h" #include "zlibfunc.h" diff --git a/plugins/wasmedge_zlib/zlibmodule.h b/plugins/wasmedge_zlib/zlibmodule.h index e502993c73f2..dd595124da6c 100644 --- a/plugins/wasmedge_zlib/zlibmodule.h +++ b/plugins/wasmedge_zlib/zlibmodule.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 73405ee189fb..831a5c8dce3d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC find_package(GTest QUIET) if(GTest_FOUND) @@ -8,60 +8,41 @@ else() FetchContent_Declare( GTest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.11.0 - GIT_SHALLOW TRUE + GIT_TAG v1.15.2 + GIT_SHALLOW TRUE ) set(BUILD_GMOCK OFF CACHE BOOL "Builds the googlemock subproject" FORCE) set(INSTALL_GTEST OFF CACHE BOOL "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" FORCE) - get_property( - compile_options - DIRECTORY - PROPERTY COMPILE_OPTIONS - ) if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - set_property( - DIRECTORY - APPEND - PROPERTY COMPILE_OPTIONS - ${WASMEDGE_CFLAGS} + add_compile_options( + ${WASMEDGE_CFLAGS} ) else() - set_property( - DIRECTORY - APPEND - PROPERTY COMPILE_OPTIONS + add_compile_options( ${WASMEDGE_CFLAGS} -Wno-language-extension-token -Wno-missing-noreturn -Wno-shift-sign-overflow -Wno-undef -Wno-unused-member-function - -Wno-zero-as-null-pointer-constant + $<$<COMPILE_LANGUAGE:CXX>:-Wno-zero-as-null-pointer-constant> -Wno-deprecated ) if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - set_property( - DIRECTORY - APPEND - PROPERTY COMPILE_OPTIONS + add_compile_options( -Wno-suggest-destructor-override - -Wno-suggest-override + $<$<COMPILE_LANGUAGE:CXX>:-Wno-suggest-override> ) endif() endif() FetchContent_MakeAvailable(GTest) - set_property( - DIRECTORY - PROPERTY COMPILE_OPTIONS - ${compile_options} - ) - unset(compile_options) set(GTEST_BOTH_LIBRARIES "gtest;gtest_main") endif() -if (WASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) add_subdirectory(aot) + add_subdirectory(llvm) add_subdirectory(mixcall) endif() add_subdirectory(common) @@ -69,11 +50,11 @@ add_subdirectory(spec) add_subdirectory(loader) add_subdirectory(executor) add_subdirectory(thread) -if (WASMEDGE_BUILD_SHARED_LIB) +if(WASMEDGE_BUILD_SHARED_LIB) add_subdirectory(api) add_subdirectory(externref) endif() -if (WASMEDGE_BUILD_PLUGINS) +if(WASMEDGE_BUILD_PLUGINS) add_subdirectory(plugins) endif() add_subdirectory(host/socket) @@ -92,15 +73,15 @@ if(WASMEDGE_BUILD_COVERAGE) DEPENDENCIES wasmedge BASE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" EXCLUDE - "${PROJECT_SOURCE_DIR}/thirdparty/*" - "${PROJECT_SOURCE_DIR}/test/*" - ) + "${PROJECT_SOURCE_DIR}/thirdparty/*" + "${PROJECT_SOURCE_DIR}/test/*" + ) setup_target_for_coverage_gcovr_xml( NAME codecov EXECUTABLE ctest -j ${PROCESSOR_COUNT} DEPENDENCIES wasmedge EXCLUDE - "${PROJECT_SOURCE_DIR}/thirdparty/*" - "${PROJECT_SOURCE_DIR}/test/*" - ) + "${PROJECT_SOURCE_DIR}/thirdparty/*" + "${PROJECT_SOURCE_DIR}/test/*" + ) endif() diff --git a/test/aot/AOTBlake3Test.cpp b/test/aot/AOTBlake3Test.cpp index 3827d03637ef..9b354e9004b4 100644 --- a/test/aot/AOTBlake3Test.cpp +++ b/test/aot/AOTBlake3Test.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/aot/AOTBlake3Test.cpp - blake3 hash unit tests ------===// // diff --git a/test/aot/AOTCacheTest.cpp b/test/aot/AOTCacheTest.cpp index be81b9a0573a..d6da7df307e1 100644 --- a/test/aot/AOTCacheTest.cpp +++ b/test/aot/AOTCacheTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/aot/AOTCacheTest.cpp - aot cache unit tests ---------===// // diff --git a/test/aot/CMakeLists.txt b/test/aot/CMakeLists.txt index b49c48042a7d..699f7c6070be 100644 --- a/test/aot/CMakeLists.txt +++ b/test/aot/CMakeLists.txt @@ -1,21 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC - -wasmedge_add_executable(wasmedgeAOTCoreTests - AOTcoreTest.cpp -) - -add_test(wasmedgeAOTCoreTests wasmedgeAOTCoreTests) - -target_link_libraries(wasmedgeAOTCoreTests - PRIVATE - std::filesystem - ${GTEST_BOTH_LIBRARIES} - wasmedgeTestSpec - wasmedgeLoader - wasmedgeAOT - wasmedgeVM -) +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeAOTCacheTests AOTCacheTest.cpp diff --git a/test/api/APIAOTCoreTest.cpp b/test/api/APIAOTCoreTest.cpp index ac66bed12d09..cf2f3c328307 100644 --- a/test/api/APIAOTCoreTest.cpp +++ b/test/api/APIAOTCoreTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/api/APIAOTVMCoreTest.cpp - WasmEdge C API AOT core tests// // diff --git a/test/api/APIStepsCoreTest.cpp b/test/api/APIStepsCoreTest.cpp index ca7b0234d447..13ec02e3b491 100644 --- a/test/api/APIStepsCoreTest.cpp +++ b/test/api/APIStepsCoreTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/api/APIStepsCoreTest.cpp - WasmEdge C API core tests ===// // @@ -236,8 +236,9 @@ TEST(AsyncInvoke, InterruptTest) { ASSERT_NE(Store, nullptr); WasmEdge_ASTModuleContext *AST = nullptr; - ASSERT_TRUE(WasmEdge_ResultOK(WasmEdge_LoaderParseFromBuffer( - Loader, &AST, AsyncWasm.data(), static_cast<uint32_t>(AsyncWasm.size())))); + ASSERT_TRUE(WasmEdge_ResultOK( + WasmEdge_LoaderParseFromBuffer(Loader, &AST, AsyncWasm.data(), + static_cast<uint32_t>(AsyncWasm.size())))); ASSERT_NE(AST, nullptr); ASSERT_TRUE(WasmEdge_ResultOK(WasmEdge_ValidatorValidate(Validator, AST))); WasmEdge_ModuleInstanceContext *Module = nullptr; diff --git a/test/api/APIUnitTest.cpp b/test/api/APIUnitTest.cpp index 289671cc7475..d16fb3e611db 100644 --- a/test/api/APIUnitTest.cpp +++ b/test/api/APIUnitTest.cpp @@ -1,14 +1,16 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #include "common/filesystem.h" +#include "experimental/span.hpp" #include "wasmedge/wasmedge.h" #include <algorithm> #include <cstdint> #include <cstdlib> #include <cstring> +#include <fmt/format.h> #include <fstream> #include <gtest/gtest.h> #include <string> @@ -19,6 +21,8 @@ #include "system/winapi.h" #endif +using namespace std::literals; + namespace { std::vector<uint8_t> TestWasm = { @@ -91,86 +95,90 @@ std::vector<uint8_t> TestWasm = { 0xd, 0x2, 0x0, 0x4, 0x67, 0x2d, 0x6d, 0x69, 0x1, 0x4, 0x67, 0x2d, 0x63, 0x66}; std::vector<uint8_t> ImportWasm = { - 0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x1d, 0x5, 0x60, - 0x0, 0x1, 0x7f, 0x60, 0x2, 0x6f, 0x7f, 0x1, 0x7f, 0x60, 0x2, 0x7f, - 0x7f, 0x1, 0x7f, 0x60, 0x2, 0x7f, 0x7f, 0x2, 0x7f, 0x7f, 0x60, 0x1, - 0x7f, 0x1, 0x7f, 0x2, 0xfb, 0x1, 0xe, 0x6, 0x65, 0x78, 0x74, 0x65, - 0x72, 0x6e, 0x8, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x61, 0x64, 0x64, 0x0, - 0x1, 0x6, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x8, 0x66, 0x75, 0x6e, - 0x63, 0x2d, 0x73, 0x75, 0x62, 0x0, 0x1, 0x6, 0x65, 0x78, 0x74, 0x65, - 0x72, 0x6e, 0x8, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x6d, 0x75, 0x6c, 0x0, - 0x1, 0x6, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x8, 0x66, 0x75, 0x6e, - 0x63, 0x2d, 0x64, 0x69, 0x76, 0x0, 0x1, 0x6, 0x65, 0x78, 0x74, 0x65, - 0x72, 0x6e, 0x9, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x74, 0x65, 0x72, 0x6d, - 0x0, 0x0, 0x6, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x9, 0x66, 0x75, - 0x6e, 0x63, 0x2d, 0x66, 0x61, 0x69, 0x6c, 0x0, 0x0, 0x5, 0x64, 0x75, - 0x6d, 0x6d, 0x79, 0x8, 0x67, 0x6c, 0x6f, 0x62, 0x2d, 0x69, 0x33, 0x32, - 0x3, 0x7f, 0x1, 0x5, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x8, 0x67, 0x6c, - 0x6f, 0x62, 0x2d, 0x69, 0x36, 0x34, 0x3, 0x7e, 0x0, 0x5, 0x64, 0x75, - 0x6d, 0x6d, 0x79, 0x8, 0x67, 0x6c, 0x6f, 0x62, 0x2d, 0x66, 0x33, 0x32, - 0x3, 0x7d, 0x1, 0x5, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x8, 0x67, 0x6c, - 0x6f, 0x62, 0x2d, 0x66, 0x36, 0x34, 0x3, 0x7c, 0x0, 0x5, 0x64, 0x75, - 0x6d, 0x6d, 0x79, 0x8, 0x74, 0x61, 0x62, 0x2d, 0x66, 0x75, 0x6e, 0x63, - 0x1, 0x70, 0x1, 0xa, 0x14, 0x5, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x7, - 0x74, 0x61, 0x62, 0x2d, 0x65, 0x78, 0x74, 0x1, 0x6f, 0x1, 0xa, 0x1e, - 0x5, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x4, 0x6d, 0x65, 0x6d, 0x31, 0x2, - 0x1, 0x1, 0x3, 0x5, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x4, 0x6d, 0x65, - 0x6d, 0x32, 0x2, 0x0, 0x2, 0x3, 0xc, 0xb, 0x0, 0x0, 0x0, 0x0, - 0x2, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x7, 0x2, 0x70, 0x0, - 0xa, 0x6f, 0x0, 0xa, 0x5, 0x4, 0x1, 0x1, 0x1, 0x3, 0x6, 0xf, - 0x2, 0x7f, 0x1, 0x41, 0x8e, 0x1, 0xb, 0x7d, 0x0, 0x43, 0xae, 0x47, - 0x45, 0x44, 0xb, 0x7, 0xcd, 0x1, 0x10, 0x6, 0x66, 0x75, 0x6e, 0x63, - 0x2d, 0x31, 0x0, 0x6, 0x6, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x32, 0x0, - 0x7, 0x6, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x33, 0x0, 0x8, 0x6, 0x66, - 0x75, 0x6e, 0x63, 0x2d, 0x34, 0x0, 0x9, 0x8, 0x66, 0x75, 0x6e, 0x63, - 0x2d, 0x61, 0x64, 0x64, 0x0, 0xa, 0xa, 0x66, 0x75, 0x6e, 0x63, 0x2d, - 0x6d, 0x75, 0x6c, 0x2d, 0x32, 0x0, 0xb, 0x12, 0x66, 0x75, 0x6e, 0x63, - 0x2d, 0x63, 0x61, 0x6c, 0x6c, 0x2d, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x0, 0xc, 0xd, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x68, 0x6f, - 0x73, 0x74, 0x2d, 0x61, 0x64, 0x64, 0x0, 0xd, 0xd, 0x66, 0x75, 0x6e, - 0x63, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x73, 0x75, 0x62, 0x0, 0xe, - 0xd, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x6d, - 0x75, 0x6c, 0x0, 0xf, 0xd, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x68, 0x6f, - 0x73, 0x74, 0x2d, 0x64, 0x69, 0x76, 0x0, 0x10, 0x8, 0x74, 0x61, 0x62, - 0x2d, 0x66, 0x75, 0x6e, 0x63, 0x1, 0x2, 0x7, 0x74, 0x61, 0x62, 0x2d, - 0x65, 0x78, 0x74, 0x1, 0x3, 0x3, 0x6d, 0x65, 0x6d, 0x2, 0x2, 0xc, - 0x67, 0x6c, 0x6f, 0x62, 0x2d, 0x6d, 0x75, 0x74, 0x2d, 0x69, 0x33, 0x32, - 0x3, 0x4, 0xe, 0x67, 0x6c, 0x6f, 0x62, 0x2d, 0x63, 0x6f, 0x6e, 0x73, - 0x74, 0x2d, 0x66, 0x33, 0x32, 0x3, 0x5, 0x9, 0xc, 0x1, 0x2, 0x2, - 0x41, 0x2, 0xb, 0x0, 0x4, 0x6, 0x7, 0x8, 0x9, 0xa, 0x5e, 0xb, - 0x4, 0x0, 0x41, 0x1, 0xb, 0x4, 0x0, 0x41, 0x2, 0xb, 0x4, 0x0, - 0x41, 0x3, 0xb, 0x4, 0x0, 0x41, 0x4, 0xb, 0x7, 0x0, 0x20, 0x0, - 0x20, 0x1, 0x6a, 0xb, 0xc, 0x0, 0x20, 0x0, 0x41, 0x2, 0x6c, 0x20, - 0x1, 0x41, 0x2, 0x6c, 0xb, 0x7, 0x0, 0x20, 0x0, 0x11, 0x0, 0x2, - 0xb, 0xa, 0x0, 0x41, 0x0, 0x25, 0x3, 0x20, 0x0, 0x10, 0x0, 0xb, - 0xa, 0x0, 0x41, 0x1, 0x25, 0x3, 0x20, 0x0, 0x10, 0x1, 0xb, 0xa, - 0x0, 0x41, 0x2, 0x25, 0x3, 0x20, 0x0, 0x10, 0x2, 0xb, 0xa, 0x0, - 0x41, 0x3, 0x25, 0x3, 0x20, 0x0, 0x10, 0x3, 0xb, 0xb, 0x10, 0x1, - 0x0, 0x41, 0xa, 0xb, 0xa, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, - 0x7, 0x8, 0x9, 0x0, 0x8f, 0x2, 0x4, 0x6e, 0x61, 0x6d, 0x65, 0x1, - 0x8d, 0x1, 0x11, 0x0, 0x7, 0x65, 0x2d, 0x66, 0x2d, 0x61, 0x64, 0x64, - 0x1, 0x7, 0x65, 0x2d, 0x66, 0x2d, 0x73, 0x75, 0x62, 0x2, 0x7, 0x65, - 0x2d, 0x66, 0x2d, 0x6d, 0x75, 0x6c, 0x3, 0x7, 0x65, 0x2d, 0x66, 0x2d, - 0x64, 0x69, 0x76, 0x4, 0x8, 0x65, 0x2d, 0x66, 0x2d, 0x74, 0x65, 0x72, - 0x6d, 0x5, 0x8, 0x65, 0x2d, 0x66, 0x2d, 0x66, 0x61, 0x69, 0x6c, 0x6, - 0x3, 0x66, 0x2d, 0x31, 0x7, 0x3, 0x66, 0x2d, 0x32, 0x8, 0x3, 0x66, - 0x2d, 0x33, 0x9, 0x3, 0x66, 0x2d, 0x34, 0xa, 0x5, 0x66, 0x2d, 0x61, - 0x64, 0x64, 0xb, 0x7, 0x66, 0x2d, 0x6d, 0x75, 0x6c, 0x2d, 0x32, 0xc, - 0xa, 0x66, 0x2d, 0x63, 0x61, 0x6c, 0x6c, 0x2d, 0x69, 0x6e, 0x64, 0xd, - 0x7, 0x66, 0x2d, 0x65, 0x2d, 0x61, 0x64, 0x64, 0xe, 0x7, 0x66, 0x2d, - 0x65, 0x2d, 0x73, 0x75, 0x62, 0xf, 0x7, 0x66, 0x2d, 0x65, 0x2d, 0x6d, - 0x75, 0x6c, 0x10, 0x7, 0x66, 0x2d, 0x65, 0x2d, 0x64, 0x69, 0x76, 0x2, - 0x45, 0x11, 0x0, 0x2, 0x0, 0x0, 0x1, 0x0, 0x1, 0x2, 0x0, 0x0, - 0x1, 0x0, 0x2, 0x2, 0x0, 0x0, 0x1, 0x0, 0x3, 0x2, 0x0, 0x0, - 0x1, 0x0, 0x4, 0x0, 0x5, 0x0, 0x6, 0x0, 0x7, 0x0, 0x8, 0x0, - 0x9, 0x0, 0xa, 0x2, 0x0, 0x0, 0x1, 0x0, 0xb, 0x2, 0x0, 0x0, - 0x1, 0x0, 0xc, 0x1, 0x0, 0x0, 0xd, 0x1, 0x0, 0x0, 0xe, 0x1, - 0x0, 0x0, 0xf, 0x1, 0x0, 0x0, 0x10, 0x1, 0x0, 0x0, 0x4, 0xf, - 0x2, 0x0, 0x5, 0x74, 0x79, 0x70, 0x65, 0x30, 0x1, 0x5, 0x74, 0x79, - 0x70, 0x65, 0x31, 0x5, 0xb, 0x2, 0x2, 0x3, 0x74, 0x2d, 0x66, 0x3, - 0x3, 0x74, 0x2d, 0x65, 0x6, 0x4, 0x1, 0x0, 0x1, 0x6d, 0x7, 0xd, - 0x2, 0x4, 0x4, 0x67, 0x2d, 0x6d, 0x69, 0x5, 0x4, 0x67, 0x2d, 0x63, - 0x66}; + 0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x34, 0xa, 0x60, + 0x0, 0x1, 0x7f, 0x60, 0x2, 0x6f, 0x7f, 0x1, 0x7f, 0x60, 0x1, 0x7c, + 0x0, 0x60, 0x2, 0x7c, 0x7e, 0x0, 0x60, 0x0, 0x0, 0x60, 0x4, 0x7f, + 0x7e, 0x7d, 0x7c, 0x0, 0x60, 0x1, 0x7d, 0x0, 0x60, 0x2, 0x7f, 0x7f, + 0x1, 0x7f, 0x60, 0x2, 0x7f, 0x7f, 0x2, 0x7f, 0x7f, 0x60, 0x1, 0x7f, + 0x1, 0x7f, 0x2, 0xa5, 0x2, 0x11, 0x6, 0x65, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x8, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x61, 0x64, 0x64, 0x0, 0x1, + 0x6, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x8, 0x66, 0x75, 0x6e, 0x63, + 0x2d, 0x73, 0x75, 0x62, 0x0, 0x1, 0x6, 0x65, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x8, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x6d, 0x75, 0x6c, 0x0, 0x1, + 0x6, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x8, 0x66, 0x75, 0x6e, 0x63, + 0x2d, 0x64, 0x69, 0x76, 0x0, 0x1, 0x6, 0x65, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x9, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x74, 0x65, 0x72, 0x6d, 0x0, + 0x0, 0x6, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x9, 0x66, 0x75, 0x6e, + 0x63, 0x2d, 0x66, 0x61, 0x69, 0x6c, 0x0, 0x0, 0x5, 0x64, 0x75, 0x6d, + 0x6d, 0x79, 0x8, 0x67, 0x6c, 0x6f, 0x62, 0x2d, 0x69, 0x33, 0x32, 0x3, + 0x7f, 0x1, 0x5, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x8, 0x67, 0x6c, 0x6f, + 0x62, 0x2d, 0x69, 0x36, 0x34, 0x3, 0x7e, 0x0, 0x5, 0x64, 0x75, 0x6d, + 0x6d, 0x79, 0x8, 0x67, 0x6c, 0x6f, 0x62, 0x2d, 0x66, 0x33, 0x32, 0x3, + 0x7d, 0x1, 0x5, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x8, 0x67, 0x6c, 0x6f, + 0x62, 0x2d, 0x66, 0x36, 0x34, 0x3, 0x7c, 0x0, 0x5, 0x64, 0x75, 0x6d, + 0x6d, 0x79, 0x8, 0x74, 0x61, 0x62, 0x2d, 0x66, 0x75, 0x6e, 0x63, 0x1, + 0x70, 0x1, 0xa, 0x14, 0x5, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x7, 0x74, + 0x61, 0x62, 0x2d, 0x65, 0x78, 0x74, 0x1, 0x6f, 0x1, 0xa, 0x1e, 0x5, + 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x4, 0x6d, 0x65, 0x6d, 0x31, 0x2, 0x1, + 0x1, 0x3, 0x5, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x4, 0x6d, 0x65, 0x6d, + 0x32, 0x2, 0x0, 0x2, 0x5, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x4, 0x74, + 0x61, 0x67, 0x31, 0x4, 0x0, 0x2, 0x5, 0x64, 0x75, 0x6d, 0x6d, 0x79, + 0x4, 0x74, 0x61, 0x67, 0x32, 0x4, 0x0, 0x3, 0x5, 0x64, 0x75, 0x6d, + 0x6d, 0x79, 0x4, 0x74, 0x61, 0x67, 0x33, 0x4, 0x0, 0x4, 0x3, 0xc, + 0xb, 0x0, 0x0, 0x0, 0x0, 0x7, 0x8, 0x9, 0x9, 0x9, 0x9, 0x9, + 0x4, 0x7, 0x2, 0x70, 0x0, 0xa, 0x6f, 0x0, 0xa, 0x5, 0x4, 0x1, + 0x1, 0x1, 0x3, 0xd, 0x7, 0x3, 0x0, 0x5, 0x0, 0x4, 0x0, 0x6, + 0x6, 0xf, 0x2, 0x7f, 0x1, 0x41, 0x8e, 0x1, 0xb, 0x7d, 0x0, 0x43, + 0xae, 0x47, 0x45, 0x44, 0xb, 0x7, 0xe5, 0x1, 0x13, 0x6, 0x66, 0x75, + 0x6e, 0x63, 0x2d, 0x31, 0x0, 0x6, 0x6, 0x66, 0x75, 0x6e, 0x63, 0x2d, + 0x32, 0x0, 0x7, 0x6, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x33, 0x0, 0x8, + 0x6, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x34, 0x0, 0x9, 0x8, 0x66, 0x75, + 0x6e, 0x63, 0x2d, 0x61, 0x64, 0x64, 0x0, 0xa, 0xa, 0x66, 0x75, 0x6e, + 0x63, 0x2d, 0x6d, 0x75, 0x6c, 0x2d, 0x32, 0x0, 0xb, 0x12, 0x66, 0x75, + 0x6e, 0x63, 0x2d, 0x63, 0x61, 0x6c, 0x6c, 0x2d, 0x69, 0x6e, 0x64, 0x69, + 0x72, 0x65, 0x63, 0x74, 0x0, 0xc, 0xd, 0x66, 0x75, 0x6e, 0x63, 0x2d, + 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x61, 0x64, 0x64, 0x0, 0xd, 0xd, 0x66, + 0x75, 0x6e, 0x63, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x73, 0x75, 0x62, + 0x0, 0xe, 0xd, 0x66, 0x75, 0x6e, 0x63, 0x2d, 0x68, 0x6f, 0x73, 0x74, + 0x2d, 0x6d, 0x75, 0x6c, 0x0, 0xf, 0xd, 0x66, 0x75, 0x6e, 0x63, 0x2d, + 0x68, 0x6f, 0x73, 0x74, 0x2d, 0x64, 0x69, 0x76, 0x0, 0x10, 0x8, 0x74, + 0x61, 0x62, 0x2d, 0x66, 0x75, 0x6e, 0x63, 0x1, 0x2, 0x7, 0x74, 0x61, + 0x62, 0x2d, 0x65, 0x78, 0x74, 0x1, 0x3, 0x3, 0x6d, 0x65, 0x6d, 0x2, + 0x2, 0x5, 0x74, 0x61, 0x67, 0x2d, 0x31, 0x4, 0x3, 0x5, 0x74, 0x61, + 0x67, 0x2d, 0x32, 0x4, 0x4, 0x5, 0x74, 0x61, 0x67, 0x2d, 0x33, 0x4, + 0x5, 0xc, 0x67, 0x6c, 0x6f, 0x62, 0x2d, 0x6d, 0x75, 0x74, 0x2d, 0x69, + 0x33, 0x32, 0x3, 0x4, 0xe, 0x67, 0x6c, 0x6f, 0x62, 0x2d, 0x63, 0x6f, + 0x6e, 0x73, 0x74, 0x2d, 0x66, 0x33, 0x32, 0x3, 0x5, 0x9, 0xc, 0x1, + 0x2, 0x2, 0x41, 0x2, 0xb, 0x0, 0x4, 0x6, 0x7, 0x8, 0x9, 0xa, + 0x5e, 0xb, 0x4, 0x0, 0x41, 0x1, 0xb, 0x4, 0x0, 0x41, 0x2, 0xb, + 0x4, 0x0, 0x41, 0x3, 0xb, 0x4, 0x0, 0x41, 0x4, 0xb, 0x7, 0x0, + 0x20, 0x0, 0x20, 0x1, 0x6a, 0xb, 0xc, 0x0, 0x20, 0x0, 0x41, 0x2, + 0x6c, 0x20, 0x1, 0x41, 0x2, 0x6c, 0xb, 0x7, 0x0, 0x20, 0x0, 0x11, + 0x0, 0x2, 0xb, 0xa, 0x0, 0x41, 0x0, 0x25, 0x3, 0x20, 0x0, 0x10, + 0x0, 0xb, 0xa, 0x0, 0x41, 0x1, 0x25, 0x3, 0x20, 0x0, 0x10, 0x1, + 0xb, 0xa, 0x0, 0x41, 0x2, 0x25, 0x3, 0x20, 0x0, 0x10, 0x2, 0xb, + 0xa, 0x0, 0x41, 0x3, 0x25, 0x3, 0x20, 0x0, 0x10, 0x3, 0xb, 0xb, + 0x10, 0x1, 0x0, 0x41, 0xa, 0xb, 0xa, 0x0, 0x1, 0x2, 0x3, 0x4, + 0x5, 0x6, 0x7, 0x8, 0x9, 0x0, 0xe0, 0x1, 0x4, 0x6e, 0x61, 0x6d, + 0x65, 0x1, 0x8d, 0x1, 0x11, 0x0, 0x7, 0x65, 0x2d, 0x66, 0x2d, 0x61, + 0x64, 0x64, 0x1, 0x7, 0x65, 0x2d, 0x66, 0x2d, 0x73, 0x75, 0x62, 0x2, + 0x7, 0x65, 0x2d, 0x66, 0x2d, 0x6d, 0x75, 0x6c, 0x3, 0x7, 0x65, 0x2d, + 0x66, 0x2d, 0x64, 0x69, 0x76, 0x4, 0x8, 0x65, 0x2d, 0x66, 0x2d, 0x74, + 0x65, 0x72, 0x6d, 0x5, 0x8, 0x65, 0x2d, 0x66, 0x2d, 0x66, 0x61, 0x69, + 0x6c, 0x6, 0x3, 0x66, 0x2d, 0x31, 0x7, 0x3, 0x66, 0x2d, 0x32, 0x8, + 0x3, 0x66, 0x2d, 0x33, 0x9, 0x3, 0x66, 0x2d, 0x34, 0xa, 0x5, 0x66, + 0x2d, 0x61, 0x64, 0x64, 0xb, 0x7, 0x66, 0x2d, 0x6d, 0x75, 0x6c, 0x2d, + 0x32, 0xc, 0xa, 0x66, 0x2d, 0x63, 0x61, 0x6c, 0x6c, 0x2d, 0x69, 0x6e, + 0x64, 0xd, 0x7, 0x66, 0x2d, 0x65, 0x2d, 0x61, 0x64, 0x64, 0xe, 0x7, + 0x66, 0x2d, 0x65, 0x2d, 0x73, 0x75, 0x62, 0xf, 0x7, 0x66, 0x2d, 0x65, + 0x2d, 0x6d, 0x75, 0x6c, 0x10, 0x7, 0x66, 0x2d, 0x65, 0x2d, 0x64, 0x69, + 0x76, 0x4, 0xf, 0x2, 0x0, 0x5, 0x74, 0x79, 0x70, 0x65, 0x30, 0x1, + 0x5, 0x74, 0x79, 0x70, 0x65, 0x31, 0x5, 0xb, 0x2, 0x2, 0x3, 0x74, + 0x2d, 0x66, 0x3, 0x3, 0x74, 0x2d, 0x65, 0x6, 0x4, 0x1, 0x2, 0x1, + 0x6d, 0x7, 0xd, 0x2, 0x4, 0x4, 0x67, 0x2d, 0x6d, 0x69, 0x5, 0x4, + 0x67, 0x2d, 0x63, 0x66, 0xb, 0x16, 0x3, 0x3, 0x5, 0x74, 0x61, 0x67, + 0x2d, 0x31, 0x4, 0x5, 0x74, 0x61, 0x67, 0x2d, 0x32, 0x5, 0x5, 0x74, + 0x61, 0x67, 0x2d, 0x33}; std::vector<uint8_t> FibonacciWasm = { 0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x6, 0x1, @@ -215,11 +223,10 @@ char *Preopens[] = {&PreopensVec[0], &PreopensVec[12], &PreopensVec[21], &PreopensVec[32], &PreopensVec[49]}; char TPath[] = "apiTestData/test.wasm"; -void HexToFile(std::vector<uint8_t> &Wasm, const char *Path) { +void HexToFile(cxx20::span<const uint8_t> Wasm, const char *Path) { std::ofstream TFile(std::filesystem::u8path(Path), std::ios_base::binary); - for (auto &Hex : Wasm) { - TFile << Hex; - } + TFile.write(reinterpret_cast<const char *>(Wasm.data()), + static_cast<std::streamsize>(Wasm.size())); TFile.close(); } @@ -459,7 +466,8 @@ bool isErrMatch(WasmEdge_ErrCategory ErrCate, uint32_t Code, } TEST(APICoreTest, Version) { - EXPECT_EQ(std::string(WASMEDGE_VERSION), std::string(WasmEdge_VersionGet())); + EXPECT_EQ(std::string_view(WASMEDGE_VERSION), + std::string_view(WasmEdge_VersionGet())); EXPECT_EQ(static_cast<uint32_t>(WASMEDGE_VERSION_MAJOR), WasmEdge_VersionGetMajor()); EXPECT_EQ(static_cast<uint32_t>(WASMEDGE_VERSION_MINOR), @@ -811,7 +819,10 @@ TEST(APICoreTest, ImportType) { const WasmEdge_ImportTypeContext *ImpTypes[20]; WasmEdge_Limit Lim; WasmEdge_String Name; - WasmEdge_LoaderContext *Loader = WasmEdge_LoaderCreate(nullptr); + WasmEdge_ConfigureContext *Conf = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddProposal(Conf, WasmEdge_Proposal_ExceptionHandling); + WasmEdge_LoaderContext *Loader = WasmEdge_LoaderCreate(Conf); + WasmEdge_ConfigureDelete(Conf); // Load AST module from buffer EXPECT_TRUE(WasmEdge_ResultOK(WasmEdge_LoaderParseFromBytes( @@ -822,97 +833,115 @@ TEST(APICoreTest, ImportType) { // AST list imports EXPECT_EQ(WasmEdge_ASTModuleListImportsLength(nullptr), 0U); - EXPECT_EQ(WasmEdge_ASTModuleListImportsLength(Mod), 14U); + EXPECT_EQ(WasmEdge_ASTModuleListImportsLength(Mod), 17U); EXPECT_EQ(WasmEdge_ASTModuleListImports(nullptr, ImpTypes, 20), 0U); - EXPECT_EQ(WasmEdge_ASTModuleListImports(Mod, nullptr, 20), 14U); + EXPECT_EQ(WasmEdge_ASTModuleListImports(Mod, nullptr, 20), 17U); std::memset(ImpTypes, 0, sizeof(const WasmEdge_ImportTypeContext *) * 20); - EXPECT_EQ(WasmEdge_ASTModuleListImports(Mod, ImpTypes, 4), 14U); + EXPECT_EQ(WasmEdge_ASTModuleListImports(Mod, ImpTypes, 4), 17U); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[0]), WasmEdge_ExternalType_Function); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[0]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-add")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-add"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[0]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("extern")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "extern"sv); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[1]), WasmEdge_ExternalType_Function); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[1]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-sub")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-sub"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[1]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("extern")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "extern"sv); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[2]), WasmEdge_ExternalType_Function); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[2]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-mul")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-mul"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[2]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("extern")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "extern"sv); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[3]), WasmEdge_ExternalType_Function); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[3]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-div")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-div"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[3]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("extern")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "extern"sv); std::memset(ImpTypes, 0, sizeof(const WasmEdge_ImportTypeContext *) * 20); - EXPECT_EQ(WasmEdge_ASTModuleListImports(Mod, ImpTypes, 20), 14U); + EXPECT_EQ(WasmEdge_ASTModuleListImports(Mod, ImpTypes, 20), 17U); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[4]), WasmEdge_ExternalType_Function); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[4]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-term")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-term"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[4]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("extern")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "extern"sv); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[5]), WasmEdge_ExternalType_Function); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[5]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-fail")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-fail"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[5]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("extern")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "extern"sv); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[6]), WasmEdge_ExternalType_Global); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[6]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("glob-i32")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "glob-i32"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[6]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("dummy")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "dummy"sv); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[7]), WasmEdge_ExternalType_Global); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[7]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("glob-i64")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "glob-i64"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[7]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("dummy")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "dummy"sv); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[8]), WasmEdge_ExternalType_Global); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[8]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("glob-f32")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "glob-f32"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[8]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("dummy")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "dummy"sv); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[9]), WasmEdge_ExternalType_Global); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[9]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("glob-f64")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "glob-f64"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[9]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("dummy")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "dummy"sv); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[10]), WasmEdge_ExternalType_Table); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[10]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("tab-func")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "tab-func"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[10]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("dummy")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "dummy"sv); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[11]), WasmEdge_ExternalType_Table); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[11]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("tab-ext")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "tab-ext"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[11]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("dummy")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "dummy"sv); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[12]), WasmEdge_ExternalType_Memory); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[12]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("mem1")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "mem1"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[12]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("dummy")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "dummy"sv); EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[13]), WasmEdge_ExternalType_Memory); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[13]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("mem2")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "mem2"sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[13]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("dummy")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "dummy"sv); + EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[14]), + WasmEdge_ExternalType_Tag); + Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[14]); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "tag1"sv); + Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[14]); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "dummy"sv); + EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[15]), + WasmEdge_ExternalType_Tag); + Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[15]); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "tag2"sv); + Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[15]); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "dummy"sv); + EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(ImpTypes[16]), + WasmEdge_ExternalType_Tag); + Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[16]); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "tag3"sv); + Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[16]); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "dummy"sv); // Import type get external type EXPECT_EQ(WasmEdge_ImportTypeGetExternalType(nullptr), @@ -922,15 +951,15 @@ TEST(APICoreTest, ImportType) { // Import type get module name Name = WasmEdge_ImportTypeGetModuleName(nullptr); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), ""sv); Name = WasmEdge_ImportTypeGetModuleName(ImpTypes[0]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("extern")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "extern"sv); // Import type get external name Name = WasmEdge_ImportTypeGetExternalName(nullptr); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), ""sv); Name = WasmEdge_ImportTypeGetExternalName(ImpTypes[0]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-add")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-add"sv); // Import type get function type EXPECT_EQ(WasmEdge_ImportTypeGetFunctionType(nullptr, nullptr), nullptr); @@ -971,6 +1000,25 @@ TEST(APICoreTest, ImportType) { WasmEdge_ImportTypeGetMemoryType(Mod, ImpTypes[13])), Lim)); + // Import type get tag type + EXPECT_EQ(WasmEdge_ImportTypeGetTagType(nullptr, nullptr), nullptr); + EXPECT_EQ(WasmEdge_ImportTypeGetTagType(Mod, nullptr), nullptr); + EXPECT_EQ(WasmEdge_ImportTypeGetTagType(nullptr, ImpTypes[15]), nullptr); + EXPECT_EQ(WasmEdge_ImportTypeGetTagType(Mod, ImpTypes[0]), nullptr); + EXPECT_NE(WasmEdge_ImportTypeGetTagType(Mod, ImpTypes[15]), nullptr); + EXPECT_EQ(WasmEdge_TagTypeGetFunctionType(nullptr), nullptr); + EXPECT_NE(WasmEdge_TagTypeGetFunctionType( + WasmEdge_ImportTypeGetTagType(Mod, ImpTypes[15])), + nullptr); + EXPECT_EQ( + WasmEdge_FunctionTypeGetParametersLength(WasmEdge_TagTypeGetFunctionType( + WasmEdge_ImportTypeGetTagType(Mod, ImpTypes[15]))), + 2U); + EXPECT_EQ( + WasmEdge_FunctionTypeGetReturnsLength(WasmEdge_TagTypeGetFunctionType( + WasmEdge_ImportTypeGetTagType(Mod, ImpTypes[15]))), + 0U); + // Import type get global type EXPECT_EQ(WasmEdge_ImportTypeGetGlobalType(nullptr, nullptr), nullptr); EXPECT_EQ(WasmEdge_ImportTypeGetGlobalType(Mod, nullptr), nullptr); @@ -992,7 +1040,10 @@ TEST(APICoreTest, ExportType) { const WasmEdge_ExportTypeContext *ExpTypes[20]; WasmEdge_Limit Lim; WasmEdge_String Name; - WasmEdge_LoaderContext *Loader = WasmEdge_LoaderCreate(nullptr); + WasmEdge_ConfigureContext *Conf = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddProposal(Conf, WasmEdge_Proposal_ExceptionHandling); + WasmEdge_LoaderContext *Loader = WasmEdge_LoaderCreate(Conf); + WasmEdge_ConfigureDelete(Conf); // Load AST module from buffer EXPECT_TRUE(WasmEdge_ResultOK(WasmEdge_LoaderParseFromBytes( @@ -1003,90 +1054,101 @@ TEST(APICoreTest, ExportType) { // AST list exports EXPECT_EQ(WasmEdge_ASTModuleListExportsLength(nullptr), 0U); - EXPECT_EQ(WasmEdge_ASTModuleListExportsLength(Mod), 16U); + EXPECT_EQ(WasmEdge_ASTModuleListExportsLength(Mod), 19U); EXPECT_EQ(WasmEdge_ASTModuleListExports(nullptr, ExpTypes, 20), 0U); - EXPECT_EQ(WasmEdge_ASTModuleListExports(Mod, nullptr, 20), 16U); + EXPECT_EQ(WasmEdge_ASTModuleListExports(Mod, nullptr, 20), 19U); std::memset(ExpTypes, 0, sizeof(const WasmEdge_ExportTypeContext *) * 20); - EXPECT_EQ(WasmEdge_ASTModuleListExports(Mod, ExpTypes, 4), 16U); + EXPECT_EQ(WasmEdge_ASTModuleListExports(Mod, ExpTypes, 4), 19U); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[0]), WasmEdge_ExternalType_Function); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[0]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-1")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-1"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[1]), WasmEdge_ExternalType_Function); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[1]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-2")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-2"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[2]), WasmEdge_ExternalType_Function); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[2]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-3")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-3"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[3]), WasmEdge_ExternalType_Function); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[3]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-4")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-4"sv); std::memset(ExpTypes, 0, sizeof(const WasmEdge_ExportTypeContext *) * 20); - EXPECT_EQ(WasmEdge_ASTModuleListExports(Mod, ExpTypes, 20), 16U); + EXPECT_EQ(WasmEdge_ASTModuleListExports(Mod, ExpTypes, 20), 19U); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[4]), WasmEdge_ExternalType_Function); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[4]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-add")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-add"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[5]), WasmEdge_ExternalType_Function); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[5]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-mul-2")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-mul-2"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[6]), WasmEdge_ExternalType_Function); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[6]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), - std::string("func-call-indirect")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-call-indirect"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[7]), WasmEdge_ExternalType_Function); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[7]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-host-add")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-host-add"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[8]), WasmEdge_ExternalType_Function); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[8]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-host-sub")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-host-sub"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[9]), WasmEdge_ExternalType_Function); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[9]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-host-mul")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-host-mul"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[10]), WasmEdge_ExternalType_Function); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[10]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-host-div")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-host-div"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[11]), WasmEdge_ExternalType_Table); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[11]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("tab-func")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "tab-func"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[12]), WasmEdge_ExternalType_Table); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[12]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("tab-ext")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "tab-ext"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[13]), WasmEdge_ExternalType_Memory); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[13]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("mem")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "mem"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[14]), - WasmEdge_ExternalType_Global); + WasmEdge_ExternalType_Tag); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[14]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("glob-mut-i32")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "tag-1"sv); EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[15]), - WasmEdge_ExternalType_Global); + WasmEdge_ExternalType_Tag); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[15]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("glob-const-f32")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "tag-2"sv); + EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[16]), + WasmEdge_ExternalType_Tag); + Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[16]); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "tag-3"sv); + EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[17]), + WasmEdge_ExternalType_Global); + Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[17]); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "glob-mut-i32"sv); + EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[18]), + WasmEdge_ExternalType_Global); + Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[18]); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "glob-const-f32"sv); // Export type get external type EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(nullptr), WasmEdge_ExternalType_Function); - EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[15]), + EXPECT_EQ(WasmEdge_ExportTypeGetExternalType(ExpTypes[18]), WasmEdge_ExternalType_Global); // Export type get external name Name = WasmEdge_ExportTypeGetExternalName(nullptr); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), ""sv); Name = WasmEdge_ExportTypeGetExternalName(ExpTypes[0]); - EXPECT_EQ(std::string(Name.Buf, Name.Length), std::string("func-1")); + EXPECT_EQ(std::string_view(Name.Buf, Name.Length), "func-1"sv); // Export type get function type EXPECT_EQ(WasmEdge_ExportTypeGetFunctionType(nullptr, nullptr), nullptr); @@ -1127,23 +1189,42 @@ TEST(APICoreTest, ExportType) { WasmEdge_ExportTypeGetMemoryType(Mod, ExpTypes[13])), Lim)); + // Export type get tag type + EXPECT_EQ(WasmEdge_ExportTypeGetTagType(nullptr, nullptr), nullptr); + EXPECT_EQ(WasmEdge_ExportTypeGetTagType(Mod, nullptr), nullptr); + EXPECT_EQ(WasmEdge_ExportTypeGetTagType(nullptr, ExpTypes[14]), nullptr); + EXPECT_EQ(WasmEdge_ExportTypeGetTagType(Mod, ExpTypes[0]), nullptr); + EXPECT_NE(WasmEdge_ExportTypeGetTagType(Mod, ExpTypes[14]), nullptr); + EXPECT_EQ(WasmEdge_TagTypeGetFunctionType(nullptr), nullptr); + EXPECT_NE(WasmEdge_TagTypeGetFunctionType( + WasmEdge_ExportTypeGetTagType(Mod, ExpTypes[14])), + nullptr); + EXPECT_EQ( + WasmEdge_FunctionTypeGetParametersLength(WasmEdge_TagTypeGetFunctionType( + WasmEdge_ExportTypeGetTagType(Mod, ExpTypes[14]))), + 4U); + EXPECT_EQ( + WasmEdge_FunctionTypeGetReturnsLength(WasmEdge_TagTypeGetFunctionType( + WasmEdge_ExportTypeGetTagType(Mod, ExpTypes[14]))), + 0U); + // Export type get global type EXPECT_EQ(WasmEdge_ExportTypeGetGlobalType(nullptr, nullptr), nullptr); EXPECT_EQ(WasmEdge_ExportTypeGetGlobalType(Mod, nullptr), nullptr); - EXPECT_EQ(WasmEdge_ExportTypeGetGlobalType(nullptr, ExpTypes[15]), nullptr); + EXPECT_EQ(WasmEdge_ExportTypeGetGlobalType(nullptr, ExpTypes[18]), nullptr); EXPECT_EQ(WasmEdge_ExportTypeGetGlobalType(Mod, ExpTypes[0]), nullptr); - EXPECT_NE(WasmEdge_ExportTypeGetGlobalType(Mod, ExpTypes[15]), nullptr); + EXPECT_NE(WasmEdge_ExportTypeGetGlobalType(Mod, ExpTypes[18]), nullptr); EXPECT_TRUE(WasmEdge_ValTypeIsF32(WasmEdge_GlobalTypeGetValType( - WasmEdge_ExportTypeGetGlobalType(Mod, ExpTypes[15])))); + WasmEdge_ExportTypeGetGlobalType(Mod, ExpTypes[18])))); EXPECT_EQ(WasmEdge_GlobalTypeGetMutability( - WasmEdge_ExportTypeGetGlobalType(Mod, ExpTypes[15])), + WasmEdge_ExportTypeGetGlobalType(Mod, ExpTypes[18])), WasmEdge_Mutability_Const); WasmEdge_LoaderDelete(Loader); WasmEdge_ASTModuleDelete(Mod); } -#ifdef WASMEDGE_BUILD_AOT_RUNTIME +#ifdef WASMEDGE_USE_LLVM TEST(APICoreTest, Compiler) { WasmEdge_ConfigureContext *Conf = WasmEdge_ConfigureCreate(); std::ifstream OutFile; @@ -1328,7 +1409,7 @@ TEST(APICoreTest, Loader) { WasmEdge_ErrCode_WrongVMWorkflow, WasmEdge_LoaderParseFromBuffer(nullptr, nullptr, Buf.data(), static_cast<uint32_t>(Buf.size())))); -#ifdef WASMEDGE_BUILD_AOT_RUNTIME +#ifdef WASMEDGE_USE_LLVM // Failed case to parse from buffer with AOT compiled WASM EXPECT_TRUE(readToVector("test_aot" WASMEDGE_LIB_EXTENSION, Buf)); Mod = nullptr; @@ -1691,6 +1772,19 @@ TEST(APICoreTest, ExecutorWithStatistics) { isErrMatch(WasmEdge_ErrCategory_UserLevelError, 0x5678U, WasmEdge_ExecutorInvoke(ExecCxt, FuncCxt, nullptr, 0, R, 1))); + // Invoke independent host functions + // host function "func-add": {externref, i32} -> {i32} + WasmEdge_ValType Result[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *FuncType = + WasmEdge_FunctionTypeCreate(nullptr, 0, Result, 1); + FuncCxt = WasmEdge_FunctionInstanceCreate(FuncType, ExternTerm, nullptr, 0); + WasmEdge_FunctionTypeDelete(FuncType); + EXPECT_NE(FuncCxt, nullptr); + EXPECT_TRUE(WasmEdge_ResultOK( + WasmEdge_ExecutorInvoke(ExecCxt, FuncCxt, nullptr, 0, R, 1))); + WasmEdge_FunctionInstanceDelete(FuncCxt); + EXPECT_TRUE(true); + // Statistics get instruction count EXPECT_GT(WasmEdge_StatisticsGetInstrCount(Stat), 0ULL); EXPECT_EQ(WasmEdge_StatisticsGetInstrCount(nullptr), 0ULL); @@ -1766,21 +1860,21 @@ TEST(APICoreTest, Store) { EXPECT_EQ(WasmEdge_StoreListModule(Store, nullptr, 15), 2U); std::memset(Names, 0, sizeof(WasmEdge_String) * 15); EXPECT_EQ(WasmEdge_StoreListModule(Store, Names, 1), 2U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("extern")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "extern"sv); std::memset(Names, 0, sizeof(WasmEdge_String) * 15); EXPECT_EQ(WasmEdge_StoreListModule(Store, Names, 15), 2U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("extern")); - EXPECT_EQ(std::string(Names[1].Buf, Names[1].Length), std::string("module")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "extern"sv); + EXPECT_EQ(std::string_view(Names[1].Buf, Names[1].Length), "module"sv); // Module instance get module name Names[0] = WasmEdge_ModuleInstanceGetModuleName(nullptr); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), ""sv); Names[0] = WasmEdge_ModuleInstanceGetModuleName(ModCxt); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), ""sv); Names[0] = WasmEdge_ModuleInstanceGetModuleName(ModRegCxt); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("module")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "module"sv); Names[0] = WasmEdge_ModuleInstanceGetModuleName(HostMod); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("extern")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "extern"sv); // Module instance list function exports EXPECT_EQ(WasmEdge_ModuleInstanceListFunctionLength(ModCxt), 11U); @@ -1789,30 +1883,24 @@ TEST(APICoreTest, Store) { EXPECT_EQ(WasmEdge_ModuleInstanceListFunction(ModCxt, nullptr, 15), 11U); std::memset(Names, 0, sizeof(WasmEdge_String) * 15); EXPECT_EQ(WasmEdge_ModuleInstanceListFunction(ModCxt, Names, 4), 11U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("func-1")); - EXPECT_EQ(std::string(Names[1].Buf, Names[1].Length), std::string("func-2")); - EXPECT_EQ(std::string(Names[2].Buf, Names[2].Length), std::string("func-3")); - EXPECT_EQ(std::string(Names[3].Buf, Names[3].Length), std::string("func-4")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "func-1"sv); + EXPECT_EQ(std::string_view(Names[1].Buf, Names[1].Length), "func-2"sv); + EXPECT_EQ(std::string_view(Names[2].Buf, Names[2].Length), "func-3"sv); + EXPECT_EQ(std::string_view(Names[3].Buf, Names[3].Length), "func-4"sv); std::memset(Names, 0, sizeof(WasmEdge_String) * 15); EXPECT_EQ(WasmEdge_ModuleInstanceListFunction(ModCxt, Names, 15), 11U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("func-1")); - EXPECT_EQ(std::string(Names[1].Buf, Names[1].Length), std::string("func-2")); - EXPECT_EQ(std::string(Names[2].Buf, Names[2].Length), std::string("func-3")); - EXPECT_EQ(std::string(Names[3].Buf, Names[3].Length), std::string("func-4")); - EXPECT_EQ(std::string(Names[4].Buf, Names[4].Length), - std::string("func-add")); - EXPECT_EQ(std::string(Names[5].Buf, Names[5].Length), - std::string("func-call-indirect")); - EXPECT_EQ(std::string(Names[6].Buf, Names[6].Length), - std::string("func-host-add")); - EXPECT_EQ(std::string(Names[7].Buf, Names[7].Length), - std::string("func-host-div")); - EXPECT_EQ(std::string(Names[8].Buf, Names[8].Length), - std::string("func-host-mul")); - EXPECT_EQ(std::string(Names[9].Buf, Names[9].Length), - std::string("func-host-sub")); - EXPECT_EQ(std::string(Names[10].Buf, Names[10].Length), - std::string("func-mul-2")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "func-1"sv); + EXPECT_EQ(std::string_view(Names[1].Buf, Names[1].Length), "func-2"sv); + EXPECT_EQ(std::string_view(Names[2].Buf, Names[2].Length), "func-3"sv); + EXPECT_EQ(std::string_view(Names[3].Buf, Names[3].Length), "func-4"sv); + EXPECT_EQ(std::string_view(Names[4].Buf, Names[4].Length), "func-add"sv); + EXPECT_EQ(std::string_view(Names[5].Buf, Names[5].Length), + "func-call-indirect"sv); + EXPECT_EQ(std::string_view(Names[6].Buf, Names[6].Length), "func-host-add"sv); + EXPECT_EQ(std::string_view(Names[7].Buf, Names[7].Length), "func-host-div"sv); + EXPECT_EQ(std::string_view(Names[8].Buf, Names[8].Length), "func-host-mul"sv); + EXPECT_EQ(std::string_view(Names[9].Buf, Names[9].Length), "func-host-sub"sv); + EXPECT_EQ(std::string_view(Names[10].Buf, Names[10].Length), "func-mul-2"sv); // Module instance find function EXPECT_NE(WasmEdge_ModuleInstanceFindFunction(ModCxt, Names[7]), nullptr); @@ -1826,12 +1914,11 @@ TEST(APICoreTest, Store) { EXPECT_EQ(WasmEdge_ModuleInstanceListTable(ModCxt, nullptr, 15), 2U); std::memset(Names, 0, sizeof(WasmEdge_String) * 15); EXPECT_EQ(WasmEdge_ModuleInstanceListTable(ModCxt, Names, 1), 2U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("tab-ext")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "tab-ext"sv); std::memset(Names, 0, sizeof(WasmEdge_String) * 15); EXPECT_EQ(WasmEdge_ModuleInstanceListTable(ModCxt, Names, 15), 2U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("tab-ext")); - EXPECT_EQ(std::string(Names[1].Buf, Names[1].Length), - std::string("tab-func")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "tab-ext"sv); + EXPECT_EQ(std::string_view(Names[1].Buf, Names[1].Length), "tab-func"sv); // Module instance find table EXPECT_NE(WasmEdge_ModuleInstanceFindTable(ModCxt, Names[1]), nullptr); @@ -1846,7 +1933,7 @@ TEST(APICoreTest, Store) { EXPECT_EQ(WasmEdge_ModuleInstanceListMemory(ModCxt, Names, 0), 1U); std::memset(Names, 0, sizeof(WasmEdge_String) * 15); EXPECT_EQ(WasmEdge_ModuleInstanceListMemory(ModCxt, Names, 15), 1U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("mem")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "mem"sv); // Module instance find memory EXPECT_NE(WasmEdge_ModuleInstanceFindMemory(ModCxt, Names[0]), nullptr); @@ -1860,14 +1947,13 @@ TEST(APICoreTest, Store) { EXPECT_EQ(WasmEdge_ModuleInstanceListGlobal(ModCxt, nullptr, 15), 2U); std::memset(Names, 0, sizeof(WasmEdge_String) * 15); EXPECT_EQ(WasmEdge_ModuleInstanceListGlobal(ModCxt, Names, 1), 2U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), - std::string("glob-const-f32")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), + "glob-const-f32"sv); std::memset(Names, 0, sizeof(WasmEdge_String) * 15); EXPECT_EQ(WasmEdge_ModuleInstanceListGlobal(ModCxt, Names, 15), 2U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), - std::string("glob-const-f32")); - EXPECT_EQ(std::string(Names[1].Buf, Names[1].Length), - std::string("glob-mut-i32")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), + "glob-const-f32"sv); + EXPECT_EQ(std::string_view(Names[1].Buf, Names[1].Length), "glob-mut-i32"sv); // Module instance find global EXPECT_NE(WasmEdge_ModuleInstanceFindGlobal(ModCxt, Names[1]), nullptr); @@ -2286,7 +2372,7 @@ TEST(APICoreTest, ModuleInstance) { WasmEdge_MemoryInstanceContext *HostMemory = nullptr; WasmEdge_GlobalInstanceContext *HostGlobal = nullptr; auto HostFinalizer = [](void *Data) { - std::cout << "Data address: " << Data << std::endl; + fmt::print("Data address: {}\n"sv, Data); }; WasmEdge_ValType Param[2], Result[1]; @@ -3283,23 +3369,21 @@ TEST(APICoreTest, VM) { WasmEdge_VMRunWasmFromASTModule(VM, Mod, FuncName, P, 2, nullptr, 1))); // VM get registered module - EXPECT_EQ(WasmEdge_VMListRegisteredModuleLength(VM), 16U); + EXPECT_EQ(WasmEdge_VMListRegisteredModuleLength(VM), 17U); EXPECT_EQ(WasmEdge_VMListRegisteredModuleLength(nullptr), 0U); EXPECT_EQ(WasmEdge_VMListRegisteredModule(nullptr, Names, 20), 0U); - EXPECT_EQ(WasmEdge_VMListRegisteredModule(VM, nullptr, 20), 16U); + EXPECT_EQ(WasmEdge_VMListRegisteredModule(VM, nullptr, 20), 17U); std::memset(Names, 0, sizeof(WasmEdge_String) * 20); - EXPECT_EQ(WasmEdge_VMListRegisteredModule(VM, Names, 1), 16U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("extern")); - EXPECT_EQ(std::string(Names[1].Buf, Names[1].Length), std::string("")); + EXPECT_EQ(WasmEdge_VMListRegisteredModule(VM, Names, 1), 17U); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "extern"sv); + EXPECT_EQ(std::string_view(Names[1].Buf, Names[1].Length), ""sv); std::memset(Names, 0, sizeof(WasmEdge_String) * 20); - EXPECT_EQ(WasmEdge_VMListRegisteredModule(VM, Names, 20), 16U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("extern")); - EXPECT_EQ(std::string(Names[1].Buf, Names[1].Length), - std::string("reg-wasm-ast")); - EXPECT_EQ(std::string(Names[2].Buf, Names[2].Length), - std::string("reg-wasm-buffer")); - EXPECT_EQ(std::string(Names[3].Buf, Names[3].Length), - std::string("reg-wasm-file")); + EXPECT_EQ(WasmEdge_VMListRegisteredModule(VM, Names, 20), 17U); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "extern"sv); + EXPECT_EQ(std::string_view(Names[1].Buf, Names[1].Length), "reg-wasm-ast"sv); + EXPECT_EQ(std::string_view(Names[2].Buf, Names[2].Length), + "reg-wasm-buffer"sv); + EXPECT_EQ(std::string_view(Names[3].Buf, Names[3].Length), "reg-wasm-file"sv); // VM load wasm from file EXPECT_TRUE(WasmEdge_ResultOK(WasmEdge_VMLoadWasmFromFile(VM, TPath))); @@ -3499,54 +3583,42 @@ TEST(APICoreTest, VM) { std::memset(Names, 0, sizeof(WasmEdge_String) * 15); EXPECT_EQ(WasmEdge_VMGetFunctionList(VM, Names, nullptr, 15), 11U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("func-1")); - EXPECT_EQ(std::string(Names[1].Buf, Names[1].Length), std::string("func-2")); - EXPECT_EQ(std::string(Names[2].Buf, Names[2].Length), std::string("func-3")); - EXPECT_EQ(std::string(Names[3].Buf, Names[3].Length), std::string("func-4")); - EXPECT_EQ(std::string(Names[4].Buf, Names[4].Length), - std::string("func-add")); - EXPECT_EQ(std::string(Names[5].Buf, Names[5].Length), - std::string("func-call-indirect")); - EXPECT_EQ(std::string(Names[6].Buf, Names[6].Length), - std::string("func-host-add")); - EXPECT_EQ(std::string(Names[7].Buf, Names[7].Length), - std::string("func-host-div")); - EXPECT_EQ(std::string(Names[8].Buf, Names[8].Length), - std::string("func-host-mul")); - EXPECT_EQ(std::string(Names[9].Buf, Names[9].Length), - std::string("func-host-sub")); - EXPECT_EQ(std::string(Names[10].Buf, Names[10].Length), - std::string("func-mul-2")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "func-1"sv); + EXPECT_EQ(std::string_view(Names[1].Buf, Names[1].Length), "func-2"sv); + EXPECT_EQ(std::string_view(Names[2].Buf, Names[2].Length), "func-3"sv); + EXPECT_EQ(std::string_view(Names[3].Buf, Names[3].Length), "func-4"sv); + EXPECT_EQ(std::string_view(Names[4].Buf, Names[4].Length), "func-add"sv); + EXPECT_EQ(std::string_view(Names[5].Buf, Names[5].Length), + "func-call-indirect"sv); + EXPECT_EQ(std::string_view(Names[6].Buf, Names[6].Length), "func-host-add"sv); + EXPECT_EQ(std::string_view(Names[7].Buf, Names[7].Length), "func-host-div"sv); + EXPECT_EQ(std::string_view(Names[8].Buf, Names[8].Length), "func-host-mul"sv); + EXPECT_EQ(std::string_view(Names[9].Buf, Names[9].Length), "func-host-sub"sv); + EXPECT_EQ(std::string_view(Names[10].Buf, Names[10].Length), "func-mul-2"sv); EXPECT_EQ(WasmEdge_VMGetFunctionList(VM, nullptr, nullptr, 15), 11U); std::memset(Names, 0, sizeof(WasmEdge_String) * 15); EXPECT_EQ(WasmEdge_VMGetFunctionList(VM, Names, FuncTypes, 4), 11U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("func-1")); - EXPECT_EQ(std::string(Names[1].Buf, Names[1].Length), std::string("func-2")); - EXPECT_EQ(std::string(Names[2].Buf, Names[2].Length), std::string("func-3")); - EXPECT_EQ(std::string(Names[3].Buf, Names[3].Length), std::string("func-4")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "func-1"sv); + EXPECT_EQ(std::string_view(Names[1].Buf, Names[1].Length), "func-2"sv); + EXPECT_EQ(std::string_view(Names[2].Buf, Names[2].Length), "func-3"sv); + EXPECT_EQ(std::string_view(Names[3].Buf, Names[3].Length), "func-4"sv); std::memset(Names, 0, sizeof(WasmEdge_String) * 15); EXPECT_EQ(WasmEdge_VMGetFunctionList(VM, Names, FuncTypes, 15), 11U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("func-1")); - EXPECT_EQ(std::string(Names[1].Buf, Names[1].Length), std::string("func-2")); - EXPECT_EQ(std::string(Names[2].Buf, Names[2].Length), std::string("func-3")); - EXPECT_EQ(std::string(Names[3].Buf, Names[3].Length), std::string("func-4")); - EXPECT_EQ(std::string(Names[4].Buf, Names[4].Length), - std::string("func-add")); - EXPECT_EQ(std::string(Names[5].Buf, Names[5].Length), - std::string("func-call-indirect")); - EXPECT_EQ(std::string(Names[6].Buf, Names[6].Length), - std::string("func-host-add")); - EXPECT_EQ(std::string(Names[7].Buf, Names[7].Length), - std::string("func-host-div")); - EXPECT_EQ(std::string(Names[8].Buf, Names[8].Length), - std::string("func-host-mul")); - EXPECT_EQ(std::string(Names[9].Buf, Names[9].Length), - std::string("func-host-sub")); - EXPECT_EQ(std::string(Names[10].Buf, Names[10].Length), - std::string("func-mul-2")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), "func-1"sv); + EXPECT_EQ(std::string_view(Names[1].Buf, Names[1].Length), "func-2"sv); + EXPECT_EQ(std::string_view(Names[2].Buf, Names[2].Length), "func-3"sv); + EXPECT_EQ(std::string_view(Names[3].Buf, Names[3].Length), "func-4"sv); + EXPECT_EQ(std::string_view(Names[4].Buf, Names[4].Length), "func-add"sv); + EXPECT_EQ(std::string_view(Names[5].Buf, Names[5].Length), + "func-call-indirect"sv); + EXPECT_EQ(std::string_view(Names[6].Buf, Names[6].Length), "func-host-add"sv); + EXPECT_EQ(std::string_view(Names[7].Buf, Names[7].Length), "func-host-div"sv); + EXPECT_EQ(std::string_view(Names[8].Buf, Names[8].Length), "func-host-mul"sv); + EXPECT_EQ(std::string_view(Names[9].Buf, Names[9].Length), "func-host-sub"sv); + EXPECT_EQ(std::string_view(Names[10].Buf, Names[10].Length), "func-mul-2"sv); // VM get active module EXPECT_NE(WasmEdge_VMGetActiveModule(VM), nullptr); @@ -3609,15 +3681,15 @@ TEST(APICoreTest, VM) { WasmEdge_VMDelete(VM); } -#if defined(WASMEDGE_BUILD_PLUGINS) && WASMEDGE_OS_LINUX +#if defined(WASMEDGE_BUILD_PLUGINS) TEST(APICoreTest, Plugin) { WasmEdge_String Names[15]; // Load from the specific path EXPECT_EQ(WasmEdge_PluginListPluginsLength(), 0U); WasmEdge_PluginLoadFromPath( - "../plugins/unittest/" - "libwasmedgePluginTestModuleCPP" WASMEDGE_LIB_EXTENSION); + "../plugins/unittest/" WASMEDGE_LIB_PREFIX + "wasmedgePluginTestModuleCPP" WASMEDGE_LIB_EXTENSION); EXPECT_EQ(WasmEdge_PluginListPluginsLength(), 1U); // Get the loaded plugin length @@ -3625,8 +3697,8 @@ TEST(APICoreTest, Plugin) { EXPECT_EQ(WasmEdge_PluginListPlugins(nullptr, 0), 1U); EXPECT_EQ(WasmEdge_PluginListPlugins(Names, 0), 1U); EXPECT_EQ(WasmEdge_PluginListPlugins(Names, 15), 1U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), - std::string("wasmedge_plugintest_cpp")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), + "wasmedge_plugintest_cpp"sv); // Find the plugin context const WasmEdge_PluginContext *PluginCxt = @@ -3637,10 +3709,10 @@ TEST(APICoreTest, Plugin) { // Get plugin name Names[0] = WasmEdge_PluginGetPluginName(PluginCxt); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), - std::string("wasmedge_plugintest_cpp")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), + "wasmedge_plugintest_cpp"sv); Names[0] = WasmEdge_PluginGetPluginName(nullptr); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), ""sv); // List modules in the plugin EXPECT_EQ(WasmEdge_PluginListModuleLength(nullptr), 0U); @@ -3650,10 +3722,10 @@ TEST(APICoreTest, Plugin) { EXPECT_EQ(WasmEdge_PluginListModule(nullptr, nullptr, 0), 0U); EXPECT_EQ(WasmEdge_PluginListModule(PluginCxt, nullptr, 0), 1U); EXPECT_EQ(WasmEdge_PluginListModule(PluginCxt, Names, 0), 1U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), std::string("")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), ""sv); EXPECT_EQ(WasmEdge_PluginListModule(PluginCxt, Names, 15), 1U); - EXPECT_EQ(std::string(Names[0].Buf, Names[0].Length), - std::string("wasmedge_plugintest_cpp_module")); + EXPECT_EQ(std::string_view(Names[0].Buf, Names[0].Length), + "wasmedge_plugintest_cpp_module"sv); // Create the module WasmEdge_ModuleInstanceContext *ModCxt = @@ -3664,7 +3736,7 @@ TEST(APICoreTest, Plugin) { EXPECT_EQ(ModCxt, nullptr); ModCxt = WasmEdge_PluginCreateModule(PluginCxt, Names[0]); EXPECT_NE(ModCxt, nullptr); - EXPECT_EQ(WasmEdge_ModuleInstanceListFunction(ModCxt, Names, 15), 4U); + EXPECT_EQ(WasmEdge_ModuleInstanceListFunction(ModCxt, Names, 15), 5U); WasmEdge_ModuleInstanceDelete(ModCxt); } #endif diff --git a/test/api/APIVMCoreTest.cpp b/test/api/APIVMCoreTest.cpp index 4a9c96f09846..ba89b8263ef4 100644 --- a/test/api/APIVMCoreTest.cpp +++ b/test/api/APIVMCoreTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/api/APIVMCoreTest.cpp - WasmEdge C API core tests ---===// // @@ -208,8 +208,8 @@ TEST(AsyncRunWsmFile, InterruptTest) { TEST(AsyncExecute, InterruptTest) { WasmEdge_VMContext *VM = WasmEdge_VMCreate(nullptr, nullptr); - ASSERT_TRUE(WasmEdge_ResultOK( - WasmEdge_VMLoadWasmFromBuffer(VM, AsyncWasm.data(), static_cast<uint32_t>(AsyncWasm.size())))); + ASSERT_TRUE(WasmEdge_ResultOK(WasmEdge_VMLoadWasmFromBuffer( + VM, AsyncWasm.data(), static_cast<uint32_t>(AsyncWasm.size())))); ASSERT_TRUE(WasmEdge_ResultOK(WasmEdge_VMValidate(VM))); ASSERT_TRUE(WasmEdge_ResultOK(WasmEdge_VMInstantiate(VM))); { diff --git a/test/api/CMakeLists.txt b/test/api/CMakeLists.txt index 6e92b3c1641a..11167e08725b 100644 --- a/test/api/CMakeLists.txt +++ b/test/api/CMakeLists.txt @@ -1,8 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC -if(WASMEDGE_BUILD_AOT_RUNTIME) - add_definitions(-DWASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) + add_definitions(-DWASMEDGE_USE_LLVM) endif() if(WASMEDGE_BUILD_PLUGINS) add_definitions(-DWASMEDGE_BUILD_PLUGINS) @@ -74,7 +74,7 @@ target_link_libraries(wasmedgeAPIStepsCoreTests wasmedge_shared ) -if(WASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) wasmedge_add_executable(wasmedgeAPIAOTCoreTests APIAOTCoreTest.cpp ) diff --git a/test/api/apiTestData/import.wat b/test/api/apiTestData/import.wat index 12eaa02b4c41..5b27ea46ecc1 100644 --- a/test/api/apiTestData/import.wat +++ b/test/api/apiTestData/import.wat @@ -15,6 +15,9 @@ (import "dummy" "tab-ext" (table 10 30 externref)) (import "dummy" "mem1" (memory 1 3)) (import "dummy" "mem2" (memory 2)) + (import "dummy" "tag1" (tag (param f64))) + (import "dummy" "tag2" (tag (param f64 i64))) + (import "dummy" "tag3" (tag)) (export "func-1" (func $f-1)) (export "func-2" (func $f-2)) (export "func-3" (func $f-3)) @@ -29,9 +32,16 @@ (export "tab-func" (table $t-f)) (export "tab-ext" (table $t-e)) (export "mem" (memory $m)) + (export "tag-1" (tag $tag-1)) + (export "tag-2" (tag $tag-2)) + (export "tag-3" (tag $tag-3)) (export "glob-mut-i32" (global $g-mi)) (export "glob-const-f32" (global $g-cf)) + (tag $tag-1 (param i32 i64 f32 f64)) + (tag $tag-2) + (tag $tag-3 (param f32)) + (func $f-1 (result i32) (i32.const 1)) (func $f-2 (result i32) (i32.const 2)) (func $f-3 (result i32) (i32.const 3)) diff --git a/test/api/helper.cpp b/test/api/helper.cpp index b172a9adf600..f646a88a647f 100644 --- a/test/api/helper.cpp +++ b/test/api/helper.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/api/helper.cpp - Spec test helpers for C API --------===// // @@ -23,9 +23,10 @@ namespace WasmEdge { static Proposal ProposalList[] = { - Proposal::TailCall, Proposal::MultiMemories, Proposal::Annotations, - Proposal::Memory64, Proposal::ExceptionHandling, Proposal::ExtendedConst, - Proposal::Threads, Proposal::FunctionReferences}; + Proposal::TailCall, Proposal::MultiMemories, Proposal::Annotations, + Proposal::Memory64, Proposal::ExceptionHandling, Proposal::ExtendedConst, + Proposal::Threads, Proposal::FunctionReferences, Proposal::GC, + Proposal::RelaxSIMD}; WasmEdge_ConfigureContext *createConf(const Configure &Conf) { auto *Cxt = WasmEdge_ConfigureCreate(); diff --git a/test/api/helper.h b/test/api/helper.h index 2ae43eacc44f..c7e63c250828 100644 --- a/test/api/helper.h +++ b/test/api/helper.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/api/helper.h - Spec test helpers for C API ----------===// // diff --git a/test/api/hostfunc_c.c b/test/api/hostfunc_c.c index 769345bf53ef..e025dab4f98c 100644 --- a/test/api/hostfunc_c.c +++ b/test/api/hostfunc_c.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/api/hostfunc_c.c - Spec test host functions for C API ==// // @@ -19,23 +19,22 @@ #if defined(_MSC_VER) && !defined(__clang__) // MSVC #define MAYBE_UNUSED -#pragma warning( disable : 4100 ) // unreferenced formal parameter +#pragma warning(disable : 4100) // unreferenced formal parameter #else #define MAYBE_UNUSED __attribute__((unused)) #endif -WasmEdge_Result SpecTestPrint(void *Data MAYBE_UNUSED, - const WasmEdge_CallingFrameContext *CallFrameCxt - MAYBE_UNUSED, - const WasmEdge_Value *In MAYBE_UNUSED, - WasmEdge_Value *Out MAYBE_UNUSED) { +WasmEdge_Result +SpecTestPrint(void *Data MAYBE_UNUSED, + const WasmEdge_CallingFrameContext *CallFrameCxt MAYBE_UNUSED, + const WasmEdge_Value *In MAYBE_UNUSED, + WasmEdge_Value *Out MAYBE_UNUSED) { return WasmEdge_Result_Success; } WasmEdge_Result SpecTestPrintI32(void *Data MAYBE_UNUSED, - const WasmEdge_CallingFrameContext *CallFrameCxt - MAYBE_UNUSED, + const WasmEdge_CallingFrameContext *CallFrameCxt MAYBE_UNUSED, const WasmEdge_Value *In MAYBE_UNUSED, WasmEdge_Value *Out MAYBE_UNUSED) { return WasmEdge_Result_Success; @@ -43,8 +42,7 @@ SpecTestPrintI32(void *Data MAYBE_UNUSED, WasmEdge_Result SpecTestPrintI64(void *Data MAYBE_UNUSED, - const WasmEdge_CallingFrameContext *CallFrameCxt - MAYBE_UNUSED, + const WasmEdge_CallingFrameContext *CallFrameCxt MAYBE_UNUSED, const WasmEdge_Value *In MAYBE_UNUSED, WasmEdge_Value *Out MAYBE_UNUSED) { return WasmEdge_Result_Success; @@ -52,8 +50,7 @@ SpecTestPrintI64(void *Data MAYBE_UNUSED, WasmEdge_Result SpecTestPrintF32(void *Data MAYBE_UNUSED, - const WasmEdge_CallingFrameContext *CallFrameCxt - MAYBE_UNUSED, + const WasmEdge_CallingFrameContext *CallFrameCxt MAYBE_UNUSED, const WasmEdge_Value *In MAYBE_UNUSED, WasmEdge_Value *Out MAYBE_UNUSED) { return WasmEdge_Result_Success; @@ -61,28 +58,23 @@ SpecTestPrintF32(void *Data MAYBE_UNUSED, WasmEdge_Result SpecTestPrintF64(void *Data MAYBE_UNUSED, - const WasmEdge_CallingFrameContext *CallFrameCxt - MAYBE_UNUSED, + const WasmEdge_CallingFrameContext *CallFrameCxt MAYBE_UNUSED, const WasmEdge_Value *In MAYBE_UNUSED, WasmEdge_Value *Out MAYBE_UNUSED) { return WasmEdge_Result_Success; } -WasmEdge_Result -SpecTestPrintI32F32(void *Data MAYBE_UNUSED, - const WasmEdge_CallingFrameContext *CallFrameCxt - MAYBE_UNUSED, - const WasmEdge_Value *In MAYBE_UNUSED, - WasmEdge_Value *Out MAYBE_UNUSED) { +WasmEdge_Result SpecTestPrintI32F32( + void *Data MAYBE_UNUSED, + const WasmEdge_CallingFrameContext *CallFrameCxt MAYBE_UNUSED, + const WasmEdge_Value *In MAYBE_UNUSED, WasmEdge_Value *Out MAYBE_UNUSED) { return WasmEdge_Result_Success; } -WasmEdge_Result -SpecTestPrintF64F64(void *Data MAYBE_UNUSED, - const WasmEdge_CallingFrameContext *CallFrameCxt - MAYBE_UNUSED, - const WasmEdge_Value *In MAYBE_UNUSED, - WasmEdge_Value *Out MAYBE_UNUSED) { +WasmEdge_Result SpecTestPrintF64F64( + void *Data MAYBE_UNUSED, + const WasmEdge_CallingFrameContext *CallFrameCxt MAYBE_UNUSED, + const WasmEdge_Value *In MAYBE_UNUSED, WasmEdge_Value *Out MAYBE_UNUSED) { return WasmEdge_Result_Success; } @@ -235,8 +227,8 @@ WasmEdge_ModuleInstanceContext *createSpecTestModule(void) { // Add host global "global_f32": const 666.0 HostGType = WasmEdge_GlobalTypeCreate(WasmEdge_ValTypeGenF32(), WasmEdge_Mutability_Const); - HostGlobal = - WasmEdge_GlobalInstanceCreate(HostGType, WasmEdge_ValueGenF32(666.0)); + HostGlobal = WasmEdge_GlobalInstanceCreate( + HostGType, WasmEdge_ValueGenF32((float)666.6)); WasmEdge_GlobalTypeDelete(HostGType); HostName = WasmEdge_StringCreateByCString("global_f32"); WasmEdge_ModuleInstanceAddGlobal(HostMod, HostName, HostGlobal); @@ -245,8 +237,8 @@ WasmEdge_ModuleInstanceContext *createSpecTestModule(void) { // Add host global "global_f64": const 666.0 HostGType = WasmEdge_GlobalTypeCreate(WasmEdge_ValTypeGenF64(), WasmEdge_Mutability_Const); - HostGlobal = - WasmEdge_GlobalInstanceCreate(HostGType, WasmEdge_ValueGenF64(666.0)); + HostGlobal = WasmEdge_GlobalInstanceCreate( + HostGType, WasmEdge_ValueGenF64((double)666.6)); WasmEdge_GlobalTypeDelete(HostGType); HostName = WasmEdge_StringCreateByCString("global_f64"); WasmEdge_ModuleInstanceAddGlobal(HostMod, HostName, HostGlobal); diff --git a/test/api/hostfunc_c.h b/test/api/hostfunc_c.h index 2a685648c771..b9f1b2b1aba3 100644 --- a/test/api/hostfunc_c.h +++ b/test/api/hostfunc_c.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/api/hostfunc_c.h - Spec test host functions for C API ==// // diff --git a/test/common/CMakeLists.txt b/test/common/CMakeLists.txt index 1ce9d9ac3dcb..288d432ec628 100644 --- a/test/common/CMakeLists.txt +++ b/test/common/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeCommonTests int128Test.cpp diff --git a/test/common/int128Test.cpp b/test/common/int128Test.cpp index b7787e6e71f2..f3c785aa9346 100644 --- a/test/common/int128Test.cpp +++ b/test/common/int128Test.cpp @@ -1,77 +1,107 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/int128.h" +#include "fmt/format.h" #include <cstdint> #include <gtest/gtest.h> -#include <sstream> namespace { +using namespace std::literals; TEST(Int128Test, Int128OutputTest) { - using WasmEdge::operator<<; - - WasmEdge::uint128_t Value; - std::ostringstream OS; - { - OS.str(""); - OS.clear(); - Value = 0; - OS << Value; - EXPECT_EQ(OS.str(), "0"); + const WasmEdge::uint128_t Value = 0; + EXPECT_EQ(fmt::format("{}"sv, Value), "0"); + EXPECT_EQ(fmt::format("{:x}"sv, Value), "0"); + EXPECT_EQ(fmt::format("{:#x}"sv, Value), "0x0"); + EXPECT_EQ(fmt::format("{:b}"sv, Value), "0"); + EXPECT_EQ(fmt::format("{:#b}"sv, Value), "0b0"); + EXPECT_EQ(fmt::format("{:o}"sv, Value), "0"); } { - OS.str(""); - OS.clear(); - Value = WasmEdge::uint128_t(1) << 69; - OS << Value; - EXPECT_EQ(OS.str(), "590295810358705651712"); + const WasmEdge::uint128_t Value = WasmEdge::uint128_t(1) << 69; + EXPECT_EQ(fmt::format("{}"sv, Value), "590295810358705651712"); + EXPECT_EQ(fmt::format("{:x}"sv, Value), "200000000000000000"); } { - OS.str(""); - OS.clear(); - Value = WasmEdge::uint128_t(1) << 127; - OS << Value; - EXPECT_EQ(OS.str(), "170141183460469231731687303715884105728"); + const WasmEdge::uint128_t Value = WasmEdge::uint128_t(1) << 127; + EXPECT_EQ(fmt::format("{}"sv, Value), + "170141183460469231731687303715884105728"); + EXPECT_EQ(fmt::format("{:x}"sv, Value), "80000000000000000000000000000000"); } { - OS.str(""); - OS.clear(); - Value = ~WasmEdge::uint128_t(0); - OS << Value; - EXPECT_EQ(OS.str(), "340282366920938463463374607431768211455"); + const WasmEdge::uint128_t Value = ~WasmEdge::uint128_t(0); + EXPECT_EQ(fmt::format("{}"sv, Value), + "340282366920938463463374607431768211455"); + EXPECT_EQ(fmt::format("{:x}"sv, Value), "ffffffffffffffffffffffffffffffff"); + EXPECT_EQ(fmt::format("{:#X}"sv, Value), + "0XFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); } { - OS.str(""); - OS.clear(); const WasmEdge::uint128_t P10(10000000000000); - Value = WasmEdge::uint128_t(1234567890123) * P10 * P10 + WasmEdge::uint128_t(1234567890123); - OS << Value; - EXPECT_EQ(OS.str(), "123456789012300000000000001234567890123"); + const WasmEdge::uint128_t Value = + WasmEdge::uint128_t(1234567890123) * P10 * P10 + + WasmEdge::uint128_t(1234567890123); + EXPECT_EQ(fmt::format("{}"sv, Value), + "123456789012300000000000001234567890123"); + EXPECT_EQ(fmt::format("{:x}"sv, Value), "5ce0e9a55ff035e3783f03ea3dfb04cb"); + EXPECT_EQ( + fmt::format("{:b}"sv, Value), + "1011100111000001110100110100101010111111111000000110101111000110111100" + "000111111000000111110101000111101111110110000010011001011"); } { - OS.str(""); - OS.clear(); const WasmEdge::uint128_t P10(10000000000000); - Value = WasmEdge::uint128_t(1234567890123) * P10 * P10; - OS << Value; - EXPECT_EQ(OS.str(), "123456789012300000000000000000000000000"); + const WasmEdge::uint128_t Value = + WasmEdge::uint128_t(1234567890123) * P10 * P10; + EXPECT_EQ(fmt::format("{}"sv, Value), + "123456789012300000000000000000000000000"); + EXPECT_EQ(fmt::format("{:o}"sv, Value), + "1347016464527770065706740770054531400000000"); } { - OS.str(""); - OS.clear(); const WasmEdge::uint128_t P10(10000000000000); - Value = WasmEdge::uint128_t(1234567890123) * P10 * P10 + WasmEdge::uint128_t(1234567890123) * P10; - OS << Value; - EXPECT_EQ(OS.str(), "123456789012312345678901230000000000000"); + const WasmEdge::uint128_t Value = + WasmEdge::uint128_t(1234567890123) * P10 * P10 + + WasmEdge::uint128_t(1234567890123) * P10; + EXPECT_EQ(fmt::format("{}"sv, Value), + "123456789012312345678901230000000000000"); + } + + { + auto Convert = [](WasmEdge::uint128_t V) -> fmt::detail::uint128_t { +#if !FMT_USE_INT128 + return fmt::detail::uint128_t{static_cast<uint64_t>(V >> 64), + static_cast<uint64_t>(V)}; +#else + return V; +#endif + }; + std::string S0 = "1"s; + std::string S9; + WasmEdge::uint128_t X(1); + for (unsigned int I = 1; I <= 38; ++I) { + X *= 10; + const auto Y = X - WasmEdge::uint128_t(1); + EXPECT_EQ(fmt::detail::count_digits(Convert(Y - WasmEdge::uint128_t(1))), + I); + EXPECT_EQ(fmt::detail::count_digits(Convert(Y)), I); + EXPECT_EQ(fmt::detail::count_digits(Convert(X)), I + 1); + EXPECT_EQ(fmt::detail::count_digits(Convert(X + WasmEdge::uint128_t(1))), + I + 1); + S0 += '0'; + S9 += '9'; + EXPECT_EQ(fmt::format("{}"sv, X), S0); + EXPECT_EQ(fmt::format("{}"sv, Y), S9); + } } } } // namespace diff --git a/test/errinfo/CMakeLists.txt b/test/errinfo/CMakeLists.txt index 53f973f314ea..f1cf41a07275 100644 --- a/test/errinfo/CMakeLists.txt +++ b/test/errinfo/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeErrinfoTests errinfoTest.cpp diff --git a/test/errinfo/errinfoTest.cpp b/test/errinfo/errinfoTest.cpp index d074843a3ff3..667a8244946a 100644 --- a/test/errinfo/errinfoTest.cpp +++ b/test/errinfo/errinfoTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/errinfo.h" diff --git a/test/executor/CMakeLists.txt b/test/executor/CMakeLists.txt index 088d1aefc852..6590d35c3cc8 100644 --- a/test/executor/CMakeLists.txt +++ b/test/executor/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeExecutorCoreTests ExecutorTest.cpp diff --git a/test/executor/ExecutorTest.cpp b/test/executor/ExecutorTest.cpp index 4597e6977af1..fd20d00de20d 100644 --- a/test/executor/ExecutorTest.cpp +++ b/test/executor/ExecutorTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/executor/ExecutorTest.cpp - Wasm test suites --------===// // @@ -14,7 +14,7 @@ /// //===----------------------------------------------------------------------===// -#include "common/log.h" +#include "common/spdlog.h" #include "vm/vm.h" #include "../spec/hostfunc.h" diff --git a/test/expected/CMakeLists.txt b/test/expected/CMakeLists.txt index 4af19f06bbe8..88836e7965b2 100644 --- a/test/expected/CMakeLists.txt +++ b/test/expected/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(expectedTests assignment.cpp diff --git a/test/expected/catch.hpp b/test/expected/catch.hpp index 2dda0c6e301e..dcebd6224652 100644 --- a/test/expected/catch.hpp +++ b/test/expected/catch.hpp @@ -12478,7 +12478,7 @@ namespace Catch { } void close() override { TrackerBase::close(); - // Generator interface only finds out if it has another item on atual move + // Generator interface only finds out if it has another item on actual move if (m_runState == CompletedSuccessfully && m_generator->next()) { m_children.clear(); m_runState = Executing; @@ -17612,4 +17612,3 @@ using Catch::Detail::Approx; // end catch_reenable_warnings.h // end catch.hpp #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED - diff --git a/test/expected/noexcept.cpp b/test/expected/noexcept.cpp index aacf20f7f420..6a26c182b927 100644 --- a/test/expected/noexcept.cpp +++ b/test/expected/noexcept.cpp @@ -31,7 +31,14 @@ TEST(NoExceptTest, ThrowAll) { [[noreturn]] [[maybe_unused]] throw_all(throw_all &&) noexcept(false) { throw 0; } +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4722) +#endif [[noreturn]] ~throw_all() noexcept(false) { throw 0; } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif [[noreturn]] throw_all &operator=(const throw_all &) noexcept(false) { throw 0; } diff --git a/test/externref/CMakeLists.txt b/test/externref/CMakeLists.txt index b5a304468c13..7cd40e5b543a 100644 --- a/test/externref/CMakeLists.txt +++ b/test/externref/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeExternrefTests ExternrefTest.cpp diff --git a/test/externref/ExternrefTest.cpp b/test/externref/ExternrefTest.cpp index 6093b251c3ac..40f419d5d74b 100644 --- a/test/externref/ExternrefTest.cpp +++ b/test/externref/ExternrefTest.cpp @@ -1,10 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/filesystem.h" +#include "experimental/span.hpp" #include "wasmedge/wasmedge.h" #include <cstdint> +#include <fmt/format.h> #include <fstream> #include <gtest/gtest.h> #include <iostream> @@ -14,7 +16,6 @@ #include <utility> #include <vector> - namespace { std::vector<uint8_t> FuncsWasm = { @@ -115,11 +116,10 @@ std::vector<uint8_t> STLWasm = { 0x0, 0xe, 0x2, 0x0, 0x0, 0x1, 0x0, 0xf, 0x2, 0x0, 0x0, 0x1, 0x0}; -void HexToFile(std::vector<uint8_t> &Wasm, const char *Path) { +void HexToFile(cxx20::span<const uint8_t> Wasm, const char *Path) { std::ofstream TFile(std::filesystem::u8path(Path), std::ios_base::binary); - for (auto &Hex : Wasm) { - TFile << Hex; - } + TFile.write(reinterpret_cast<const char *>(Wasm.data()), + static_cast<std::streamsize>(Wasm.size())); TFile.close(); } diff --git a/test/host/mock/CMakeLists.txt b/test/host/mock/CMakeLists.txt index 8c44f2cf5054..ad4312c6472d 100644 --- a/test/host/mock/CMakeLists.txt +++ b/test/host/mock/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeHostMockTests mockTest.cpp diff --git a/test/host/mock/mockTest.cpp b/test/host/mock/mockTest.cpp index 2c952c444133..bfcd496ec6e0 100644 --- a/test/host/mock/mockTest.cpp +++ b/test/host/mock/mockTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "host/mock/wasi_crypto_module.h" #include "host/mock/wasi_logging_module.h" diff --git a/test/host/socket/CMakeLists.txt b/test/host/socket/CMakeLists.txt index 258b890d03d9..107c5398f303 100644 --- a/test/host/socket/CMakeLists.txt +++ b/test/host/socket/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasiSocketTests wasi_socket.cpp diff --git a/test/host/socket/wasi_socket.cpp b/test/host/socket/wasi_socket.cpp index 8e10f8fd11b8..35ba7eaaabba 100644 --- a/test/host/socket/wasi_socket.cpp +++ b/test/host/socket/wasi_socket.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #include "executor/executor.h" @@ -9,12 +9,12 @@ #include "system/winapi.h" #include <algorithm> #include <array> +#include <climits> #include <cstdint> #include <cstring> #include <gtest/gtest.h> #include <string> #include <string_view> -#include <climits> #if !WASMEDGE_OS_WINDOWS #include <netinet/in.h> diff --git a/test/host/wasi/CMakeLists.txt b/test/host/wasi/CMakeLists.txt index d7fd9636564a..4909cf248e43 100644 --- a/test/host/wasi/CMakeLists.txt +++ b/test/host/wasi/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasiTests wasi.cpp diff --git a/test/host/wasi/wasi.cpp b/test/host/wasi/wasi.cpp index e57d5c547b2f..a99537a3d291 100644 --- a/test/host/wasi/wasi.cpp +++ b/test/host/wasi/wasi.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #include "host/wasi/wasibase.h" @@ -223,9 +223,10 @@ convertFiletime(WasmEdge::winapi::FILETIME_ FileTime) noexcept { std::chrono::nanoseconds::period>>; /// from 1601-01-01 to 1970-01-01, 134774 days constexpr const FiletimeDuration NTToUnixEpoch = - std::chrono::seconds{134774u * 86400u}; + std::chrono::seconds{134774LL * 86400LL}; WasmEdge::winapi::ULARGE_INTEGER_ Temp = { - /* LowPart */ FileTime.dwLowDateTime, /* HighPart */ FileTime.dwHighDateTime}; + /* LowPart */ FileTime.dwLowDateTime, + /* HighPart */ FileTime.dwHighDateTime}; auto Duration = duration_cast<nanoseconds>(FiletimeDuration{Temp.QuadPart} - NTToUnixEpoch); return static_cast<__wasi_timestamp_t>(Duration.count()); @@ -2541,8 +2542,8 @@ TEST(WasiTest, ClockTimeGet) { Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), __WASI_ERRNO_SUCCESS); const uint64_t Time = convertFiletime(SysNow); - EXPECT_NEAR(static_cast<double>(*MemInst.getPointer<const uint64_t *>(0)), - static_cast<double>(Time), 1000000.0); + EXPECT_NEAR(static_cast<double>(*MemInst.getPointer<const uint64_t *>(0)), + static_cast<double>(Time), 1000000.0); } #endif diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt new file mode 100644 index 000000000000..77afa639c838 --- /dev/null +++ b/test/llvm/CMakeLists.txt @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +wasmedge_add_executable(wasmedgeLLVMCoreTests + LLVMcoreTest.cpp +) + +add_test(wasmedgeLLVMCoreTests wasmedgeLLVMCoreTests) + +target_link_libraries(wasmedgeLLVMCoreTests + PRIVATE + std::filesystem + ${GTEST_BOTH_LIBRARIES} + wasmedgeTestSpec + wasmedgeLoader + wasmedgeLLVM + wasmedgeVM +) diff --git a/test/aot/AOTcoreTest.cpp b/test/llvm/LLVMcoreTest.cpp similarity index 73% rename from test/aot/AOTcoreTest.cpp rename to test/llvm/LLVMcoreTest.cpp index bf06003f4ede..f476aec52c51 100644 --- a/test/aot/AOTcoreTest.cpp +++ b/test/llvm/LLVMcoreTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/aot/AOTcoreTest.cpp - Wasm test suites --------------===// // @@ -14,10 +14,11 @@ /// //===----------------------------------------------------------------------===// -#include "aot/compiler.h" #include "common/defines.h" -#include "common/log.h" +#include "common/spdlog.h" #include "vm/vm.h" +#include "llvm/codegen.h" +#include "llvm/compiler.h" #include "../spec/hostfunc.h" #include "../spec/spectest.h" @@ -44,6 +45,7 @@ static SpecTest T(std::filesystem::u8path("../spec/testSuites"sv)); // Parameterized testing class. class NativeCoreTest : public testing::TestWithParam<std::string> {}; class CustomWasmCoreTest : public testing::TestWithParam<std::string> {}; +class JITCoreTest : public testing::TestWithParam<std::string> {}; TEST_P(NativeCoreTest, TestSuites) { const auto [Proposal, Conf, UnitName] = T.resolve(GetParam()); @@ -60,24 +62,27 @@ TEST_P(NativeCoreTest, TestSuites) { CopyConf.getCompilerConfigure().setOptimizationLevel( WasmEdge::CompilerConfigure::OptimizationLevel::O0); CopyConf.getCompilerConfigure().setDumpIR(true); - WasmEdge::AOT::Compiler Compiler(CopyConf); + WasmEdge::LLVM::Compiler Compiler(CopyConf); + WasmEdge::LLVM::CodeGen CodeGen(CopyConf); auto Path = std::filesystem::u8path(Filename); Path.replace_extension(std::filesystem::u8path(WASMEDGE_LIB_EXTENSION)); const auto SOPath = Path.u8string(); - auto Data = *Loader.loadFile(Filename); + std::vector<WasmEdge::Byte> Data; std::unique_ptr<WasmEdge::AST::Module> Module; - if (auto Res = Loader.parseModule(Data)) { - Module = std::move(*Res); - } else { - return Unexpect(Res); - } - if (auto Res = ValidatorEngine.validate(*Module); !Res) { - return Unexpect(Res); - } - if (auto Res = Compiler.compile(Data, *Module, SOPath); !Res) { - return Unexpect(Res); - } - return SOPath; + return Loader.loadFile(Filename) + .and_then([&](auto Result) noexcept { + Data = std::move(Result); + return Loader.parseModule(Data); + }) + .and_then([&](auto Result) noexcept { + Module = std::move(Result); + return ValidatorEngine.validate(*Module); + }) + .and_then([&]() noexcept { return Compiler.compile(*Module); }) + .and_then([&](auto Result) noexcept { + return CodeGen.codegen(Data, std::move(Result), SOPath); + }) + .and_then([&]() noexcept { return Expect<std::string>{SOPath}; }); }; T.onModule = [&VM, &Compile](const std::string &ModName, const std::string &Filename) -> Expect<void> { @@ -166,24 +171,27 @@ TEST_P(CustomWasmCoreTest, TestSuites) { CopyConf.getCompilerConfigure().setOptimizationLevel( WasmEdge::CompilerConfigure::OptimizationLevel::O0); CopyConf.getCompilerConfigure().setDumpIR(true); - WasmEdge::AOT::Compiler Compiler(CopyConf); + WasmEdge::LLVM::Compiler Compiler(CopyConf); + WasmEdge::LLVM::CodeGen CodeGen(CopyConf); auto Path = std::filesystem::u8path(Filename); Path.replace_extension(std::filesystem::u8path(".aot.wasm")); const auto SOPath = Path.u8string(); - auto Data = *Loader.loadFile(Filename); + std::vector<WasmEdge::Byte> Data; std::unique_ptr<WasmEdge::AST::Module> Module; - if (auto Res = Loader.parseModule(Data)) { - Module = std::move(*Res); - } else { - return Unexpect(Res); - } - if (auto Res = ValidatorEngine.validate(*Module); !Res) { - return Unexpect(Res); - } - if (auto Res = Compiler.compile(Data, *Module, SOPath); !Res) { - return Unexpect(Res); - } - return SOPath; + return Loader.loadFile(Filename) + .and_then([&](auto Result) noexcept { + Data = std::move(Result); + return Loader.parseModule(Data); + }) + .and_then([&](auto Result) noexcept { + Module = std::move(Result); + return ValidatorEngine.validate(*Module); + }) + .and_then([&]() noexcept { return Compiler.compile(*Module); }) + .and_then([&](auto Result) noexcept { + return CodeGen.codegen(Data, std::move(Result), SOPath); + }) + .and_then([&]() noexcept { return Expect<std::string>{SOPath}; }); }; T.onModule = [&VM, &Compile](const std::string &ModName, const std::string &Filename) -> Expect<void> { @@ -259,6 +267,79 @@ TEST_P(CustomWasmCoreTest, TestSuites) { T.run(Proposal, UnitName); } +TEST_P(JITCoreTest, TestSuites) { + const auto [Proposal, Conf, UnitName] = T.resolve(GetParam()); + WasmEdge::Configure CopyConf = Conf; + CopyConf.getRuntimeConfigure().setEnableJIT(true); + CopyConf.getCompilerConfigure().setOptimizationLevel( + WasmEdge::CompilerConfigure::OptimizationLevel::O0); + CopyConf.getCompilerConfigure().setDumpIR(true); + WasmEdge::VM::VM VM(CopyConf); + WasmEdge::SpecTestModule SpecTestMod; + VM.registerModule(SpecTestMod); + T.onModule = [&VM](const std::string &ModName, + const std::string &Filename) -> Expect<void> { + if (!ModName.empty()) { + return VM.registerModule(ModName, Filename); + } else { + return VM.loadWasm(Filename) + .and_then([&VM]() { return VM.validate(); }) + .and_then([&VM]() { return VM.instantiate(); }); + } + }; + T.onLoad = [&VM](const std::string &Filename) -> Expect<void> { + return VM.loadWasm(Filename); + }; + T.onValidate = [&VM](const std::string &Filename) -> Expect<void> { + return VM.loadWasm(Filename).and_then([&VM]() { return VM.validate(); }); + }; + T.onInstantiate = [&VM](const std::string &Filename) -> Expect<void> { + return VM.loadWasm(Filename) + .and_then([&VM]() { return VM.validate(); }) + .and_then([&VM]() { return VM.instantiate(); }); + }; + // Helper function to call functions. + T.onInvoke = [&VM](const std::string &ModName, const std::string &Field, + const std::vector<ValVariant> &Params, + const std::vector<ValType> &ParamTypes) + -> Expect<std::vector<std::pair<ValVariant, ValType>>> { + if (!ModName.empty()) { + // Invoke function of named module. Named modules are registered in Store + // Manager. + return VM.execute(ModName, Field, Params, ParamTypes); + } else { + // Invoke function of anonymous module. Anonymous modules are instantiated + // in VM. + return VM.execute(Field, Params, ParamTypes); + } + }; + // Helper function to get values. + T.onGet = [&VM](const std::string &ModName, const std::string &Field) + -> Expect<std::pair<ValVariant, ValType>> { + // Get module instance. + const WasmEdge::Runtime::Instance::ModuleInstance *ModInst = nullptr; + if (ModName.empty()) { + ModInst = VM.getActiveModule(); + } else { + ModInst = VM.getStoreManager().findModule(ModName); + } + if (ModInst == nullptr) { + return Unexpect(ErrCode::Value::WrongInstanceAddress); + } + + // Get global instance. + WasmEdge::Runtime::Instance::GlobalInstance *GlobInst = + ModInst->findGlobalExports(Field); + if (unlikely(GlobInst == nullptr)) { + return Unexpect(ErrCode::Value::WrongInstanceAddress); + } + return std::make_pair(GlobInst->getValue(), + GlobInst->getGlobalType().getValType()); + }; + + T.run(Proposal, UnitName); +} + // Initiate test suite. INSTANTIATE_TEST_SUITE_P( TestUnit, NativeCoreTest, @@ -266,6 +347,9 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P( TestUnit, CustomWasmCoreTest, testing::ValuesIn(T.enumerate(SpecTest::TestMode::AOT))); +INSTANTIATE_TEST_SUITE_P( + TestUnit, JITCoreTest, + testing::ValuesIn(T.enumerate(SpecTest::TestMode::JIT))); std::array<WasmEdge::Byte, 46> AsyncWasm{ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, @@ -282,12 +366,15 @@ TEST(AsyncRunWsmFile, NativeInterruptTest) { WasmEdge::VM::VM VM(Conf); WasmEdge::Loader::Loader Loader(Conf); WasmEdge::Validator::Validator ValidatorEngine(Conf); - WasmEdge::AOT::Compiler Compiler(Conf); + WasmEdge::LLVM::Compiler Compiler(Conf); + WasmEdge::LLVM::CodeGen CodeGen(Conf); auto Path = std::filesystem::temp_directory_path() / std::filesystem::u8path("AOTcoreTest" WASMEDGE_LIB_EXTENSION); auto Module = *Loader.parseModule(AsyncWasm); ASSERT_TRUE(ValidatorEngine.validate(*Module)); - ASSERT_TRUE(Compiler.compile(AsyncWasm, *Module, Path)); + auto Data = Compiler.compile(*Module); + ASSERT_TRUE(Data); + ASSERT_TRUE(CodeGen.codegen(AsyncWasm, std::move(*Data), Path)); { auto Timeout = std::chrono::system_clock::now() + std::chrono::milliseconds(1); @@ -320,12 +407,15 @@ TEST(AsyncExecute, NativeInterruptTest) { WasmEdge::VM::VM VM(Conf); WasmEdge::Loader::Loader Loader(Conf); WasmEdge::Validator::Validator ValidatorEngine(Conf); - WasmEdge::AOT::Compiler Compiler(Conf); + WasmEdge::LLVM::Compiler Compiler(Conf); + WasmEdge::LLVM::CodeGen CodeGen(Conf); auto Path = std::filesystem::temp_directory_path() / std::filesystem::u8path("AOTcoreTest" WASMEDGE_LIB_EXTENSION); auto Module = *Loader.parseModule(AsyncWasm); ASSERT_TRUE(ValidatorEngine.validate(*Module)); - ASSERT_TRUE(Compiler.compile(AsyncWasm, *Module, Path)); + auto Data = Compiler.compile(*Module); + ASSERT_TRUE(Data); + ASSERT_TRUE(CodeGen.codegen(AsyncWasm, std::move(*Data), Path)); ASSERT_TRUE(VM.loadWasm(Path)); ASSERT_TRUE(VM.validate()); ASSERT_TRUE(VM.instantiate()); @@ -361,12 +451,15 @@ TEST(AsyncRunWsmFile, CustomWasmInterruptTest) { WasmEdge::VM::VM VM(Conf); WasmEdge::Loader::Loader Loader(Conf); WasmEdge::Validator::Validator ValidatorEngine(Conf); - WasmEdge::AOT::Compiler Compiler(Conf); + WasmEdge::LLVM::Compiler Compiler(Conf); + WasmEdge::LLVM::CodeGen CodeGen(Conf); auto Path = std::filesystem::temp_directory_path() / std::filesystem::u8path("AOTcoreTest.aot.wasm"); auto Module = *Loader.parseModule(AsyncWasm); ASSERT_TRUE(ValidatorEngine.validate(*Module)); - ASSERT_TRUE(Compiler.compile(AsyncWasm, *Module, Path)); + auto Data = Compiler.compile(*Module); + ASSERT_TRUE(Data); + ASSERT_TRUE(CodeGen.codegen(AsyncWasm, std::move(*Data), Path)); { auto Timeout = std::chrono::system_clock::now() + std::chrono::milliseconds(1); @@ -399,12 +492,15 @@ TEST(AsyncExecute, CustomWasmInterruptTest) { WasmEdge::VM::VM VM(Conf); WasmEdge::Loader::Loader Loader(Conf); WasmEdge::Validator::Validator ValidatorEngine(Conf); - WasmEdge::AOT::Compiler Compiler(Conf); + WasmEdge::LLVM::Compiler Compiler(Conf); + WasmEdge::LLVM::CodeGen CodeGen(Conf); auto Path = std::filesystem::temp_directory_path() / std::filesystem::u8path("AOTcoreTest.aot.wasm"); auto Module = *Loader.parseModule(AsyncWasm); ASSERT_TRUE(ValidatorEngine.validate(*Module)); - ASSERT_TRUE(Compiler.compile(AsyncWasm, *Module, Path)); + auto Data = Compiler.compile(*Module); + ASSERT_TRUE(Data); + ASSERT_TRUE(CodeGen.codegen(AsyncWasm, std::move(*Data), Path)); ASSERT_TRUE(VM.loadWasm(Path)); ASSERT_TRUE(VM.validate()); ASSERT_TRUE(VM.instantiate()); diff --git a/test/loader/CMakeLists.txt b/test/loader/CMakeLists.txt index e5ad9d9d4b64..3ee5bb56543f 100644 --- a/test/loader/CMakeLists.txt +++ b/test/loader/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeLoaderFileMgrTests filemgrTest.cpp diff --git a/test/loader/descriptionTest.cpp b/test/loader/descriptionTest.cpp index 981ed19a2dc0..174898f04617 100644 --- a/test/loader/descriptionTest.cpp +++ b/test/loader/descriptionTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/loader/descriptionTest.cpp - Load AST description ---===// // @@ -179,7 +179,7 @@ TEST(DescriptionTest, LoadExportDesc) { 0x0AU, // Content size = 10 0x01U, // Vector length = 1 0x06U, 0x4CU, 0x6FU, 0x61U, 0x64U, 0x65U, 0x72U, // External name: Loader - 0x04U, 0x00U // Invalid external type + 0x05U, 0x00U // Invalid external type }; EXPECT_FALSE(Ldr.parseModule(prefixedVec(Vec))); diff --git a/test/loader/expressionTest.cpp b/test/loader/expressionTest.cpp index 1e956f92b15c..7216e02b2f72 100644 --- a/test/loader/expressionTest.cpp +++ b/test/loader/expressionTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/loader/expressionTest.cpp - Load AST expression tests===// // diff --git a/test/loader/filemgrTest.cpp b/test/loader/filemgrTest.cpp index 35923a917550..272f18895e4a 100644 --- a/test/loader/filemgrTest.cpp +++ b/test/loader/filemgrTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/loader/filemgrTest.cpp - file manager unit tests ----===// // @@ -369,8 +369,148 @@ TEST(FileManagerTest, File__ReadSigned64TooLarge) { EXPECT_EQ(WasmEdge::ErrCode::Value::IntegerTooLarge, ReadNum.error()); } +TEST(FileManagerTest, File__PeekByte) { + // 19. Test unsigned char peeking. + WasmEdge::Expect<uint8_t> PeekByte; + ASSERT_TRUE(Mgr.setPath("filemgrTestData/readByteTest.bin")); + EXPECT_EQ(0U, Mgr.getOffset()); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x00, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0xFF, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x1F, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x2E, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x3D, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x4C, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x5B, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x6A, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x79, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x88, PeekByte.value()); + Mgr.readByte(); + ASSERT_FALSE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(10U, Mgr.getOffset()); +} + +TEST(FileManagerTest, File__ReadSigned33) { + // 20. Test signed 33bit integer decoding. + WasmEdge::Expect<int64_t> ReadNum; + // Reuse the test data of reading S32 + ASSERT_TRUE(Mgr.setPath("filemgrTestData/readS32Test.bin")); + EXPECT_EQ(0U, Mgr.getOffset()); + ASSERT_TRUE(ReadNum = Mgr.readS33()); + EXPECT_EQ(0, ReadNum.value()); + ASSERT_TRUE(ReadNum = Mgr.readS33()); + EXPECT_EQ(INT32_MAX, ReadNum.value()); + ASSERT_TRUE(ReadNum = Mgr.readS33()); + EXPECT_EQ(INT32_MIN, ReadNum.value()); + ASSERT_TRUE(ReadNum = Mgr.readS33()); + EXPECT_EQ(-1, ReadNum.value()); + ASSERT_TRUE(ReadNum = Mgr.readS33()); + EXPECT_EQ(1, ReadNum.value()); + ASSERT_TRUE(ReadNum = Mgr.readS33()); + EXPECT_EQ(134, ReadNum.value()); + ASSERT_TRUE(ReadNum = Mgr.readS33()); + EXPECT_EQ(-348415746, ReadNum.value()); + ASSERT_TRUE(ReadNum = Mgr.readS33()); + EXPECT_EQ(13018, ReadNum.value()); + ASSERT_TRUE(ReadNum = Mgr.readS33()); + EXPECT_EQ(-98765432, ReadNum.value()); + ASSERT_TRUE(ReadNum = Mgr.readS33()); + EXPECT_EQ(891055, ReadNum.value()); + ASSERT_FALSE(ReadNum = Mgr.readS33()); + EXPECT_EQ(30U, Mgr.getOffset()); + + std::vector<uint8_t> TestData = { + // First number. + // The first 4 bytes are 0b11111111, which indicates 4*7=28 lowest bits + // be 1. + // The last byte is 0b00001111. The highest bit is 0, indicating that this + // is the last byte. The fifth lowest bit is 0, indicating this number is + // a positive number. Therefore, the sixth and seventh bit must also be 0. + // The lowest 4 bits are all 1. + // In total, the represented number is 2^32 - 1. + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x0F, + // Second number. + // The first 4 bytes are 0b10000000, which indicates 4*7=28 lowest bits + // be 0. + // The last byte is 0b01110000. The highest bit is 0, indicating that this + // is the last byte. The fifth lowest bit is 1, indicating this number is + // a negative number. Therefore, the sixth and seventh bit must also be 1. + // The lowest 4 bits are all 0. + // In total, the represented number is 0b1 with 32 tailing zeros, which is + // -2^32. + 0x80, + 0x80, + 0x80, + 0x80, + 0x70, + }; + + ASSERT_TRUE(Mgr.setCode(std::move(TestData))); + ASSERT_EQ((1LL << 32) - 1, Mgr.readS33().value()); + ASSERT_EQ(5, Mgr.getOffset()); + ASSERT_EQ(-(1LL << 32), Mgr.readS33().value()); + ASSERT_EQ(10, Mgr.getOffset()); +} + +TEST(FileManagerTest, File__ReadSigned33TooLong) { + // 21. Test signed 33bit integer decoding in too long case. + WasmEdge::Expect<int64_t> ReadNum; + // Reuse the test data of reading S32. Loading too long for S32 is the same as + // S33, since both of them occupy at most 5 bytes. + ASSERT_TRUE(Mgr.setPath("filemgrTestData/readS32TestTooLong.bin")); + ASSERT_FALSE(ReadNum = Mgr.readS33()); + EXPECT_EQ(WasmEdge::ErrCode::Value::IntegerTooLong, ReadNum.error()); +} + +TEST(FileManagerTest, File__ReadSigned33TooLarge) { + // 22. Test signed 33bit integer decoding in too large case. + WasmEdge::Expect<int64_t> ReadNum; + // The first 4 bytes starts with bit 1, which indicates there is a coming + // fifth byte. The last byte is 0b00101111. The highest bit is 0, indicating + // that this is the last byte. The fifth lowest bit is 0, indicating this + // number is a positive number. Therefore, the sixth and seventh bit must also + // be 0. However, the sixth lowest bit is 1, which will cause loading a too + // large positive number. + ASSERT_TRUE( + Mgr.setCode(std::vector<uint8_t>({0xFF, 0xFF, 0xFF, 0xFF, 0x1F}))); + ASSERT_FALSE(ReadNum = Mgr.readS33()); + EXPECT_EQ(WasmEdge::ErrCode::Value::IntegerTooLarge, ReadNum.error()); + // The first 4 bytes starts with bit 1, which indicates there is a coming + // fifth byte. The last byte is 0b01011111. The highest bit is 0, indicating + // that this is the last byte. The fifth lowest bit is 1, indicating this + // number is a negative number. Therefore, the sixth and seventh bit must also + // be 1. However, the sixth lowest bit is 0, which will cause loading a too + // large negative number. + ASSERT_TRUE( + Mgr.setCode(std::vector<uint8_t>({0xFF, 0xFF, 0xFF, 0xFF, 0x5F}))); + ASSERT_FALSE(ReadNum = Mgr.readS33()); + EXPECT_EQ(WasmEdge::ErrCode::Value::IntegerTooLarge, ReadNum.error()); +} + TEST(FileManagerTest, Vector__ReadByte) { - // 19. Test unsigned char reading. + // 1. Test unsigned char reading. WasmEdge::Expect<uint8_t> ReadByte; ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{0x00, 0xFF, 0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A, 0x79, 0x88})); @@ -402,7 +542,7 @@ TEST(FileManagerTest, Vector__ReadByte) { } TEST(FileManagerTest, Vector__ReadBytes) { - // 20. Test unsigned char list reading. + // 2. Test unsigned char list reading. WasmEdge::Expect<std::vector<uint8_t>> ReadBytes; ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{0x00, 0xFF, 0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A, 0x79, 0x88})); @@ -428,7 +568,7 @@ TEST(FileManagerTest, Vector__ReadBytes) { } TEST(FileManagerTest, Vector__ReadUnsigned32) { - // 21. Test unsigned 32bit integer decoding. + // 3. Test unsigned 32bit integer decoding. WasmEdge::Expect<uint32_t> ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x80, 0x80, 0x80, 0x08, 0xFF, @@ -462,7 +602,7 @@ TEST(FileManagerTest, Vector__ReadUnsigned32) { } TEST(FileManagerTest, Vector__ReadUnsigned64) { - // 22. Test unsigned 64bit integer decoding. + // 4. Test unsigned 64bit integer decoding. WasmEdge::Expect<uint64_t> ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x80, 0x80, @@ -499,7 +639,7 @@ TEST(FileManagerTest, Vector__ReadUnsigned64) { } TEST(FileManagerTest, Vector__ReadSigned32) { - // 23. Test signed 32bit integer decoding. + // 5. Test signed 32bit integer decoding. WasmEdge::Expect<int32_t> ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x80, 0x80, 0x80, @@ -533,7 +673,7 @@ TEST(FileManagerTest, Vector__ReadSigned32) { } TEST(FileManagerTest, Vector__ReadSigned64) { - // 24. Test signed 64bit integer decoding. + // 6. Test signed 64bit integer decoding. WasmEdge::Expect<int64_t> ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, @@ -570,7 +710,7 @@ TEST(FileManagerTest, Vector__ReadSigned64) { } TEST(FileManagerTest, Vector__ReadFloat32) { - // 25. Test Special Cases float. + // 7. Test Special Cases float. // // 1. +0.0 // 2. -0.0 @@ -612,7 +752,7 @@ TEST(FileManagerTest, Vector__ReadFloat32) { } TEST(FileManagerTest, Vector__ReadFloat64) { - // 26. Test Special Cases double. + // 8. Test Special Cases double. // // 1. +0.0 // 2. -0.0 @@ -657,7 +797,7 @@ TEST(FileManagerTest, Vector__ReadFloat64) { } TEST(FileManagerTest, Vector__ReadName) { - // 27. Test utf-8 string reading. + // 9. Test utf-8 string reading. WasmEdge::Expect<std::string> ReadStr; ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x01, 0x20, 0x06, 0x4C, @@ -678,7 +818,7 @@ TEST(FileManagerTest, Vector__ReadName) { } TEST(FileManagerTest, Vector__ReadUnsigned32TooLong) { - // 28. Test unsigned 32bit integer decoding in too long case. + // 10. Test unsigned 32bit integer decoding in too long case. WasmEdge::Expect<uint32_t> ReadNum; ASSERT_TRUE( Mgr.setCode(std::vector<uint8_t>{0x80, 0x80, 0x80, 0x80, 0x80, 0x00})); @@ -687,7 +827,7 @@ TEST(FileManagerTest, Vector__ReadUnsigned32TooLong) { } TEST(FileManagerTest, Vector__ReadUnsigned32TooLarge) { - // 29. Test unsigned 32bit integer decoding in too large case. + // 11. Test unsigned 32bit integer decoding in too large case. WasmEdge::Expect<uint32_t> ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{0x80, 0x80, 0x80, 0x80, 0x1F})); ASSERT_FALSE(ReadNum = Mgr.readU32()); @@ -695,7 +835,7 @@ TEST(FileManagerTest, Vector__ReadUnsigned32TooLarge) { } TEST(FileManagerTest, Vector__ReadSigned32TooLong) { - // 30. Test signed 32bit integer decoding in too long case. + // 12. Test signed 32bit integer decoding in too long case. WasmEdge::Expect<int32_t> ReadNum; ASSERT_TRUE( Mgr.setCode(std::vector<uint8_t>{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F})); @@ -704,7 +844,7 @@ TEST(FileManagerTest, Vector__ReadSigned32TooLong) { } TEST(FileManagerTest, Vector__ReadSigned32TooLarge) { - // 31. Test signed 32bit integer decoding in too large case. + // 13. Test signed 32bit integer decoding in too large case. WasmEdge::Expect<int32_t> ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{0xFF, 0xFF, 0xFF, 0xFF, 0x4F})); ASSERT_FALSE(ReadNum = Mgr.readS32()); @@ -712,7 +852,7 @@ TEST(FileManagerTest, Vector__ReadSigned32TooLarge) { } TEST(FileManagerTest, Vector__ReadUnsigned64TooLong) { - // 32. Test unsigned 64bit integer decoding in too long case. + // 14. Test unsigned 64bit integer decoding in too long case. WasmEdge::Expect<uint64_t> ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00})); @@ -721,7 +861,7 @@ TEST(FileManagerTest, Vector__ReadUnsigned64TooLong) { } TEST(FileManagerTest, Vector__ReadUnsigned64TooLarge) { - // 33. Test unsigned 64bit integer decoding in too large case. + // 15. Test unsigned 64bit integer decoding in too large case. WasmEdge::Expect<uint64_t> ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7E})); @@ -730,7 +870,7 @@ TEST(FileManagerTest, Vector__ReadUnsigned64TooLarge) { } TEST(FileManagerTest, Vector__ReadSigned64TooLong) { - // 34. Test signed 64bit integer decoding in too long case. + // 16. Test signed 64bit integer decoding in too long case. WasmEdge::Expect<int64_t> ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F})); @@ -739,7 +879,7 @@ TEST(FileManagerTest, Vector__ReadSigned64TooLong) { } TEST(FileManagerTest, Vector__ReadSigned64TooLarge) { - // 35. Test signed 64bit integer decoding in too large case. + // 17. Test signed 64bit integer decoding in too large case. WasmEdge::Expect<int64_t> ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x41})); @@ -747,106 +887,46 @@ TEST(FileManagerTest, Vector__ReadSigned64TooLarge) { EXPECT_EQ(WasmEdge::ErrCode::Value::IntegerTooLarge, ReadNum.error()); } -TEST(FileManagerTest, File__ReadSigned33) { - // 36. Test signed 33bit integer decoding. - WasmEdge::Expect<int64_t> ReadNum; - // Reuse the test data of reading S32 - ASSERT_TRUE(Mgr.setPath("filemgrTestData/readS32Test.bin")); +TEST(FileManagerTest, Vector__PeekByte) { + // 18. Test unsigned char peeking. + WasmEdge::Expect<uint8_t> PeekByte; + ASSERT_TRUE(Mgr.setCode(std::vector<uint8_t>{0x00, 0xFF, 0x1F, 0x2E, 0x3D, + 0x4C, 0x5B, 0x6A, 0x79, 0x88})); EXPECT_EQ(0U, Mgr.getOffset()); - ASSERT_TRUE(ReadNum = Mgr.readS33()); - EXPECT_EQ(0, ReadNum.value()); - ASSERT_TRUE(ReadNum = Mgr.readS33()); - EXPECT_EQ(INT32_MAX, ReadNum.value()); - ASSERT_TRUE(ReadNum = Mgr.readS33()); - EXPECT_EQ(INT32_MIN, ReadNum.value()); - ASSERT_TRUE(ReadNum = Mgr.readS33()); - EXPECT_EQ(-1, ReadNum.value()); - ASSERT_TRUE(ReadNum = Mgr.readS33()); - EXPECT_EQ(1, ReadNum.value()); - ASSERT_TRUE(ReadNum = Mgr.readS33()); - EXPECT_EQ(134, ReadNum.value()); - ASSERT_TRUE(ReadNum = Mgr.readS33()); - EXPECT_EQ(-348415746, ReadNum.value()); - ASSERT_TRUE(ReadNum = Mgr.readS33()); - EXPECT_EQ(13018, ReadNum.value()); - ASSERT_TRUE(ReadNum = Mgr.readS33()); - EXPECT_EQ(-98765432, ReadNum.value()); - ASSERT_TRUE(ReadNum = Mgr.readS33()); - EXPECT_EQ(891055, ReadNum.value()); - ASSERT_FALSE(ReadNum = Mgr.readS33()); - EXPECT_EQ(30U, Mgr.getOffset()); - - std::vector<uint8_t> TestData = { - // First number. - // The first 4 bytes are 0b11111111, which indicates 4*7=28 lowest bits - // be 1. - // The last byte is 0b00001111. The highest bit is 0, indicating that this - // is the last byte. The fifth lowest bit is 0, indicating this number is - // a positive number. Therefore, the sixth and seventh bit must also be 0. - // The lowest 4 bits are all 1. - // In total, the represented number is 2^32 - 1. - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0x0F, - // Second number. - // The first 4 bytes are 0b10000000, which indicates 4*7=28 lowest bits - // be 0. - // The last byte is 0b01110000. The highest bit is 0, indicating that this - // is the last byte. The fifth lowest bit is 1, indicating this number is - // a negative number. Therefore, the sixth and seventh bit must also be 1. - // The lowest 4 bits are all 0. - // In total, the represented number is 0b1 with 32 tailing zeros, which is - // -2^32. - 0x80, - 0x80, - 0x80, - 0x80, - 0x70, - }; - - ASSERT_TRUE(Mgr.setCode(std::move(TestData))); - ASSERT_EQ((1LL << 32) - 1, Mgr.readS33().value()); - ASSERT_EQ(5, Mgr.getOffset()); - ASSERT_EQ(-(1LL << 32), Mgr.readS33().value()); - ASSERT_EQ(10, Mgr.getOffset()); -} - -TEST(FileManagerTest, File__ReadSigned33TooLong) { - // 37. Test signed 33bit integer decoding in too long case. - WasmEdge::Expect<int64_t> ReadNum; - // Reuse the test data of reading S32. Loading too long for S32 is the same as - // S33, since both of them occupy at most 5 bytes. - ASSERT_TRUE(Mgr.setPath("filemgrTestData/readS32TestTooLong.bin")); - ASSERT_FALSE(ReadNum = Mgr.readS33()); - EXPECT_EQ(WasmEdge::ErrCode::Value::IntegerTooLong, ReadNum.error()); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x00, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0xFF, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x1F, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x2E, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x3D, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x4C, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x5B, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x6A, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x79, PeekByte.value()); + Mgr.readByte(); + ASSERT_TRUE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(0x88, PeekByte.value()); + Mgr.readByte(); + ASSERT_FALSE(PeekByte = Mgr.peekByte()); + EXPECT_EQ(10U, Mgr.getOffset()); } -TEST(FileManagerTest, File__ReadSigned33TooLarge) { - // 38. Test signed 33bit integer decoding in too large case. - WasmEdge::Expect<int64_t> ReadNum; - // The first 4 bytes starts with bit 1, which indicates there is a coming - // fifth byte. The last byte is 0b00101111. The highest bit is 0, indicating - // that this is the last byte. The fifth lowest bit is 0, indicating this - // number is a positive number. Therefore, the sixth and seventh bit must also - // be 0. However, the sixth lowest bit is 1, which will cause loading a too - // large positive number. - ASSERT_TRUE( - Mgr.setCode(std::vector<uint8_t>({0xFF, 0xFF, 0xFF, 0xFF, 0x1F}))); - ASSERT_FALSE(ReadNum = Mgr.readS33()); - EXPECT_EQ(WasmEdge::ErrCode::Value::IntegerTooLarge, ReadNum.error()); - // The first 4 bytes starts with bit 1, which indicates there is a coming - // fifth byte. The last byte is 0b01011111. The highest bit is 0, indicating - // that this is the last byte. The fifth lowest bit is 1, indicating this - // number is a negative number. Therefore, the sixth and seventh bit must also - // be 1. However, the sixth lowest bit is 0, which will cause loading a too - // large negative number. - ASSERT_TRUE( - Mgr.setCode(std::vector<uint8_t>({0xFF, 0xFF, 0xFF, 0xFF, 0x5F}))); - ASSERT_FALSE(ReadNum = Mgr.readS33()); - EXPECT_EQ(WasmEdge::ErrCode::Value::IntegerTooLarge, ReadNum.error()); -} } // namespace GTEST_API_ int main(int argc, char **argv) { diff --git a/test/loader/instructionTest.cpp b/test/loader/instructionTest.cpp index 15ea71bba44d..5f6468ca443c 100644 --- a/test/loader/instructionTest.cpp +++ b/test/loader/instructionTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/loader/instructionTest.cpp - Instruction unit tests -===// // @@ -700,7 +700,7 @@ TEST(InstructionTest, LoadMemoryInstruction) { 0x0DU, // Code segment size = 13 0x00U, // Local vec(0) 0x28U, // OpCode I32__load. - 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0x0FU, // Align. + 0x8FU, 0x80U, 0x80U, 0x80U, 0x00U, // Align. 0xFEU, 0xFFU, 0xFFU, 0xFFU, 0x0FU, // Offset. 0x0BU // Expression End. }; diff --git a/test/loader/moduleTest.cpp b/test/loader/moduleTest.cpp index da1aaadaeaae..ae1c6651ce1b 100644 --- a/test/loader/moduleTest.cpp +++ b/test/loader/moduleTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/loader/moduleTest.cpp - Load AST module unit tests --===// // diff --git a/test/loader/sectionTest.cpp b/test/loader/sectionTest.cpp index a458789975b1..6f359f5fd1be 100644 --- a/test/loader/sectionTest.cpp +++ b/test/loader/sectionTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/loader/sectionTest.cpp - Load AST section unit tests ===// // diff --git a/test/loader/segmentTest.cpp b/test/loader/segmentTest.cpp index cbbc7f0d0017..12ac05cf962b 100644 --- a/test/loader/segmentTest.cpp +++ b/test/loader/segmentTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/loader/segmentTest.cpp - Load AST segment unit tests ===// // diff --git a/test/loader/serializeDescriptionTest.cpp b/test/loader/serializeDescriptionTest.cpp index b4249746f97c..8ee181154533 100644 --- a/test/loader/serializeDescriptionTest.cpp +++ b/test/loader/serializeDescriptionTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" diff --git a/test/loader/serializeExpressionTest.cpp b/test/loader/serializeExpressionTest.cpp index aef7dd67e4e6..fa114b357f58 100644 --- a/test/loader/serializeExpressionTest.cpp +++ b/test/loader/serializeExpressionTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" diff --git a/test/loader/serializeInstructionTest.cpp b/test/loader/serializeInstructionTest.cpp index ab19f4c46d35..e7fd5673ac1b 100644 --- a/test/loader/serializeInstructionTest.cpp +++ b/test/loader/serializeInstructionTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" @@ -42,7 +42,7 @@ TEST(SerializeInstructionTest, SerializeBlockControlInstruction) { WasmEdge::AST::Instruction I32Eq(WasmEdge::OpCode::I32__eq); WasmEdge::AST::Instruction I32Ne(WasmEdge::OpCode::I32__ne); - Block.setEmptyBlockType(); + Block.getBlockType().setEmpty(); Instructions = {Block, End, End}; Output = {}; EXPECT_TRUE(Ser.serializeSection(createCodeSec(Instructions), Output)); @@ -59,7 +59,7 @@ TEST(SerializeInstructionTest, SerializeBlockControlInstruction) { }; EXPECT_EQ(Output, Expected); - Loop.setEmptyBlockType(); + Loop.getBlockType().setEmpty(); Instructions = {Loop, End, End}; Output = {}; EXPECT_TRUE(Ser.serializeSection(createCodeSec(Instructions), Output)); @@ -76,7 +76,7 @@ TEST(SerializeInstructionTest, SerializeBlockControlInstruction) { }; EXPECT_EQ(Output, Expected); - Loop.setEmptyBlockType(); + Loop.getBlockType().setEmpty(); Instructions = {Block, I32Eqz, I32Eq, I32Ne, End, End}; Output = {}; EXPECT_TRUE(Ser.serializeSection(createCodeSec(Instructions), Output)); @@ -94,7 +94,7 @@ TEST(SerializeInstructionTest, SerializeBlockControlInstruction) { }; EXPECT_EQ(Output, Expected); - Loop.setEmptyBlockType(); + Loop.getBlockType().setEmpty(); Instructions = {Loop, I32Eqz, I32Eq, I32Ne, End, End}; Output = {}; EXPECT_TRUE(Ser.serializeSection(createCodeSec(Instructions), Output)); @@ -132,7 +132,7 @@ TEST(SerializeInstructionTest, SerializeIfElseControlInstruction) { WasmEdge::AST::Instruction I32Eq(WasmEdge::OpCode::I32__eq); WasmEdge::AST::Instruction I32Ne(WasmEdge::OpCode::I32__ne); - If.setEmptyBlockType(); + If.getBlockType().setEmpty(); Instructions = {If, End, End}; Output = {}; EXPECT_TRUE(Ser.serializeSection(createCodeSec(Instructions), Output)); @@ -149,7 +149,7 @@ TEST(SerializeInstructionTest, SerializeIfElseControlInstruction) { }; EXPECT_EQ(Output, Expected); - If.setEmptyBlockType(); + If.getBlockType().setEmpty(); Instructions = {If, Else, End, End}; Output = {}; EXPECT_TRUE(Ser.serializeSection(createCodeSec(Instructions), Output)); @@ -167,7 +167,7 @@ TEST(SerializeInstructionTest, SerializeIfElseControlInstruction) { }; EXPECT_EQ(Output, Expected); - If.setEmptyBlockType(); + If.getBlockType().setEmpty(); Instructions = {If, I32Eqz, I32Eq, I32Ne, End, End}; Output = {}; EXPECT_TRUE(Ser.serializeSection(createCodeSec(Instructions), Output)); @@ -185,7 +185,7 @@ TEST(SerializeInstructionTest, SerializeIfElseControlInstruction) { }; EXPECT_EQ(Output, Expected); - If.setEmptyBlockType(); + If.getBlockType().setEmpty(); Instructions = {If, I32Eqz, I32Eq, I32Ne, Else, I32Eqz, I32Eq, I32Ne, End, End}; Output = {}; diff --git a/test/loader/serializeModuleTest.cpp b/test/loader/serializeModuleTest.cpp index b18fee4d5892..f81e4538a5bb 100644 --- a/test/loader/serializeModuleTest.cpp +++ b/test/loader/serializeModuleTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" diff --git a/test/loader/serializeSectionTest.cpp b/test/loader/serializeSectionTest.cpp index ed193a6659e1..611140348063 100644 --- a/test/loader/serializeSectionTest.cpp +++ b/test/loader/serializeSectionTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" diff --git a/test/loader/serializeSegmentTest.cpp b/test/loader/serializeSegmentTest.cpp index b85cc575bb74..8f4fbe87d2b3 100644 --- a/test/loader/serializeSegmentTest.cpp +++ b/test/loader/serializeSegmentTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" diff --git a/test/loader/serializeTypeTest.cpp b/test/loader/serializeTypeTest.cpp index f1f00d4a190d..d71ea7269820 100644 --- a/test/loader/serializeTypeTest.cpp +++ b/test/loader/serializeTypeTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "loader/serialize.h" diff --git a/test/loader/typeTest.cpp b/test/loader/typeTest.cpp index 9b9487cb74d4..0c36b4ee667a 100644 --- a/test/loader/typeTest.cpp +++ b/test/loader/typeTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/loader/typeTest.cpp - Load AST type unit tests ------===// // diff --git a/test/memlimit/CMakeLists.txt b/test/memlimit/CMakeLists.txt index bc5d7037a115..809e7a226883 100644 --- a/test/memlimit/CMakeLists.txt +++ b/test/memlimit/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeMemLimitTests MemLimitTest.cpp diff --git a/test/memlimit/MemLimitTest.cpp b/test/memlimit/MemLimitTest.cpp index a30fbcde3ed8..2e90db665eed 100644 --- a/test/memlimit/MemLimitTest.cpp +++ b/test/memlimit/MemLimitTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/configure.h" #include "runtime/instance/memory.h" @@ -15,7 +15,8 @@ TEST(MemLimitTest, Limit__Pages) { MemInst Inst1(WasmEdge::AST::MemoryType(257), Conf.getRuntimeConfigure().getMaxMemoryPage()); - ASSERT_TRUE(Inst1.getDataPtr() == nullptr); + ASSERT_FALSE(Inst1.getDataPtr() == nullptr); + EXPECT_EQ(Inst1.getPageSize(), 256U); MemInst Inst2(WasmEdge::AST::MemoryType(257)); ASSERT_FALSE(Inst2.getDataPtr() == nullptr); diff --git a/test/mixcall/CMakeLists.txt b/test/mixcall/CMakeLists.txt index 9b2c37314498..6cea610f978a 100644 --- a/test/mixcall/CMakeLists.txt +++ b/test/mixcall/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeMixcallTests mixcallTest.cpp @@ -17,6 +17,6 @@ target_link_libraries(wasmedgeMixcallTests PRIVATE std::filesystem ${GTEST_BOTH_LIBRARIES} - wasmedgeAOT + wasmedgeLLVM wasmedgeVM ) diff --git a/test/mixcall/mixcallTest.cpp b/test/mixcall/mixcallTest.cpp index 892a61471ff1..894e9df6872e 100644 --- a/test/mixcall/mixcallTest.cpp +++ b/test/mixcall/mixcallTest.cpp @@ -1,15 +1,18 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC -#include "aot/compiler.h" #include "common/configure.h" #include "common/errinfo.h" #include "common/filesystem.h" +#include "experimental/span.hpp" #include "loader/loader.h" #include "runtime/instance/module.h" #include "validator/validator.h" #include "vm/vm.h" +#include "llvm/codegen.h" +#include "llvm/compiler.h" +#include <fmt/format.h> #include <gtest/gtest.h> #include <iostream> #include <vector> @@ -72,11 +75,10 @@ std::vector<uint8_t> Module2Wasm = { 0x5, 0x74, 0x79, 0x70, 0x65, 0x30, 0x1, 0x5, 0x74, 0x79, 0x70, 0x65, 0x31}; -void HexToFile(std::vector<uint8_t> &Wasm, const char *Path) { +void HexToFile(cxx20::span<const uint8_t> Wasm, const char *Path) { std::ofstream TFile(std::filesystem::u8path(Path), std::ios_base::binary); - for (auto &Hex : Wasm) { - TFile << Hex; - } + TFile.write(reinterpret_cast<const char *>(Wasm.data()), + static_cast<std::streamsize>(Wasm.size())); TFile.close(); } @@ -84,7 +86,8 @@ class HostPrintI32 : public WasmEdge::Runtime::HostFunction<HostPrintI32> { public: WasmEdge::Expect<void> body(const WasmEdge::Runtime::CallingFrame &, uint32_t Val) { - std::cout << "-- Host Function: print I32 " << Val << std::endl; + using namespace std::string_view_literals; + fmt::print("-- Host Function: print I32 {}\n"sv, Val); return {}; } }; @@ -93,7 +96,8 @@ class HostPrintF64 : public WasmEdge::Runtime::HostFunction<HostPrintF64> { public: WasmEdge::Expect<void> body(const WasmEdge::Runtime::CallingFrame &, double Val) { - std::cout << "-- Host Function: print F64 " << Val << std::endl; + using namespace std::string_view_literals; + fmt::print("-- Host Function: print F64 {}\n"sv, Val); return {}; } }; @@ -111,20 +115,25 @@ bool compileModule(const WasmEdge::Configure &Conf, std::string_view InPath, std::string_view OutPath) { WasmEdge::Loader::Loader Load(Conf); WasmEdge::Validator::Validator Valid(Conf); - WasmEdge::AOT::Compiler Compiler(Conf); + WasmEdge::LLVM::Compiler Compiler(Conf); + WasmEdge::LLVM::CodeGen CodeGen(Conf); - auto Mod = Load.parseModule(InPath); - auto Data = Load.loadFile(InPath); - if (!Mod || !Data) { - return false; - } - if (auto Res = Valid.validate(*(*Mod).get()); !Res) { - return false; - } - if (auto Res = Compiler.compile(*Data, *(*Mod).get(), OutPath); !Res) { - return false; - } - return true; + std::vector<WasmEdge::Byte> Data; + std::unique_ptr<WasmEdge::AST::Module> Module; + return Load.loadFile(InPath) + .and_then([&](auto Result) noexcept { + Data = std::move(Result); + return Load.parseModule(InPath); + }) + .and_then([&](auto Result) noexcept { + Module = std::move(Result); + return Valid.validate(*Module); + }) + .and_then([&]() noexcept { return Compiler.compile(*Module); }) + .and_then([&](auto Result) noexcept { + return CodeGen.codegen(Data, std::move(Result), OutPath); + }) + .has_value(); } TEST(MixCallTest, Call__InterpCallAOT) { diff --git a/test/plugins/CMakeLists.txt b/test/plugins/CMakeLists.txt index 808507fd0021..457b16533afc 100644 --- a/test/plugins/CMakeLists.txt +++ b/test/plugins/CMakeLists.txt @@ -1,62 +1,103 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC -if(WASMEDGE_PLUGIN_PROCESS) - if (CMAKE_SYSTEM_NAME MATCHES "Linux") - add_subdirectory(wasmedge_process) - endif() +# WASI plug-in: WASI-Crypto proposal. +if(WASMEDGE_PLUGIN_WASI_CRYPTO) + add_subdirectory(wasi_crypto) endif() -if(WASMEDGE_PLUGIN_ZLIB) - add_subdirectory(wasmedge_zlib) -endif() +# WASI plug-in: WASI-Logging proposal. +add_subdirectory(wasi_logging) +# WASI plug-in: WASI-NN proposal with backends. if(WASMEDGE_PLUGIN_WASI_NN_BACKEND) add_subdirectory(wasi_nn) endif() -if(WASMEDGE_PLUGIN_WASI_CRYPTO) - add_subdirectory(wasi_crypto) -endif() - -if(WASMEDGE_PLUGIN_TENSORFLOW) - if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") - add_subdirectory(wasmedge_tensorflow) +# WasmEdge plug-in: wasm-bpf. +if(WASMEDGE_PLUGIN_WASM_BPF) + # Only Linux systems support wasm_bpf now. + if(CMAKE_SYSTEM_NAME MATCHES "Linux") + add_subdirectory(wasm_bpf) + else() + message(WARNING "Only Linux platforms support wasm_bpf plug-in now.") endif() endif() -if(WASMEDGE_PLUGIN_TENSORFLOWLITE) - if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") - add_subdirectory(wasmedge_tensorflowlite) - endif() +# WasmEdge plug-in: ffmpeg. +if(WASMEDGE_PLUGIN_FFMPEG) + add_subdirectory(wasmedge_ffmpeg) endif() +# WasmEdge plug-in: Image. if(WASMEDGE_PLUGIN_IMAGE) + # Only Linux and MacOS support wasmedge_image now. if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") add_subdirectory(wasmedge_image) + else() + message(WARNING "Only Linux and Darwin platforms support WasmEdge_Image plug-in now.") endif() endif() +# WasmEdge plug-in: LLMC. +if(WASMEDGE_PLUGIN_LLMC) + add_subdirectory(wasmedge_llmc) +endif() + +# WasmEdge plug-in: OpenCV-mini. if(WASMEDGE_PLUGIN_OPENCVMINI) + # Only Linux and MacOS support wasmedge_opencvmini now. if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") add_subdirectory(wasmedge_opencvmini) + else() + message(WARNING "Only Linux and Darwin platforms support WasmEdge_OpenCVMini plug-in now.") endif() endif() -if(WASMEDGE_PLUGIN_WASM_BPF) +# WasmEdge plug-in: Process. +if(WASMEDGE_PLUGIN_PROCESS) + # Only Linux systems support wasmedge_process now. if(CMAKE_SYSTEM_NAME MATCHES "Linux") - add_subdirectory(wasm_bpf) + add_subdirectory(wasmedge_process) + else() + message(WARNING "Only Linux platforms support WasmEdge_Process plug-in now.") + endif() +endif() + +# WasmEdge plug-in: Stable-diffusion. +if(WASMEDGE_PLUGIN_STABLEDIFFUSION) + # Only Linux and MacOS support wasmedge_stablediffusion now. + if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") + add_subdirectory(wasmedge_stablediffusion) + else() + message(WARNING "Only Linux and Darwin platforms support WasmEdge_StableDiffusion plug-in now.") endif() endif() -if(WASMEDGE_PLUGIN_WASI_LOGGING) - add_subdirectory(wasi_logging) +# WasmEdge plug-in: TensorFlow. +if(WASMEDGE_PLUGIN_TENSORFLOW) + # Only Linux and MacOS support wasmedge_tensorflow now. + if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") + add_subdirectory(wasmedge_tensorflow) + else() + message(WARNING "Only Linux and Darwin platforms support WasmEdge_Tensorflow plug-in now.") + endif() endif() -if(WASMEDGE_PLUGIN_RUSTLS) - add_subdirectory(wasmedge_rustls) +# WasmEdge plug-in: TensorFlow-Lite. +if(WASMEDGE_PLUGIN_TENSORFLOWLITE) + # Only Linux and MacOS support wasmedge_tensorflowlite now. + if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") + add_subdirectory(wasmedge_tensorflowlite) + else() + message(WARNING "Only Linux and Darwin platforms support WasmEdge_TensorflowLite plug-in now.") + endif() endif() -if(CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Darwin") - add_subdirectory(unittest) +# WasmEdge plug-in: zlib. +if(WASMEDGE_PLUGIN_ZLIB) + add_subdirectory(wasmedge_zlib) endif() + +# Plug-in unit tests. +add_subdirectory(unittest) diff --git a/test/plugins/unittest/CMakeLists.txt b/test/plugins/unittest/CMakeLists.txt index 4631c0b44e35..8a0e2ad51bc7 100644 --- a/test/plugins/unittest/CMakeLists.txt +++ b/test/plugins/unittest/CMakeLists.txt @@ -1,16 +1,23 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC # The test plugin module in C API +enable_language(C) + wasmedge_add_library(wasmedgePluginTestModuleC SHARED testplugin.c -) + ) set_target_properties(wasmedgePluginTestModuleC PROPERTIES C_STANDARD 11 ) +# remove cxx_standard for msvc +set_property(TARGET wasmedgePluginTestModuleC PROPERTY + CXX_STANDARD +) + target_compile_options(wasmedgePluginTestModuleC PUBLIC -DWASMEDGE_PLUGIN diff --git a/test/plugins/unittest/testplugin.c b/test/plugins/unittest/testplugin.c index a0536101d982..a2be6472061d 100644 --- a/test/plugins/unittest/testplugin.c +++ b/test/plugins/unittest/testplugin.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "wasmedge/wasmedge.h" @@ -12,15 +12,15 @@ static WasmEdge_String NameString; static const char NameCString[] = "name"; static const WasmEdge_String NameStringDefaultValue = {.Buf = NameCString, .Length = 4}; -void Finalizer(void *Data) { +static void Finalizer(void *Data) { printf("Deallocate host data\n"); free((int32_t *)Data); } -WasmEdge_Result HostFuncAdd(void *Data, - const WasmEdge_CallingFrameContext *CallFrameCxt - __attribute__((unused)), - const WasmEdge_Value *In, WasmEdge_Value *Out) { +static WasmEdge_Result +HostFuncAdd(void *Data, const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + (void)CallFrameCxt; /* * Host function to calculate A + B, * and accumulate (A + B) to the host data. @@ -34,10 +34,10 @@ WasmEdge_Result HostFuncAdd(void *Data, return WasmEdge_Result_Success; } -WasmEdge_Result HostFuncSub(void *Data, - const WasmEdge_CallingFrameContext *CallFrameCxt - __attribute__((unused)), - const WasmEdge_Value *In, WasmEdge_Value *Out) { +static WasmEdge_Result +HostFuncSub(void *Data, const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + (void)CallFrameCxt; /* * Host function to calculate A - B, * and accumulate (A - B) to the host data. @@ -51,7 +51,7 @@ WasmEdge_Result HostFuncSub(void *Data, return WasmEdge_Result_Success; } -WasmEdge_ModuleInstanceContext * +static WasmEdge_ModuleInstanceContext * CreateTestModule(const struct WasmEdge_ModuleDescriptor *Desc) { /* Allocate and initialize a host data. */ printf("Allocate host data\n"); diff --git a/test/plugins/unittest/testplugin.cpp b/test/plugins/unittest/testplugin.cpp index 21431b14f063..589df415751b 100644 --- a/test/plugins/unittest/testplugin.cpp +++ b/test/plugins/unittest/testplugin.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "testplugin.h" #include "po/helper.h" @@ -19,12 +19,16 @@ PO::Option<std::string> WasmEdgePluginTestEnv::CmdName(PO::Description("Test for input name."sv), PO::DefaultValue(std::string(""))); +PO::Option<PO::Toggle> + WasmEdgePluginTestEnv::CmdOpt(PO::Description("Test for option."sv)); + namespace { void addOptions(const Plugin::Plugin::PluginDescriptor *, PO::ArgumentParser &Parser) noexcept { Parser.add_option("arg"sv, WasmEdgePluginTestEnv::CmdArgs) - .add_option("name"sv, WasmEdgePluginTestEnv::CmdName); + .add_option("name"sv, WasmEdgePluginTestEnv::CmdName) + .add_option("opt"sv, WasmEdgePluginTestEnv::CmdOpt); } Runtime::Instance::ModuleInstance * @@ -32,26 +36,28 @@ create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { return new WasmEdgePluginTestModule; } -Plugin::Plugin::PluginDescriptor Descriptor{ - .Name = "wasmedge_plugintest_cpp", - .Description = "", - .APIVersion = Plugin::Plugin::CurrentAPIVersion, - .Version = {0, 10, 0, 0}, - .ModuleCount = 1, - .ModuleDescriptions = - (Plugin::PluginModule::ModuleDescriptor[]){ - { - .Name = "wasmedge_plugintest_cpp_module", - .Description = "This is for the plugin tests in WasmEdge.", - .Create = create, - }, - }, - .AddOptions = addOptions, +static Plugin::PluginModule::ModuleDescriptor MD[]{ + { + /* Name */ "wasmedge_plugintest_cpp_module", + /* Description */ "This is for the plugin tests in WasmEdge.", + /* Create */ create, + }, }; -} // namespace +Plugin::Plugin::PluginDescriptor Descriptor{ + /* Name */ "wasmedge_plugintest_cpp", + /* Description */ "", + /* APIVersion */ Plugin::Plugin::CurrentAPIVersion, + /* Version */ {0, 10, 0, 0}, + /* ModuleCount */ 1, + /* ModuleDescriptions */ MD, + /* ComponentCount */ 0, + /* ComponentDescriptions */ nullptr, + /* AddOptions */ addOptions, +}; -Plugin::PluginRegister WasmEdgePluginTestEnv::Register(&Descriptor); +EXPORT_GET_DESCRIPTOR(Descriptor) +} // namespace } // namespace Host } // namespace WasmEdge diff --git a/test/plugins/unittest/testplugin.h b/test/plugins/unittest/testplugin.h index 214ab0495fcc..82376b3e9ccf 100644 --- a/test/plugins/unittest/testplugin.h +++ b/test/plugins/unittest/testplugin.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once @@ -20,7 +20,7 @@ class WasmEdgePluginTestEnv { static PO::List<std::string> CmdArgs; static PO::Option<std::string> CmdName; - static Plugin::PluginRegister Register; + static PO::Option<PO::Toggle> CmdOpt; }; template <typename T> @@ -63,6 +63,16 @@ class WasmEdgePluginTestFuncArgLen } }; +class WasmEdgePluginTestFuncOpt + : public WasmEdgePluginTestFunc<WasmEdgePluginTestFuncOpt> { +public: + WasmEdgePluginTestFuncOpt(WasmEdgePluginTestEnv &HostEnv) + : WasmEdgePluginTestFunc(HostEnv) {} + Expect<uint32_t> body(const Runtime::CallingFrame &) { + return static_cast<uint32_t>(Env.CmdOpt.value()); + } +}; + class WasmEdgePluginTestFuncNameSize : public WasmEdgePluginTestFunc<WasmEdgePluginTestFuncNameSize> { public: @@ -80,6 +90,7 @@ class WasmEdgePluginTestModule : public Runtime::Instance::ModuleInstance { addHostFunc("add", std::make_unique<WasmEdgePluginTestFuncAdd>(Env)); addHostFunc("sub", std::make_unique<WasmEdgePluginTestFuncSub>(Env)); addHostFunc("arg_len", std::make_unique<WasmEdgePluginTestFuncArgLen>(Env)); + addHostFunc("opt", std::make_unique<WasmEdgePluginTestFuncOpt>(Env)); addHostFunc("name_size", std::make_unique<WasmEdgePluginTestFuncNameSize>(Env)); } diff --git a/test/plugins/unittest/unittest_c.cpp b/test/plugins/unittest/unittest_c.cpp index 19f229932345..1943648b173a 100644 --- a/test/plugins/unittest/unittest_c.cpp +++ b/test/plugins/unittest/unittest_c.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #include "wasmedge/wasmedge.h" @@ -11,7 +11,8 @@ namespace { WasmEdge_ModuleInstanceContext *createModuleC() { WasmEdge_PluginLoadFromPath( - "./libwasmedgePluginTestModuleC" WASMEDGE_LIB_EXTENSION); + "./" WASMEDGE_LIB_PREFIX + "wasmedgePluginTestModuleC" WASMEDGE_LIB_EXTENSION); WasmEdge_String Str = WasmEdge_StringCreateByCString("wasmedge_plugintest_c"); const WasmEdge_PluginContext *PluginCxt = WasmEdge_PluginFind(Str); WasmEdge_StringDelete(Str); @@ -28,7 +29,8 @@ WasmEdge_ModuleInstanceContext *createModuleC() { WasmEdge_ModuleInstanceContext *createModuleCPP() { WasmEdge_PluginLoadFromPath( - "./libwasmedgePluginTestModuleCPP" WASMEDGE_LIB_EXTENSION); + "./" WASMEDGE_LIB_PREFIX + "wasmedgePluginTestModuleCPP" WASMEDGE_LIB_EXTENSION); WasmEdge_String Str = WasmEdge_StringCreateByCString("wasmedge_plugintest_cpp"); const WasmEdge_PluginContext *PluginCxt = WasmEdge_PluginFind(Str); @@ -152,9 +154,9 @@ TEST(wasmedgePluginTests, C_Module) { // Create the wasmedge_plugintest_cpp_module module instance. auto *ModInstCPP = createModuleCPP(); ASSERT_FALSE(ModInstCPP == nullptr); - EXPECT_EQ(WasmEdge_ModuleInstanceListFunctionLength(ModInstCPP), 4U); + EXPECT_EQ(WasmEdge_ModuleInstanceListFunctionLength(ModInstCPP), 5U); std::memset(NameBuf, 0, sizeof(WasmEdge_String) * 16); - EXPECT_EQ(WasmEdge_ModuleInstanceListFunction(ModInstCPP, NameBuf, 16), 4U); + EXPECT_EQ(WasmEdge_ModuleInstanceListFunction(ModInstCPP, NameBuf, 16), 5U); EXPECT_TRUE( WasmEdge_StringIsEqual(NameBuf[0], WasmEdge_StringWrap("add", 3U))); EXPECT_TRUE( @@ -162,7 +164,9 @@ TEST(wasmedgePluginTests, C_Module) { EXPECT_TRUE( WasmEdge_StringIsEqual(NameBuf[2], WasmEdge_StringWrap("name_size", 9U))); EXPECT_TRUE( - WasmEdge_StringIsEqual(NameBuf[3], WasmEdge_StringWrap("sub", 3U))); + WasmEdge_StringIsEqual(NameBuf[3], WasmEdge_StringWrap("opt", 3U))); + EXPECT_TRUE( + WasmEdge_StringIsEqual(NameBuf[4], WasmEdge_StringWrap("sub", 3U))); WasmEdge_ModuleInstanceDelete(ModInstCPP); } diff --git a/test/plugins/unittest/unittest_cpp.cpp b/test/plugins/unittest/unittest_cpp.cpp index 00efc45e2b20..f800c29e4695 100644 --- a/test/plugins/unittest/unittest_cpp.cpp +++ b/test/plugins/unittest/unittest_cpp.cpp @@ -1,38 +1,41 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" +#include "plugin/plugin.h" #include "runtime/callingframe.h" #include "runtime/instance/module.h" -#include "testplugin.h" - #include <algorithm> #include <array> #include <cstdint> #include <gtest/gtest.h> +#include <memory> #include <string> #include <vector> namespace { -WasmEdge::Runtime::Instance::ModuleInstance *createModuleC() { + +std::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance> createModuleC() { using namespace std::literals::string_view_literals; WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "./libwasmedgePluginTestModuleC" WASMEDGE_LIB_EXTENSION)); + "./" WASMEDGE_LIB_PREFIX + "wasmedgePluginTestModuleC" WASMEDGE_LIB_EXTENSION)); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasmedge_plugintest_c"sv)) { if (const auto *Module = Plugin->findModule("wasmedge_plugintest_c_module"sv)) { - return Module->create().release(); + return Module->create(); } } - return nullptr; + return {}; } -WasmEdge::Runtime::Instance::ModuleInstance *createModuleCPP() { +std::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance> createModuleCPP() { using namespace std::literals::string_view_literals; WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "./libwasmedgePluginTestModuleCPP" WASMEDGE_LIB_EXTENSION)); + "./" WASMEDGE_LIB_PREFIX + "wasmedgePluginTestModuleCPP" WASMEDGE_LIB_EXTENSION)); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasmedge_plugintest_cpp"sv)) { WasmEdge::PO::ArgumentParser Parser; @@ -40,20 +43,20 @@ WasmEdge::Runtime::Instance::ModuleInstance *createModuleCPP() { Parser.set_raw_value<std::string>("name"sv, std::string("test_name")); Parser.set_raw_value<std::vector<std::string>>( "arg"sv, std::vector<std::string>({"arg0", "arg1", "arg2", "arg3"})); + Parser.set_raw_value("opt"sv); if (const auto *Module = Plugin->findModule("wasmedge_plugintest_cpp_module"sv)) { - return Module->create().release(); + return Module->create(); } } - return nullptr; + return {}; } } // namespace TEST(wasmedgePluginTests, CPP_Run) { // Create the wasmedge_plugintest_cpp_module module instance. - auto *TestModCPP = dynamic_cast<WasmEdge::Host::WasmEdgePluginTestModule *>( - createModuleCPP()); - ASSERT_FALSE(TestModCPP == nullptr); + auto TestModCPP = createModuleCPP(); + ASSERT_TRUE(TestModCPP); WasmEdge::Runtime::Instance::ModuleInstance Mod(""); WasmEdge::Runtime::CallingFrame CallFrame(nullptr, &Mod); @@ -63,9 +66,7 @@ TEST(wasmedgePluginTests, CPP_Run) { auto *FuncInst1 = TestModCPP->findFuncExports("arg_len"); EXPECT_NE(FuncInst1, nullptr); EXPECT_TRUE(FuncInst1->isHostFunction()); - auto &HostFuncInst1 = - dynamic_cast<WasmEdge::Host::WasmEdgePluginTestFuncArgLen &>( - FuncInst1->getHostFunc()); + auto &HostFuncInst1 = FuncInst1->getHostFunc(); // Test: Run function successfully. EXPECT_TRUE(HostFuncInst1.run(CallFrame, {}, RetVal)); @@ -75,43 +76,46 @@ TEST(wasmedgePluginTests, CPP_Run) { auto *FuncInst2 = TestModCPP->findFuncExports("name_size"); EXPECT_NE(FuncInst2, nullptr); EXPECT_TRUE(FuncInst2->isHostFunction()); - auto &HostFuncInst2 = - dynamic_cast<WasmEdge::Host::WasmEdgePluginTestFuncNameSize &>( - FuncInst2->getHostFunc()); + auto &HostFuncInst2 = FuncInst2->getHostFunc(); // Test: Run function successfully. EXPECT_TRUE(HostFuncInst2.run(CallFrame, {}, RetVal)); EXPECT_EQ(RetVal[0].get<int32_t>(), 9); - delete TestModCPP; + // Get the function "opt". + auto *FuncInst3 = TestModCPP->findFuncExports("opt"); + EXPECT_NE(FuncInst3, nullptr); + EXPECT_TRUE(FuncInst3->isHostFunction()); + auto &HostFuncInst3 = FuncInst3->getHostFunc(); + + // Test: Run function successfully. + EXPECT_TRUE(HostFuncInst3.run(CallFrame, {}, RetVal)); + EXPECT_EQ(RetVal[0].get<int32_t>(), 1); // Create the wasmedge_plugintest_c_module module instance. - auto *TestModC = createModuleC(); - ASSERT_FALSE(TestModC == nullptr); + auto TestModC = createModuleC(); + ASSERT_TRUE(TestModC); // The host functions are implemented in the C API. // Therefore not test to invoke them here. - delete TestModC; } TEST(wasmedgePluginTests, CPP_Module) { // Create the wasmedge_plugintest_cpp_module module instance. - auto *TestModCPP = dynamic_cast<WasmEdge::Host::WasmEdgePluginTestModule *>( - createModuleCPP()); - ASSERT_FALSE(TestModCPP == nullptr); - EXPECT_EQ(TestModCPP->getFuncExportNum(), 4U); + auto TestModCPP = createModuleCPP(); + ASSERT_TRUE(TestModCPP); + EXPECT_EQ(TestModCPP->getFuncExportNum(), 5U); EXPECT_NE(TestModCPP->findFuncExports("add"), nullptr); EXPECT_NE(TestModCPP->findFuncExports("sub"), nullptr); EXPECT_NE(TestModCPP->findFuncExports("arg_len"), nullptr); + EXPECT_NE(TestModCPP->findFuncExports("opt"), nullptr); EXPECT_NE(TestModCPP->findFuncExports("name_size"), nullptr); - delete TestModCPP; // Create the wasmedge_plugintest_c_module module instance. - auto *TestModC = createModuleC(); - ASSERT_FALSE(TestModC == nullptr); + auto TestModC = createModuleC(); + ASSERT_TRUE(TestModC); EXPECT_EQ(TestModC->getFuncExportNum(), 2U); EXPECT_NE(TestModC->findFuncExports("add"), nullptr); EXPECT_NE(TestModC->findFuncExports("sub"), nullptr); - delete TestModC; } GTEST_API_ int main(int argc, char **argv) { diff --git a/test/plugins/wasi_crypto/CMakeLists.txt b/test/plugins/wasi_crypto/CMakeLists.txt index 5e874abd3557..8935d0664e41 100644 --- a/test/plugins/wasi_crypto/CMakeLists.txt +++ b/test/plugins/wasi_crypto/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasiCryptoTests aeads.cpp diff --git a/test/plugins/wasi_crypto/aeads.cpp b/test/plugins/wasi_crypto/aeads.cpp index eefc21c7bc3b..bae54a266a6d 100644 --- a/test/plugins/wasi_crypto/aeads.cpp +++ b/test/plugins/wasi_crypto/aeads.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "helper.h" diff --git a/test/plugins/wasi_crypto/asymmetric.cpp b/test/plugins/wasi_crypto/asymmetric.cpp index c218216a5eab..9e9f9c9fa315 100644 --- a/test/plugins/wasi_crypto/asymmetric.cpp +++ b/test/plugins/wasi_crypto/asymmetric.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "helper.h" diff --git a/test/plugins/wasi_crypto/common.cpp b/test/plugins/wasi_crypto/common.cpp index d50a527c6f8c..e8310c3335e1 100644 --- a/test/plugins/wasi_crypto/common.cpp +++ b/test/plugins/wasi_crypto/common.cpp @@ -1,11 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/func.h" #include "helper.h" namespace { -template <typename T, typename M> T *getHostFunc(M *Mod, const char *Name) { +template <typename T, typename M> +inline T *getHostFunc(const M &Mod, const char *Name) { if (Mod) { auto *FuncInst = Mod->findFuncExports(Name); if (FuncInst && FuncInst->isHostFunction()) { diff --git a/test/plugins/wasi_crypto/hash.cpp b/test/plugins/wasi_crypto/hash.cpp index 825e043270ac..ac6159785c6d 100644 --- a/test/plugins/wasi_crypto/hash.cpp +++ b/test/plugins/wasi_crypto/hash.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "helper.h" diff --git a/test/plugins/wasi_crypto/helper.cpp b/test/plugins/wasi_crypto/helper.cpp index 51b849559a5b..f3ca00a75b97 100644 --- a/test/plugins/wasi_crypto/helper.cpp +++ b/test/plugins/wasi_crypto/helper.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "helper.h" #include "asymmetric_common/func.h" @@ -22,7 +22,8 @@ } while (0) namespace { -template <typename T, typename M> T *getHostFunc(M *Mod, const char *Name) { +template <typename T, typename M> +inline T *getHostFunc(M &Mod, const char *Name) { if (Mod) { auto *FuncInst = Mod->findFuncExports(Name); if (FuncInst && FuncInst->isHostFunction()) { diff --git a/test/plugins/wasi_crypto/helper.h b/test/plugins/wasi_crypto/helper.h index beb1a33988f4..0fd03a50835b 100644 --- a/test/plugins/wasi_crypto/helper.h +++ b/test/plugins/wasi_crypto/helper.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #pragma once @@ -20,6 +20,7 @@ #include <algorithm> #include <cstdint> +#include <memory> #include <queue> #include <string> #include <string_view> @@ -52,6 +53,16 @@ std::vector<uint8_t> operator"" _u8(const char *Str, std::size_t Len); std::vector<uint8_t> operator"" _u8v(const char *Str, std::size_t Len); +template <typename T, typename U> +inline std::unique_ptr<T> dynamicPointerCast(std::unique_ptr<U> &&R) noexcept { + static_assert(std::has_virtual_destructor_v<T>); + T *P = dynamic_cast<T *>(R.get()); + if (P) { + R.release(); + } + return std::unique_ptr<T>(P); +} + /// Designed for testing. class WasiCryptoTest : public ::testing::Test { public: @@ -63,55 +74,37 @@ class WasiCryptoTest : public ::testing::Test { using namespace std::literals::string_view_literals; Plugin::Plugin::load(std::filesystem::u8path( - "../../../plugins/wasi_crypto/" - "libwasmedgePluginWasiCrypto" WASMEDGE_LIB_EXTENSION)); + "../../../plugins/wasi_crypto/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasiCrypto" WASMEDGE_LIB_EXTENSION)); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasi_crypto"sv)) { if (const auto *Module = Plugin->findModule("wasi_crypto_asymmetric_common"sv)) { - WasiCryptoAsymCommonMod = - dynamic_cast<WasmEdge::Host::WasiCryptoAsymmetricCommonModule *>( - Module->create().release()); + WasiCryptoAsymCommonMod = dynamicPointerCast< + WasmEdge::Host::WasiCryptoAsymmetricCommonModule>(Module->create()); } if (const auto *Module = Plugin->findModule("wasi_crypto_common"sv)) { WasiCryptoCommonMod = - dynamic_cast<WasmEdge::Host::WasiCryptoCommonModule *>( - Module->create().release()); + dynamicPointerCast<WasmEdge::Host::WasiCryptoCommonModule>( + Module->create()); } if (const auto *Module = Plugin->findModule("wasi_crypto_kx"sv)) { - WasiCryptoKxMod = dynamic_cast<WasmEdge::Host::WasiCryptoKxModule *>( - Module->create().release()); + WasiCryptoKxMod = + dynamicPointerCast<WasmEdge::Host::WasiCryptoKxModule>( + Module->create()); } if (const auto *Module = Plugin->findModule("wasi_crypto_signatures"sv)) { WasiCryptoSignMod = - dynamic_cast<WasmEdge::Host::WasiCryptoSignaturesModule *>( - Module->create().release()); + dynamicPointerCast<WasmEdge::Host::WasiCryptoSignaturesModule>( + Module->create()); } if (const auto *Module = Plugin->findModule("wasi_crypto_symmetric"sv)) { WasiCryptoSymmMod = - dynamic_cast<WasmEdge::Host::WasiCryptoSymmetricModule *>( - Module->create().release()); + dynamicPointerCast<WasmEdge::Host::WasiCryptoSymmetricModule>( + Module->create()); } } } - ~WasiCryptoTest() override { - if (WasiCryptoAsymCommonMod) { - delete WasiCryptoAsymCommonMod; - } - if (WasiCryptoCommonMod) { - delete WasiCryptoCommonMod; - } - if (WasiCryptoKxMod) { - delete WasiCryptoKxMod; - } - if (WasiCryptoSignMod) { - delete WasiCryptoSignMod; - } - if (WasiCryptoSymmMod) { - delete WasiCryptoSymmMod; - } - } - protected: void writeDummyMemoryContent(); @@ -398,11 +391,12 @@ class WasiCryptoTest : public ::testing::Test { std::array<WasmEdge::ValVariant, 1> Errno; - Host::WasiCryptoAsymmetricCommonModule *WasiCryptoAsymCommonMod = nullptr; - Host::WasiCryptoCommonModule *WasiCryptoCommonMod = nullptr; - Host::WasiCryptoKxModule *WasiCryptoKxMod = nullptr; - Host::WasiCryptoSignaturesModule *WasiCryptoSignMod = nullptr; - Host::WasiCryptoSymmetricModule *WasiCryptoSymmMod = nullptr; + std::unique_ptr<Host::WasiCryptoAsymmetricCommonModule> + WasiCryptoAsymCommonMod; + std::unique_ptr<Host::WasiCryptoCommonModule> WasiCryptoCommonMod; + std::unique_ptr<Host::WasiCryptoKxModule> WasiCryptoKxMod; + std::unique_ptr<Host::WasiCryptoSignaturesModule> WasiCryptoSignMod; + std::unique_ptr<Host::WasiCryptoSymmetricModule> WasiCryptoSymmMod; }; } // namespace WasiCrypto diff --git a/test/plugins/wasi_crypto/kdf.cpp b/test/plugins/wasi_crypto/kdf.cpp index 6e3fa5ed4dc4..8d64fa9f175c 100644 --- a/test/plugins/wasi_crypto/kdf.cpp +++ b/test/plugins/wasi_crypto/kdf.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "helper.h" diff --git a/test/plugins/wasi_crypto/kx.cpp b/test/plugins/wasi_crypto/kx.cpp index de107fcb22ea..a47b728c5029 100644 --- a/test/plugins/wasi_crypto/kx.cpp +++ b/test/plugins/wasi_crypto/kx.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "helper.h" diff --git a/test/plugins/wasi_crypto/mac.cpp b/test/plugins/wasi_crypto/mac.cpp index 2e8521fcb4b4..c2616e31f2b7 100644 --- a/test/plugins/wasi_crypto/mac.cpp +++ b/test/plugins/wasi_crypto/mac.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "helper.h" diff --git a/test/plugins/wasi_crypto/notimplement.cpp b/test/plugins/wasi_crypto/notimplement.cpp index b87c0b062fb7..0b2551803125 100644 --- a/test/plugins/wasi_crypto/notimplement.cpp +++ b/test/plugins/wasi_crypto/notimplement.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "helper.h" diff --git a/test/plugins/wasi_crypto/signatures.cpp b/test/plugins/wasi_crypto/signatures.cpp index 8cd2f083bdfa..07deb8c4363d 100644 --- a/test/plugins/wasi_crypto/signatures.cpp +++ b/test/plugins/wasi_crypto/signatures.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "helper.h" diff --git a/test/plugins/wasi_logging/CMakeLists.txt b/test/plugins/wasi_logging/CMakeLists.txt index d3373e8022ae..923363a21491 100644 --- a/test/plugins/wasi_logging/CMakeLists.txt +++ b/test/plugins/wasi_logging/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasiLoggingTests wasi_logging.cpp @@ -19,6 +19,7 @@ target_link_libraries(wasiLoggingTests PRIVATE ${GTEST_BOTH_LIBRARIES} ) + # Link to the WasmEdge library if(WASMEDGE_LINK_PLUGINS_STATIC) target_link_libraries(wasiLoggingTests diff --git a/test/plugins/wasi_logging/wasi_logging.cpp b/test/plugins/wasi_logging/wasi_logging.cpp index d1c36c021541..706aeada95e9 100644 --- a/test/plugins/wasi_logging/wasi_logging.cpp +++ b/test/plugins/wasi_logging/wasi_logging.cpp @@ -1,27 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "plugin/wasi_logging/func.h" +#include "plugin/wasi_logging/module.h" + #include "common/defines.h" #include "runtime/instance/module.h" -#include "wasi_logging/func.h" -#include "wasi_logging/module.h" #include <gtest/gtest.h> -#include <iostream> -#include <spdlog/sinks/ostream_sink.h> -#include <spdlog/spdlog.h> +#include <memory> #include <sstream> namespace { -WasmEdge::Runtime::Instance::ModuleInstance *createModule() { +template <typename T, typename U> +inline std::unique_ptr<T> dynamicPointerCast(std::unique_ptr<U> &&R) noexcept { + static_assert(std::has_virtual_destructor_v<T>); + T *P = dynamic_cast<T *>(R.get()); + if (P) { + R.release(); + } + return std::unique_ptr<T>(P); +} + +std::unique_ptr<WasmEdge::Host::WasiLoggingModule> createModule() { using namespace std::literals::string_view_literals; - WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "../../../plugins/wasi_logging/" - "libwasmedgePluginWasiLogging" WASMEDGE_LIB_EXTENSION)); + // The built-in plugins are loaded when loading from default paths. + WasmEdge::Plugin::Plugin::loadFromDefaultPaths(); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasi_logging"sv)) { if (const auto *Module = Plugin->findModule("wasi:logging/logging"sv)) { - return Module->create().release(); + return dynamicPointerCast<WasmEdge::Host::WasiLoggingModule>( + Module->create()); } } - return nullptr; + return {}; } void fillMemContent(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, @@ -30,18 +42,21 @@ void fillMemContent(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, } void fillMemContent(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, - uint32_t Offset, const std::string &Str) noexcept { + uint32_t Offset, std::string_view Str) noexcept { char *Buf = MemInst.getPointer<char *>(Offset); - std::copy_n(Str.c_str(), Str.length(), Buf); + std::copy_n(Str.data(), Str.length(), Buf); } } // namespace TEST(WasiLoggingTests, func_log) { + using namespace std::literals::string_view_literals; // Create the wasi-logging module instance. - auto WasiLoggingMod = - dynamic_cast<WasmEdge::Host::WasiLoggingModule *>(createModule()); - EXPECT_NE(WasiLoggingMod, nullptr); + // Here create 2 wasi-logging modules for testing in multiple modules. + auto WasiLoggingMod1 = createModule(); + ASSERT_TRUE(WasiLoggingMod1); + auto WasiLoggingMod2 = createModule(); + ASSERT_TRUE(WasiLoggingMod2); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -53,71 +68,119 @@ TEST(WasiLoggingTests, func_log) { auto &MemInst = *MemInstPtr; WasmEdge::Runtime::CallingFrame CallFrame(nullptr, &Mod); - // Clear the memory[0, 32]. - fillMemContent(MemInst, 0, 32); - // Set strings in memory - fillMemContent(MemInst, 0, std::string("CxtStr")); - fillMemContent(MemInst, 8, std::string("stderr")); - fillMemContent(MemInst, 16, std::string("MsgStr")); - - // Get the function "log" - auto *FuncInst = WasiLoggingMod->findFuncExports("log"); - EXPECT_NE(FuncInst, nullptr); - EXPECT_TRUE(FuncInst->isHostFunction()); - auto &HostFuncInst = - dynamic_cast<WasmEdge::Host::WasiLoggingLog &>(FuncInst->getHostFunc()); + // Clear the memory[0, 256]. + fillMemContent(MemInst, 0, 256); + // Set strings in memory. + fillMemContent(MemInst, 0, "stdout"sv); + fillMemContent(MemInst, 8, "stderr"sv); + fillMemContent(MemInst, 16, "out.log"sv); + fillMemContent(MemInst, 24, "out2.log"sv); + fillMemContent(MemInst, 128, "This is log message"sv); + fillMemContent(MemInst, 160, "Message 1 to file"sv); + fillMemContent(MemInst, 192, "Message 2 to file"sv); + fillMemContent(MemInst, 224, "Message 3 to file"sv); + + // Get the function "log". + auto *FuncInst1 = WasiLoggingMod1->findFuncExports("log"); + auto *FuncInst2 = WasiLoggingMod2->findFuncExports("log"); + EXPECT_NE(FuncInst1, nullptr); + EXPECT_NE(FuncInst2, nullptr); + EXPECT_TRUE(FuncInst1->isHostFunction()); + EXPECT_TRUE(FuncInst2->isHostFunction()); + auto &HostFuncInst1 = dynamic_cast<WasmEdge::Host::WASILogging::Log &>( + FuncInst1->getHostFunc()); + auto &HostFuncInst2 = dynamic_cast<WasmEdge::Host::WASILogging::Log &>( + FuncInst2->getHostFunc()); // Show All Level - EXPECT_TRUE(HostFuncInst.run( + EXPECT_TRUE(HostFuncInst1.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - UINT32_C(0), UINT32_C(0), UINT32_C(6), UINT32_C(16), UINT32_C(6)}, + UINT32_C(0), UINT32_C(0), UINT32_C(6), UINT32_C(128), UINT32_C(19)}, {})); - EXPECT_TRUE(HostFuncInst.run( + EXPECT_TRUE(HostFuncInst1.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - UINT32_C(1), UINT32_C(0), UINT32_C(6), UINT32_C(16), UINT32_C(6)}, + UINT32_C(1), UINT32_C(0), UINT32_C(6), UINT32_C(128), UINT32_C(19)}, {})); - EXPECT_TRUE(HostFuncInst.run( + EXPECT_TRUE(HostFuncInst1.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - UINT32_C(2), UINT32_C(0), UINT32_C(6), UINT32_C(16), UINT32_C(6)}, + UINT32_C(2), UINT32_C(0), UINT32_C(6), UINT32_C(128), UINT32_C(19)}, {})); - - EXPECT_TRUE(HostFuncInst.run( + EXPECT_TRUE(HostFuncInst1.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - UINT32_C(3), UINT32_C(0), UINT32_C(6), UINT32_C(16), UINT32_C(6)}, + UINT32_C(3), UINT32_C(0), UINT32_C(6), UINT32_C(128), UINT32_C(19)}, {})); - EXPECT_TRUE(HostFuncInst.run( + EXPECT_TRUE(HostFuncInst1.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - UINT32_C(4), UINT32_C(0), UINT32_C(6), UINT32_C(16), UINT32_C(6)}, + UINT32_C(4), UINT32_C(0), UINT32_C(6), UINT32_C(128), UINT32_C(19)}, {})); - EXPECT_TRUE(HostFuncInst.run( + EXPECT_TRUE(HostFuncInst1.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - UINT32_C(5), UINT32_C(0), UINT32_C(6), UINT32_C(16), UINT32_C(6)}, + UINT32_C(5), UINT32_C(0), UINT32_C(6), UINT32_C(128), UINT32_C(19)}, {})); - EXPECT_FALSE(WasiLoggingMod->getEnv().isCxtStrStderr); // Stderr Context - EXPECT_TRUE(HostFuncInst.run( + EXPECT_TRUE(HostFuncInst1.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - UINT32_C(0), UINT32_C(8), UINT32_C(6), UINT32_C(16), UINT32_C(6)}, + UINT32_C(0), UINT32_C(8), UINT32_C(6), UINT32_C(128), UINT32_C(19)}, + {})); + EXPECT_TRUE(HostFuncInst2.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(8), UINT32_C(6), UINT32_C(128), UINT32_C(19)}, {})); - EXPECT_TRUE(WasiLoggingMod->getEnv().isCxtStrStderr); - // UnKnown Level - EXPECT_FALSE(HostFuncInst.run( + // Log to out.txt: message 1 + EXPECT_TRUE(HostFuncInst1.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(16), UINT32_C(7), UINT32_C(160), UINT32_C(17)}, + {})); + EXPECT_TRUE(HostFuncInst2.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(16), UINT32_C(7), UINT32_C(160), UINT32_C(17)}, + {})); + // Log to out2.txt: message 2 + EXPECT_TRUE(HostFuncInst1.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - UINT32_C(6), UINT32_C(0), UINT32_C(6), UINT32_C(16), UINT32_C(6)}, + UINT32_C(0), UINT32_C(24), UINT32_C(8), UINT32_C(192), UINT32_C(17)}, + {})); + EXPECT_TRUE(HostFuncInst2.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(24), UINT32_C(8), UINT32_C(192), UINT32_C(17)}, + {})); + // Log to out.txt: message 3 + EXPECT_TRUE(HostFuncInst1.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(16), UINT32_C(7), UINT32_C(224), UINT32_C(17)}, + {})); + EXPECT_TRUE(HostFuncInst2.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(16), UINT32_C(7), UINT32_C(224), UINT32_C(17)}, {})); - EXPECT_FALSE(WasiLoggingMod->getEnv().isCxtStrStderr); - delete WasiLoggingMod; + // UnKnown Level + EXPECT_FALSE(HostFuncInst1.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(6), UINT32_C(0), UINT32_C(6), UINT32_C(128), UINT32_C(19)}, + {})); + EXPECT_FALSE(HostFuncInst2.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(6), UINT32_C(0), UINT32_C(6), UINT32_C(128), UINT32_C(19)}, + {})); } GTEST_API_ int main(int argc, char **argv) { diff --git a/test/plugins/wasi_nn/CMakeLists.txt b/test/plugins/wasi_nn/CMakeLists.txt index fe68a8faeed9..88fad025e1d8 100644 --- a/test/plugins/wasi_nn/CMakeLists.txt +++ b/test/plugins/wasi_nn/CMakeLists.txt @@ -1,69 +1,111 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasiNNTests wasi_nn.cpp ) +function(download URL OUTPUT HASH) + file(DOWNLOAD + ${URL} + ${OUTPUT} + SHOW_PROGRESS + EXPECTED_HASH ${HASH} + ) +endfunction() + # Prepare the testing data for each backends. foreach(BACKEND ${WASMEDGE_PLUGIN_WASI_NN_BACKEND}) string(TOLOWER ${BACKEND} BACKEND) if(BACKEND MATCHES "openvino") - message( STATUS "Download ML artifacts to ${CMAKE_CURRENT_BINARY_DIR}/wasinn_openvino_fixtures") - execute_process( - COMMAND bash ${CMAKE_SOURCE_DIR}/utils/wasi-nn/download-openvino-fixtures.sh ${CMAKE_CURRENT_BINARY_DIR}/wasinn_openvino_fixtures - RESULT_VARIABLE DOWNLOAD_ERROR - OUTPUT_STRIP_TRAILING_WHITESPACE) - file(MD5 ${CMAKE_CURRENT_BINARY_DIR}/wasinn_openvino_fixtures/mobilenet.bin CHECKSUM_WEIGHT) - file(MD5 ${CMAKE_CURRENT_BINARY_DIR}/wasinn_openvino_fixtures/mobilenet.xml CHECKSUM_DESCRIP) - file(MD5 ${CMAKE_CURRENT_BINARY_DIR}/wasinn_openvino_fixtures/tensor-1x224x224x3-f32.bgr CHECKSUM_TENSOR) - if(NOT CHECKSUM_WEIGHT STREQUAL "ae096b1f735f1e8e54bac8b2a42303bd") - message(FATAL_ERROR "mobilenet.bin downloaded with wrong md5") - endif() - if(NOT CHECKSUM_DESCRIP STREQUAL "4ea3a14273587ce5c1662018878f9f90") - message(FATAL_ERROR "mobilenet.xml downloaded with wrong md5") - endif() - if(NOT CHECKSUM_TENSOR STREQUAL "bfca546f4a3b5e6da49b7bd728e2799a") - message(FATAL_ERROR "tensor-1x224x224x3-f32.bgr downloaded with wrong md5") - endif() + message(STATUS "Download ML artifacts to ${CMAKE_CURRENT_BINARY_DIR}/wasinn_openvino_fixtures") + download( + https://github.com/intel/openvino-rs/raw/v0.3.3/crates/openvino/tests/fixtures/mobilenet/mobilenet.bin + ${CMAKE_CURRENT_BINARY_DIR}/wasinn_openvino_fixtures/mobilenet.bin + MD5=ae096b1f735f1e8e54bac8b2a42303bd + ) + download( + https://github.com/intel/openvino-rs/raw/v0.3.3/crates/openvino/tests/fixtures/mobilenet/mobilenet.xml + ${CMAKE_CURRENT_BINARY_DIR}/wasinn_openvino_fixtures/mobilenet.xml + MD5=4ea3a14273587ce5c1662018878f9f90 + ) + download( + https://github.com/intel/openvino-rs/raw/v0.3.3/crates/openvino/tests/fixtures/mobilenet/tensor-1x224x224x3-f32.bgr + ${CMAKE_CURRENT_BINARY_DIR}/wasinn_openvino_fixtures/tensor-1x224x224x3-f32.bgr + MD5=bfca546f4a3b5e6da49b7bd728e2799a + ) elseif(BACKEND MATCHES "pytorch") - message( STATUS "Download ML artifacts to ${CMAKE_CURRENT_BINARY_DIR}/wasinn_pytorch_fixtures") - execute_process( - COMMAND bash ${CMAKE_SOURCE_DIR}/utils/wasi-nn/download-pytorch-fixtures.sh ${CMAKE_CURRENT_BINARY_DIR}/wasinn_pytorch_fixtures - RESULT_VARIABLE DOWNLOAD_ERROR - OUTPUT_STRIP_TRAILING_WHITESPACE) - file(MD5 ${CMAKE_CURRENT_BINARY_DIR}/wasinn_pytorch_fixtures/mobilenet.pt CHECKSUM_WEIGHT) - file(MD5 ${CMAKE_CURRENT_BINARY_DIR}/wasinn_pytorch_fixtures/image-1x3x224x224.rgb CHECKSUM_IMAGE) - if(NOT CHECKSUM_WEIGHT STREQUAL "234f446d2446e0f6fd8ed700c0b4b63b") - message(FATAL_ERROR "mobilenet.pt downloaded with wrong md5") - endif() - if(NOT CHECKSUM_IMAGE STREQUAL "551caa6f3b66c1d953655228462570a1") - message(FATAL_ERROR "image-1x3x224x224.rgb downloaded with wrong md5") - endif() + message(STATUS "Download ML artifacts to ${CMAKE_CURRENT_BINARY_DIR}/wasinn_pytorch_fixtures") + download( + https://github.com/second-state/WasmEdge-WASINN-examples/raw/master/pytorch-mobilenet-image/mobilenet.pt + ${CMAKE_CURRENT_BINARY_DIR}/wasinn_pytorch_fixtures/mobilenet.pt + MD5=234f446d2446e0f6fd8ed700c0b4b63b + ) + download( + https://github.com/second-state/WasmEdge-WASINN-examples/raw/master/pytorch-mobilenet-image/image-1x3x224x224.rgb + ${CMAKE_CURRENT_BINARY_DIR}/wasinn_pytorch_fixtures/image-1x3x224x224.rgb + MD5=551caa6f3b66c1d953655228462570a1 + ) elseif(BACKEND STREQUAL "tensorflowlite") - message( STATUS "Download ML artifacts to ${CMAKE_CURRENT_BINARY_DIR}/wasinn_tflite_fixtures") - execute_process( - COMMAND bash ${CMAKE_SOURCE_DIR}/utils/wasi-nn/download-tflite-fixtures.sh ${CMAKE_CURRENT_BINARY_DIR}/wasinn_tflite_fixtures - RESULT_VARIABLE DOWNLOAD_ERROR - OUTPUT_STRIP_TRAILING_WHITESPACE) - file(MD5 ${CMAKE_CURRENT_BINARY_DIR}/wasinn_tflite_fixtures/lite-model_aiy_vision_classifier_birds_V1_3.tflite CHECKSUM_WEIGHT) - file(MD5 ${CMAKE_CURRENT_BINARY_DIR}/wasinn_tflite_fixtures/birdx224x224x3.rgb CHECKSUM_IMAGE) - if(NOT CHECKSUM_WEIGHT STREQUAL "3e59cc3a99afeeb819c2c38b319a7938") - message(FATAL_ERROR "downloaded tflite model with wrong md5") - endif() - if(NOT CHECKSUM_IMAGE STREQUAL "ad51c39cfe35d2ef35c4052b78cb3c55") - message(FATAL_ERROR "downloaded bird.jpg fixture with wrong md5") - endif() + message(STATUS "Download ML artifacts to ${CMAKE_CURRENT_BINARY_DIR}/wasinn_tflite_fixtures") + download( + https://raw.githubusercontent.com/gusye1234/WasmEdge-WASINN-examples/demo-tflite-image/tflite-birds_v1-image/lite-model_aiy_vision_classifier_birds_V1_3.tflite + ${CMAKE_CURRENT_BINARY_DIR}/wasinn_tflite_fixtures/lite-model_aiy_vision_classifier_birds_V1_3.tflite + MD5=3e59cc3a99afeeb819c2c38b319a7938 + ) + download( + https://raw.githubusercontent.com/gusye1234/WasmEdge-WASINN-examples/demo-tflite-image/tflite-birds_v1-image/birdx224x224x3.rgb + ${CMAKE_CURRENT_BINARY_DIR}/wasinn_tflite_fixtures/birdx224x224x3.rgb + MD5=ad51c39cfe35d2ef35c4052b78cb3c55 + ) elseif(BACKEND STREQUAL "ggml") - message( STATUS "Download ML artifacts to ${CMAKE_CURRENT_BINARY_DIR}/wasinn_ggml_fixtures") - execute_process( - COMMAND bash ${CMAKE_SOURCE_DIR}/utils/wasi-nn/download-ggml-fixtures.sh ${CMAKE_CURRENT_BINARY_DIR}/wasinn_ggml_fixtures - RESULT_VARIABLE DOWNLOAD_ERROR - OUTPUT_STRIP_TRAILING_WHITESPACE) - file(MD5 ${CMAKE_CURRENT_BINARY_DIR}/wasinn_ggml_fixtures/orca_mini.gguf CHECKSUM_MODEL) - if(NOT CHECKSUM_MODEL STREQUAL "f895f00678bfbf89f70d6d25f20a7b5f") - message(FATAL_ERROR "orca_mini.gguf downloaded with wrong md5") + message(STATUS "Download ML artifacts to ${CMAKE_CURRENT_BINARY_DIR}/wasinn_ggml_fixtures") + download( + https://huggingface.co/TheBloke/orca_mini_v3_7B-GGUF/resolve/main/orca_mini_v3_7b.Q2_K.gguf + ${CMAKE_CURRENT_BINARY_DIR}/wasinn_ggml_fixtures/orca_mini.gguf + MD5=f895f00678bfbf89f70d6d25f20a7b5f + ) + if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + target_compile_options(wasiNNTests PUBLIC + /wd4067 # unexpected tokens following preprocessor directive - expected a newline + ) endif() + elseif(BACKEND STREQUAL "neuralspeed") + message(NOTICE "Neural Speed backend is removed due to the upstream end-of-life.") + elseif(BACKEND STREQUAL "piper") + message(STATUS "Download ML artifacts to ${CMAKE_CURRENT_BINARY_DIR}/wasinn_piper_fixtures") + download( + https://github.com/rhasspy/piper/raw/master/etc/test_voice.onnx + ${CMAKE_CURRENT_BINARY_DIR}/wasinn_piper_fixtures/test_voice.onnx + SHA256=937682595755bbb3ee9f131b8a4b2b1ba2fac9b26431fcd7aa48cff0f7382838 + ) + download( + https://github.com/rhasspy/piper/raw/master/etc/test_voice.onnx.json + ${CMAKE_CURRENT_BINARY_DIR}/wasinn_piper_fixtures/test_voice.onnx.json + SHA256=f3e0b906861cc2fb8a50e12ceca263afe226ff9688f60e9d4ef943d4f047a513 + ) + download( + https://github.com/rhasspy/piper/releases/download/2023.11.14-2/piper_linux_x86_64.tar.gz + ${CMAKE_CURRENT_BINARY_DIR}/wasinn_piper_fixtures/piper_linux_x86_64.tar.gz + SHA256=a50cb45f355b7af1f6d758c1b360717877ba0a398cc8cbe6d2a7a3a26e225992 + ) + file(ARCHIVE_EXTRACT + INPUT ${CMAKE_CURRENT_BINARY_DIR}/wasinn_piper_fixtures/piper_linux_x86_64.tar.gz + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/wasinn_piper_fixtures + PATTERNS piper/espeak-ng-data + ) + elseif(BACKEND STREQUAL "whisper") + message( STATUS "Download ML artifacts to ${CMAKE_CURRENT_BINARY_DIR}/wasinn_whisper_fixtures") + download( + https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin + ${CMAKE_CURRENT_BINARY_DIR}/wasinn_whisper_fixtures/ggml-base.bin + MD5=4279db3d7b18d9f6e4d5817a16af4f09 + ) + download( + https://github.com/second-state/WasmEdge-WASINN-examples/raw/master/whisper-basic/test.wav + ${CMAKE_CURRENT_BINARY_DIR}/wasinn_whisper_fixtures/test.wav + MD5=6cf3f7af1ebbd6b29c373e526b548dba + ) else() # Add the other backend test files fetching here. endif() @@ -107,4 +149,4 @@ if(WASMEDGE_BUILD_WASI_NN_RPC) PRIVATE wasiNNRPC ) -endif() \ No newline at end of file +endif() diff --git a/test/plugins/wasi_nn/wasi_nn.cpp b/test/plugins/wasi_nn/wasi_nn.cpp index 381952024e1c..0ed4990b7b3e 100644 --- a/test/plugins/wasi_nn/wasi_nn.cpp +++ b/test/plugins/wasi_nn/wasi_nn.cpp @@ -1,32 +1,50 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC -#include "common/types.h" -#include "runtime/instance/module.h" #include "wasinnfunc.h" #include "wasinnmodule.h" +#include "common/types.h" +#include "runtime/instance/module.h" + +#include <gtest/gtest.h> + #include <algorithm> #include <cstdint> #include <fstream> -#include <gtest/gtest.h> +#include <memory> #include <numeric> #include <vector> using WasmEdge::Host::WASINN::Backend; +using WasmEdge::Host::WASINN::Device; using WasmEdge::Host::WASINN::ErrNo; #if defined(WASMEDGE_PLUGIN_WASI_NN_BACKEND_OPENVINO) || \ defined(WASMEDGE_PLUGIN_WASI_NN_BACKEND_TORCH) || \ defined(WASMEDGE_PLUGIN_WASI_NN_BACKEND_TFLITE) || \ - defined(WASMEDGE_PLUGIN_WASI_NN_BACKEND_GGML) + defined(WASMEDGE_PLUGIN_WASI_NN_BACKEND_GGML) || \ + defined(WASMEDGE_PLUGIN_WASI_NN_BACKEND_PIPER) || \ + defined(WASMEDGE_PLUGIN_WASI_NN_BACKEND_WHISPER) || \ + defined(WASMEDGE_PLUGIN_WASI_NN_BACKEND_CHATTTS) namespace { -WasmEdge::Runtime::Instance::ModuleInstance * + +template <typename T, typename U> +inline std::unique_ptr<T> dynamicPointerCast(std::unique_ptr<U> &&R) noexcept { + static_assert(std::has_virtual_destructor_v<T>); + T *P = dynamic_cast<T *>(R.get()); + if (P) { + R.release(); + } + return std::unique_ptr<T>(P); +} + +std::unique_ptr<WasmEdge::Host::WasiNNModule> createModule(std::string_view NNRPCURI = "") { using namespace std::literals::string_view_literals; - WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "../../../plugins/wasi_nn/" - "libwasmedgePluginWasiNN" WASMEDGE_LIB_EXTENSION)); + WasmEdge::Plugin::Plugin::load( + std::filesystem::u8path("../../../plugins/wasi_nn/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasiNN" WASMEDGE_LIB_EXTENSION)); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasi_nn"sv)) { WasmEdge::PO::ArgumentParser Parser; Plugin->registerOptions(Parser); @@ -34,31 +52,32 @@ createModule(std::string_view NNRPCURI = "") { Parser.set_raw_value<std::string>("nn-rpc-uri"sv, std::string(NNRPCURI)); } if (const auto *Module = Plugin->findModule("wasi_nn"sv)) { - return Module->create().release(); + return dynamicPointerCast<WasmEdge::Host::WasiNNModule>(Module->create()); } } - return nullptr; + return {}; } +#if !defined(WASMEDGE_PLUGIN_WASI_NN_BACKEND_CHATTTS) inline std::vector<uint8_t> readEntireFile(const std::string &Path) { - std::ifstream Fin(Path, std::ios::binary | std::ios::ate); + std::ifstream Fin(Path, std::ios::in | std::ios::binary | std::ios::ate); if (!Fin) { return {}; } - Fin.seekg(0, std::ios::end); - std::vector<uint8_t> Buf(static_cast<size_t>(Fin.tellg())); + std::vector<uint8_t> Buf(static_cast<std::size_t>(Fin.tellg())); Fin.seekg(0, std::ios::beg); if (!Fin.read(reinterpret_cast<char *>(Buf.data()), - static_cast<size_t>(Buf.size()))) { + static_cast<std::streamsize>(Buf.size()))) { return {}; } Fin.close(); return Buf; } +#endif template <typename T> void writeBinaries(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, - std::vector<T> Binaries, uint32_t Ptr) noexcept { + WasmEdge::Span<const T> Binaries, uint32_t Ptr) noexcept { std::copy(Binaries.begin(), Binaries.end(), MemInst.getPointer<T *>(Ptr)); } @@ -75,6 +94,9 @@ void writeFatPointer(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, writeUInt32(MemInst, PtrSize, Ptr); } +#if defined(WASMEDGE_PLUGIN_WASI_NN_BACKEND_OPENVINO) || \ + defined(WASMEDGE_PLUGIN_WASI_NN_BACKEND_TORCH) || \ + defined(WASMEDGE_PLUGIN_WASI_NN_BACKEND_TFLITE) template <typename T> std::vector<size_t> classSort(WasmEdge::Span<const T> Array) { std::vector<size_t> Indices(Array.size()); @@ -86,14 +108,15 @@ std::vector<size_t> classSort(WasmEdge::Span<const T> Array) { }); return Indices; } +#endif } // namespace #endif #ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_OPENVINO TEST(WasiNNTest, OpenVINOBackend) { - // Create the wasmedge_process module instance. - auto *NNMod = dynamic_cast<WasmEdge::Host::WasiNNModule *>(createModule()); - ASSERT_TRUE(NNMod != nullptr); + // Create the wasi_nn module instance. + auto NNMod = createModule(); + ASSERT_TRUE(NNMod); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -164,7 +187,8 @@ TEST(WasiNNTest, OpenVINOBackend) { EXPECT_TRUE(HostFuncLoad.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(2), UINT32_C(0), UINT32_C(0), BuilderPtr}, + LoadEntryPtr, UINT32_C(2), static_cast<uint32_t>(Backend::OpenVINO), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::RuntimeError)); @@ -175,7 +199,8 @@ TEST(WasiNNTest, OpenVINOBackend) { EXPECT_TRUE(HostFuncLoad.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(2), UINT32_C(0), UINT32_C(0), OutBoundPtr}, + LoadEntryPtr, UINT32_C(2), static_cast<uint32_t>(Backend::OpenVINO), + static_cast<uint32_t>(Device::CPU), OutBoundPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); @@ -186,7 +211,8 @@ TEST(WasiNNTest, OpenVINOBackend) { EXPECT_TRUE(HostFuncLoad.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - OutBoundPtr, UINT32_C(2), UINT32_C(0), UINT32_C(0), BuilderPtr}, + OutBoundPtr, UINT32_C(2), static_cast<uint32_t>(Backend::OpenVINO), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); @@ -194,14 +220,16 @@ TEST(WasiNNTest, OpenVINOBackend) { // Test: load -- OpenVINO model xml ptr out of bounds. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, OutBoundPtr, XmlRead.size(), BuilderPtr); - writeFatPointer(MemInst, StorePtr + XmlRead.size(), WeightRead.size(), + writeFatPointer(MemInst, OutBoundPtr, static_cast<uint32_t>(XmlRead.size()), BuilderPtr); + writeFatPointer(MemInst, StorePtr + static_cast<uint32_t>(XmlRead.size()), + static_cast<uint32_t>(WeightRead.size()), BuilderPtr); { EXPECT_TRUE(HostFuncLoad.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(2), UINT32_C(0), UINT32_C(0), BuilderPtr}, + LoadEntryPtr, UINT32_C(2), static_cast<uint32_t>(Backend::OpenVINO), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); @@ -209,13 +237,16 @@ TEST(WasiNNTest, OpenVINOBackend) { // Test: load -- OpenVINO model bin ptr out of bounds. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, StorePtr, XmlRead.size(), BuilderPtr); - writeFatPointer(MemInst, OutBoundPtr, WeightRead.size(), BuilderPtr); + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(XmlRead.size()), + BuilderPtr); + writeFatPointer(MemInst, OutBoundPtr, + static_cast<uint32_t>(WeightRead.size()), BuilderPtr); { EXPECT_TRUE(HostFuncLoad.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(2), UINT32_C(0), UINT32_C(0), BuilderPtr}, + LoadEntryPtr, UINT32_C(2), static_cast<uint32_t>(Backend::OpenVINO), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); @@ -223,9 +254,10 @@ TEST(WasiNNTest, OpenVINOBackend) { // Test: load -- wrong builders' length. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, StorePtr, XmlRead.size(), BuilderPtr); - writeFatPointer(MemInst, StorePtr + XmlRead.size(), WeightRead.size(), + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(XmlRead.size()), BuilderPtr); + writeFatPointer(MemInst, StorePtr + static_cast<uint32_t>(XmlRead.size()), + static_cast<uint32_t>(WeightRead.size()), BuilderPtr); writeBinaries<uint8_t>(MemInst, XmlRead, StorePtr); writeBinaries<uint8_t>(MemInst, WeightRead, StorePtr + XmlRead.size()); StorePtr += (XmlRead.size() + WeightRead.size()); @@ -233,7 +265,8 @@ TEST(WasiNNTest, OpenVINOBackend) { EXPECT_TRUE(HostFuncLoad.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(4), UINT32_C(0), UINT32_C(0), BuilderPtr}, + LoadEntryPtr, UINT32_C(4), static_cast<uint32_t>(Backend::OpenVINO), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); @@ -244,7 +277,8 @@ TEST(WasiNNTest, OpenVINOBackend) { EXPECT_TRUE(HostFuncLoad.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(2), UINT32_C(0), UINT32_C(3), BuilderPtr}, + LoadEntryPtr, UINT32_C(2), static_cast<uint32_t>(Backend::OpenVINO), + static_cast<uint32_t>(Device::AUTO), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); @@ -255,7 +289,8 @@ TEST(WasiNNTest, OpenVINOBackend) { EXPECT_TRUE(HostFuncLoad.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(2), UINT32_C(0), UINT32_C(0), BuilderPtr}, + LoadEntryPtr, UINT32_C(2), static_cast<uint32_t>(Backend::OpenVINO), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); @@ -267,7 +302,8 @@ TEST(WasiNNTest, OpenVINOBackend) { EXPECT_TRUE(HostFuncLoad.run( CallFrame, std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(2), UINT32_C(0), UINT32_C(0), BuilderPtr}, + LoadEntryPtr, UINT32_C(2), static_cast<uint32_t>(Backend::OpenVINO), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 1); @@ -326,10 +362,12 @@ TEST(WasiNNTest, OpenVINOBackend) { // OpenVINO WASI-NN set_input tests. SetInputEntryPtr = BuilderPtr; - writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); - writeUInt32(MemInst, UINT32_C(1), BuilderPtr); - writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); writeBinaries<uint32_t>(MemInst, TensorDim, StorePtr); writeBinaries<uint8_t>(MemInst, TensorData, StorePtr + TensorDim.size() * 4); @@ -375,10 +413,12 @@ TEST(WasiNNTest, OpenVINOBackend) { // Test: set_input -- tensor type not FP32. BuilderPtr = SetInputEntryPtr; - writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); - writeUInt32(MemInst, UINT32_C(2), BuilderPtr); - writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(2), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, @@ -391,10 +431,12 @@ TEST(WasiNNTest, OpenVINOBackend) { // Test: set_input -- set input successfully. BuilderPtr = SetInputEntryPtr; - writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); - writeUInt32(MemInst, UINT32_C(1), BuilderPtr); - writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, @@ -495,9 +537,9 @@ TEST(WasiNNTest, OpenVINOBackend) { #ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_TORCH TEST(WasiNNTest, PyTorchBackend) { - // Create the wasmedge_process module instance. - auto *NNMod = dynamic_cast<WasmEdge::Host::WasiNNModule *>(createModule()); - EXPECT_FALSE(NNMod == nullptr); + // Create the wasi_nn module instance. + auto NNMod = createModule(); + ASSERT_TRUE(NNMod); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -563,89 +605,91 @@ TEST(WasiNNTest, PyTorchBackend) { // Torch WASI-NN load tests. // Test: load -- meaningless binaries. { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(1), - static_cast<uint32_t>(Backend::PyTorch), - UINT32_C(0), BuilderPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::PyTorch), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); } // Test: load -- graph id ptr out of bounds. { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(1), - static_cast<uint32_t>(Backend::PyTorch), - UINT32_C(0), OutBoundPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::PyTorch), + static_cast<uint32_t>(Device::CPU), OutBoundPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); } // Test: load -- graph builder ptr out of bounds. { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - OutBoundPtr, UINT32_C(1), - static_cast<uint32_t>(Backend::PyTorch), - UINT32_C(0), BuilderPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + OutBoundPtr, UINT32_C(1), static_cast<uint32_t>(Backend::PyTorch), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); } // Test: load -- Torch model bin ptr out of bounds. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, OutBoundPtr, WeightRead.size(), BuilderPtr); + writeFatPointer(MemInst, OutBoundPtr, + static_cast<uint32_t>(WeightRead.size()), BuilderPtr); { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(1), - static_cast<uint32_t>(Backend::PyTorch), - UINT32_C(0), BuilderPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::PyTorch), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); } // Test: load -- wrong builders' length. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, StorePtr, WeightRead.size(), BuilderPtr); + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(WeightRead.size()), + BuilderPtr); writeBinaries<uint8_t>(MemInst, WeightRead, StorePtr); StorePtr += WeightRead.size(); { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(2), - static_cast<uint32_t>(Backend::PyTorch), - UINT32_C(0), BuilderPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(2), static_cast<uint32_t>(Backend::PyTorch), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); } // Test: load -- unsupported device. CPU 0, GPU 1, TPU 2 { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(1), - static_cast<uint32_t>(Backend::PyTorch), - UINT32_C(3), BuilderPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::PyTorch), + static_cast<uint32_t>(Device::AUTO), BuilderPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); } // Test: load -- load successfully. { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(1), - static_cast<uint32_t>(Backend::PyTorch), - UINT32_C(0), BuilderPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::PyTorch), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); BuilderPtr += 4; @@ -653,12 +697,12 @@ TEST(WasiNNTest, PyTorchBackend) { // Test: load -- load second graph. { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(1), - static_cast<uint32_t>(Backend::PyTorch), - UINT32_C(0), BuilderPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::PyTorch), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 1); BuilderPtr += 4; @@ -717,10 +761,12 @@ TEST(WasiNNTest, PyTorchBackend) { // Torch WASI-NN set_input tests. SetInputEntryPtr = BuilderPtr; - writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); - writeUInt32(MemInst, UINT32_C(1), BuilderPtr); - writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); writeBinaries<uint32_t>(MemInst, TensorDim, StorePtr); writeBinaries<uint8_t>(MemInst, TensorData, StorePtr + TensorDim.size() * 4); @@ -739,10 +785,12 @@ TEST(WasiNNTest, PyTorchBackend) { // Test: set_input -- tensor type not FP32. BuilderPtr = SetInputEntryPtr; - writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); - writeUInt32(MemInst, UINT32_C(2), BuilderPtr); - writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(2), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, @@ -755,10 +803,12 @@ TEST(WasiNNTest, PyTorchBackend) { // Test: set_input -- set input successfully. BuilderPtr = SetInputEntryPtr; - writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); - writeUInt32(MemInst, UINT32_C(1), BuilderPtr); - writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, @@ -859,9 +909,9 @@ TEST(WasiNNTest, PyTorchBackend) { #ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_TFLITE TEST(WasiNNTest, TFLiteBackend) { - // Create the wasmedge_process module instance. - auto *NNMod = dynamic_cast<WasmEdge::Host::WasiNNModule *>(createModule()); - EXPECT_FALSE(NNMod == nullptr); + // Create the wasi_nn module instance. + auto NNMod = createModule(); + ASSERT_TRUE(NNMod); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -933,7 +983,7 @@ TEST(WasiNNTest, TFLiteBackend) { std::initializer_list<WasmEdge::ValVariant>{ LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::TensorflowLite), - UINT32_C(0), BuilderPtr}, + static_cast<uint32_t>(Device::CPU), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); @@ -946,7 +996,7 @@ TEST(WasiNNTest, TFLiteBackend) { std::initializer_list<WasmEdge::ValVariant>{ LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::TensorflowLite), - UINT32_C(0), OutBoundPtr}, + static_cast<uint32_t>(Device::CPU), OutBoundPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); @@ -959,21 +1009,22 @@ TEST(WasiNNTest, TFLiteBackend) { std::initializer_list<WasmEdge::ValVariant>{ OutBoundPtr, UINT32_C(1), static_cast<uint32_t>(Backend::TensorflowLite), - UINT32_C(0), BuilderPtr}, + static_cast<uint32_t>(Device::CPU), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); } // Test: load -- model bin ptr out of bounds. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, OutBoundPtr, WeightRead.size(), BuilderPtr); + writeFatPointer(MemInst, OutBoundPtr, + static_cast<uint32_t>(WeightRead.size()), BuilderPtr); { EXPECT_TRUE( HostFuncLoad.run(CallFrame, std::initializer_list<WasmEdge::ValVariant>{ LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::TensorflowLite), - UINT32_C(0), BuilderPtr}, + static_cast<uint32_t>(Device::CPU), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); @@ -981,7 +1032,8 @@ TEST(WasiNNTest, TFLiteBackend) { // Test: load -- wrong builders' length. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, StorePtr, WeightRead.size(), BuilderPtr); + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(WeightRead.size()), + BuilderPtr); writeBinaries<uint8_t>(MemInst, WeightRead, StorePtr); StorePtr += WeightRead.size(); { @@ -990,7 +1042,7 @@ TEST(WasiNNTest, TFLiteBackend) { std::initializer_list<WasmEdge::ValVariant>{ LoadEntryPtr, UINT32_C(2), static_cast<uint32_t>(Backend::TensorflowLite), - UINT32_C(0), BuilderPtr}, + static_cast<uint32_t>(Device::CPU), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); @@ -1003,7 +1055,7 @@ TEST(WasiNNTest, TFLiteBackend) { std::initializer_list<WasmEdge::ValVariant>{ LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::TensorflowLite), - UINT32_C(3), BuilderPtr}, + static_cast<uint32_t>(Device::AUTO), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); @@ -1016,7 +1068,7 @@ TEST(WasiNNTest, TFLiteBackend) { std::initializer_list<WasmEdge::ValVariant>{ LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::TensorflowLite), - UINT32_C(0), BuilderPtr}, + static_cast<uint32_t>(Device::CPU), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); @@ -1030,7 +1082,7 @@ TEST(WasiNNTest, TFLiteBackend) { std::initializer_list<WasmEdge::ValVariant>{ LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::TensorflowLite), - UINT32_C(0), BuilderPtr}, + static_cast<uint32_t>(Device::CPU), BuilderPtr}, Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 1); @@ -1089,10 +1141,12 @@ TEST(WasiNNTest, TFLiteBackend) { // Torch WASI-NN set_input tests. SetInputEntryPtr = BuilderPtr; - writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); - writeUInt32(MemInst, UINT32_C(1), BuilderPtr); - writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); writeBinaries<uint32_t>(MemInst, TensorDim, StorePtr); writeBinaries<uint8_t>(MemInst, TensorData, StorePtr + TensorDim.size() * 4); @@ -1111,11 +1165,13 @@ TEST(WasiNNTest, TFLiteBackend) { // Test: set_input -- set input successfully. BuilderPtr = SetInputEntryPtr; - writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), + BuilderPtr); // Tensor type U8 writeUInt32(MemInst, UINT32_C(2), BuilderPtr); - writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), - BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, @@ -1218,9 +1274,9 @@ TEST(WasiNNTest, TFLiteBackend) { #ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_GGML TEST(WasiNNTest, GGMLBackend) { - // Create the wasmedge_process module instance. - auto *NNMod = dynamic_cast<WasmEdge::Host::WasiNNModule *>(createModule()); - EXPECT_FALSE(NNMod == nullptr); + // Create the wasi_nn module instance. + auto NNMod = createModule(); + ASSERT_TRUE(NNMod); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -1282,78 +1338,80 @@ TEST(WasiNNTest, GGMLBackend) { // GGML WASI-NN load tests. // Test: load -- meaningless binaries. { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(1), - static_cast<uint32_t>(Backend::GGML), - UINT32_C(0), BuilderPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::GGML), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); } // Test: load -- graph id ptr out of bounds. { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(1), - static_cast<uint32_t>(Backend::GGML), - UINT32_C(0), OutBoundPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::GGML), + static_cast<uint32_t>(Device::CPU), OutBoundPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); } // Test: load -- graph builder ptr out of bounds. { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - OutBoundPtr, UINT32_C(1), - static_cast<uint32_t>(Backend::GGML), - UINT32_C(0), BuilderPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + OutBoundPtr, UINT32_C(1), static_cast<uint32_t>(Backend::GGML), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); } // Test: load -- GGML model bin ptr out of bounds. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, OutBoundPtr, WeightRead.size(), BuilderPtr); + writeFatPointer(MemInst, OutBoundPtr, + static_cast<uint32_t>(WeightRead.size()), BuilderPtr); { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(1), - static_cast<uint32_t>(Backend::GGML), - UINT32_C(0), BuilderPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::GGML), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidArgument)); } // Test: load -- wrong metadata encoding when builders length > 1. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, StorePtr, WeightRead.size(), BuilderPtr); + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(WeightRead.size()), + BuilderPtr); writeBinaries<uint8_t>(MemInst, WeightRead, StorePtr); - StorePtr += WeightRead.size(); + StorePtr += static_cast<uint32_t>(WeightRead.size()); { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(2), - static_cast<uint32_t>(Backend::GGML), - UINT32_C(0), BuilderPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(2), static_cast<uint32_t>(Backend::GGML), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::InvalidEncoding)); } // Test: load -- load successfully. { - EXPECT_TRUE(HostFuncLoad.run(CallFrame, - std::initializer_list<WasmEdge::ValVariant>{ - LoadEntryPtr, UINT32_C(1), - static_cast<uint32_t>(Backend::GGML), - UINT32_C(0), BuilderPtr}, - Errno)); + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::GGML), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); BuilderPtr += 4; @@ -1383,12 +1441,16 @@ TEST(WasiNNTest, GGMLBackend) { // GGML WASI-NN set_input tests. SetInputEntryPtr = BuilderPtr; - writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); - writeUInt32(MemInst, UINT32_C(1), BuilderPtr); - writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); writeBinaries<uint32_t>(MemInst, TensorDim, StorePtr); - writeBinaries<uint8_t>(MemInst, TensorData, StorePtr + TensorDim.size() * 4); + writeBinaries<uint8_t>(MemInst, TensorData, + StorePtr + + static_cast<uint32_t>(TensorDim.size()) * 4); // Test: set_input -- context id exceeds. { @@ -1403,10 +1465,12 @@ TEST(WasiNNTest, GGMLBackend) { // Test: set_input -- set input successfully. BuilderPtr = SetInputEntryPtr; - writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); - writeUInt32(MemInst, UINT32_C(1), BuilderPtr); - writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, @@ -1415,7 +1479,7 @@ TEST(WasiNNTest, GGMLBackend) { Errno)); EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); } - StorePtr += (TensorDim.size() * 4 + TensorData.size()); + StorePtr += static_cast<uint32_t>(TensorDim.size() * 4 + TensorData.size()); // GGML WASI-NN compute tests. // Test: compute -- context id exceeds. @@ -1491,10 +1555,9 @@ TEST(WasiNNTest, GGMLBackendWithRPC) { GTEST_SKIP() << "WASI_NN_RPC_TEST_URI is unset"; } - // Create the wasmedge_process module instance. - auto *NNMod = - dynamic_cast<WasmEdge::Host::WasiNNModule *>(createModule(NNRPCURI)); - EXPECT_FALSE(NNMod == nullptr); + // Create the wasi_nn module instance. + auto NNMod = createModule(NNRPCURI); + ASSERT_TRUE(NNMod); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -1525,6 +1588,13 @@ TEST(WasiNNTest, GGMLBackendWithRPC) { EXPECT_TRUE(FuncInst->isHostFunction()); auto &HostFuncLoadByName = dynamic_cast<WasmEdge::Host::WasiNNLoadByName &>(FuncInst->getHostFunc()); + // Get the function "load_by_name_with_config". + FuncInst = NNMod->findFuncExports("load_by_name_with_config"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncLoadByNameWithConfig = + dynamic_cast<WasmEdge::Host::WasiNNLoadByNameWithConfig &>( + FuncInst->getHostFunc()); // Get the function "init_execution_context". FuncInst = NNMod->findFuncExports("init_execution_context"); EXPECT_NE(FuncInst, nullptr); @@ -1565,6 +1635,26 @@ TEST(WasiNNTest, GGMLBackendWithRPC) { BuilderPtr += 4; } + // Test: load_by_name_with_config -- load successfully. + { + std::string Name = "default"; + std::string Config = "{}"; + std::vector<char> NameVec(Name.begin(), Name.end()); + std::vector<char> ConfigVec(Config.begin(), Config.end()); + uint32_t ConfigPtr = LoadEntryPtr + NameVec.size(); + writeBinaries<char>(MemInst, NameVec, LoadEntryPtr); + writeBinaries<char>(MemInst, ConfigVec, ConfigPtr); + EXPECT_TRUE(HostFuncLoadByNameWithConfig.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, static_cast<uint32_t>(NameVec.size()), ConfigPtr, + static_cast<uint32_t>(ConfigVec.size()), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); + BuilderPtr += 4; + } + // GGML WASI-NN init_execution_context tests. // Test: init_execution_context -- graph id invalid. { @@ -1588,10 +1678,12 @@ TEST(WasiNNTest, GGMLBackendWithRPC) { // GGML WASI-NN set_input tests. SetInputEntryPtr = BuilderPtr; - writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); - writeUInt32(MemInst, UINT32_C(1), BuilderPtr); - writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); writeBinaries<uint32_t>(MemInst, TensorDim, StorePtr); writeBinaries<uint8_t>(MemInst, TensorData, StorePtr + TensorDim.size() * 4); @@ -1607,10 +1699,12 @@ TEST(WasiNNTest, GGMLBackendWithRPC) { // Test: set_input -- set input successfully. BuilderPtr = SetInputEntryPtr; - writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); - writeUInt32(MemInst, UINT32_C(1), BuilderPtr); - writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, @@ -1676,5 +1770,939 @@ TEST(WasiNNTest, GGMLBackendWithRPC) { EXPECT_GE(BytesWritten, 50); } } -#endif // WASMEDGE_BUILD_WASI_NN_RPC -#endif // WASMEDGE_PLUGIN_WASI_NN_BACKEND_GGML + +TEST(WasiNNTest, GGMLBackendComputeSingleWithRPC) { + // wasi_nn_rpcserver has to be started outside this test, + // and the URI has to be set to $WASI_NN_RPC_TEST_URI. + // nn-preload has to be specified for "default". + /* + DIR=/tmp/build + export WASI_NN_RPC_TEST_URI=unix://${DIR}/wasi_nn_rpc.sock + export WASMEDGE_PLUGIN_PATH=${DIR}/plugins/wasi_nn + ${DIR}/tools/wasmedge/wasi_nn_rpcserver \ + --nn-rpc-uri=$WASI_NN_RPC_TEST_URI \ + --nn-preload=default:GGML:AUTO:${DIR}/test/plugins/wasi_nn/wasinn_ggml_fixtures/orca_mini.gguf + */ + const auto NNRPCURI = ::getenv("WASI_NN_RPC_TEST_URI"); + if (NNRPCURI == nullptr) { + GTEST_SKIP() << "WASI_NN_RPC_TEST_URI is unset"; + } + + // Create the wasmedge_process module instance. + auto NNMod = createModule(NNRPCURI); + ASSERT_TRUE(NNMod); + + // Create the calling frame with memory instance. + WasmEdge::Runtime::Instance::ModuleInstance Mod(""); + Mod.addHostMemory( + "memory", std::make_unique<WasmEdge::Runtime::Instance::MemoryInstance>( + WasmEdge::AST::MemoryType(60000))); + auto *MemInstPtr = Mod.findMemoryExports("memory"); + ASSERT_TRUE(MemInstPtr != nullptr); + auto &MemInst = *MemInstPtr; + WasmEdge::Runtime::CallingFrame CallFrame(nullptr, &Mod); + + std::string Prompt = "Once upon a time, "; + std::vector<uint8_t> TensorData(Prompt.begin(), Prompt.end()); + + std::vector<uint32_t> TensorDim{1}; + uint32_t BuilderPtr = UINT32_C(0); + uint32_t LoadEntryPtr = UINT32_C(0); + uint32_t SetInputEntryPtr = UINT32_C(0); + uint32_t OutBoundPtr = UINT32_C(61000) * UINT32_C(65536); + uint32_t StorePtr = UINT32_C(65536); + + // Return value. + std::array<WasmEdge::ValVariant, 1> Errno = {UINT32_C(0)}; + + // Get the function "load_by_name". + auto FuncInst = NNMod->findFuncExports("load_by_name"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncLoadByName = + dynamic_cast<WasmEdge::Host::WasiNNLoadByName &>(FuncInst->getHostFunc()); + // Get the function "load_by_name_with_config". + FuncInst = NNMod->findFuncExports("load_by_name_with_config"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncLoadByNameWithConfig = + dynamic_cast<WasmEdge::Host::WasiNNLoadByNameWithConfig &>( + FuncInst->getHostFunc()); + // Get the function "init_execution_context". + FuncInst = NNMod->findFuncExports("init_execution_context"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncInit = dynamic_cast<WasmEdge::Host::WasiNNInitExecCtx &>( + FuncInst->getHostFunc()); + // Get the function "set_input". + FuncInst = NNMod->findFuncExports("set_input"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSetInput = + dynamic_cast<WasmEdge::Host::WasiNNSetInput &>(FuncInst->getHostFunc()); + // Get the function "get_output". + FuncInst = NNMod->findFuncExports("get_output_single"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncGetOutputSingle = + dynamic_cast<WasmEdge::Host::WasiNNGetOutputSingle &>( + FuncInst->getHostFunc()); + // Get the function "compute". + FuncInst = NNMod->findFuncExports("compute_single"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncComputeSingle = + dynamic_cast<WasmEdge::Host::WasiNNComputeSingle &>( + FuncInst->getHostFunc()); + + // Test: load_by_name -- load successfully. + { + std::string Name = "default"; + std::vector<char> NameVec(Name.begin(), Name.end()); + writeBinaries<char>(MemInst, NameVec, LoadEntryPtr); + EXPECT_TRUE(HostFuncLoadByName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, static_cast<uint32_t>(NameVec.size()), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); + BuilderPtr += 4; + } + + // Test: load_by_name_with_config -- load successfully. + { + std::string Name = "default"; + std::string Config = "{}"; + std::vector<char> NameVec(Name.begin(), Name.end()); + std::vector<char> ConfigVec(Config.begin(), Config.end()); + uint32_t ConfigPtr = LoadEntryPtr + NameVec.size(); + writeBinaries<char>(MemInst, NameVec, LoadEntryPtr); + writeBinaries<char>(MemInst, ConfigVec, ConfigPtr); + EXPECT_TRUE(HostFuncLoadByNameWithConfig.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, static_cast<uint32_t>(NameVec.size()), ConfigPtr, + static_cast<uint32_t>(ConfigVec.size()), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); + BuilderPtr += 4; + } + + // Test: init_execution_context -- init context successfully. + { + EXPECT_TRUE(HostFuncInit.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{UINT32_C(0), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); + BuilderPtr += 4; + } + + // GGML WASI-NN set_input tests. + SetInputEntryPtr = BuilderPtr; + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), + BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); + writeBinaries<uint32_t>(MemInst, TensorDim, StorePtr); + writeBinaries<uint8_t>(MemInst, TensorData, StorePtr + TensorDim.size() * 4); + + // Test: set_input -- set input successfully. + BuilderPtr = SetInputEntryPtr; + writeFatPointer(MemInst, StorePtr, static_cast<uint32_t>(TensorDim.size()), + BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast<uint32_t>(TensorDim.size()) * 4, + static_cast<uint32_t>(TensorData.size()), BuilderPtr); + { + EXPECT_TRUE( + HostFuncSetInput.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), SetInputEntryPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } + StorePtr += (TensorDim.size() * 4 + TensorData.size()); + + // GGML WASI-NN compute_single tests. + // Test: compute_single -- context id exceeds. + { + EXPECT_TRUE(HostFuncComputeSingle.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(3)}, + Errno)); + EXPECT_NE(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } + + // Test: compute_single -- call compute_single once follow by a + // get_output_single. + { + // compute_single + EXPECT_TRUE(HostFuncComputeSingle.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(0)}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + // get_output_single + EXPECT_TRUE(HostFuncGetOutputSingle.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), StorePtr, 65532, BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } + + // GGML WASI-NN get_output_single tests. + // Test: get_output_single -- output bytes ptr out of bounds. + { + EXPECT_TRUE(HostFuncGetOutputSingle.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), StorePtr, 65532, OutBoundPtr}, + Errno)); + EXPECT_NE(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } + + // Test: get_output -- output buffer ptr out of bounds. + { + EXPECT_TRUE(HostFuncGetOutputSingle.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), OutBoundPtr, 65532, BuilderPtr}, + Errno)); + EXPECT_NE(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } +} +#endif // WASMEDGE_BUILD_WASI_NN_RPC +#endif // WASMEDGE_PLUGIN_WASI_NN_BACKEND_GGML + +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_WHISPER +TEST(WasiNNTest, WhisperBackend) { + // Create the wasi_nn module instance. + auto NNMod = createModule(); + ASSERT_TRUE(NNMod); + + // Create the calling frame with memory instance. + WasmEdge::Runtime::Instance::ModuleInstance Mod(""); + Mod.addHostMemory( + "memory", std::make_unique<WasmEdge::Runtime::Instance::MemoryInstance>( + WasmEdge::AST::MemoryType(60000))); + auto *MemInstPtr = Mod.findMemoryExports("memory"); + ASSERT_TRUE(MemInstPtr != nullptr); + auto &MemInst = *MemInstPtr; + WasmEdge::Runtime::CallingFrame CallFrame(nullptr, &Mod); + + std::vector<uint8_t> TensorData = + readEntireFile("./wasinn_whisper_fixtures/test.wav"); + std::vector<uint8_t> WeightRead = + readEntireFile("./wasinn_whisper_fixtures/ggml-base.bin"); + std::vector<uint32_t> TensorDim{1, static_cast<uint32_t>(TensorData.size())}; + uint32_t BuilderPtr = UINT32_C(0); + uint32_t LoadEntryPtr = UINT32_C(0); + uint32_t SetInputEntryPtr = UINT32_C(0); + uint32_t OutBoundPtr = UINT32_C(61000) * UINT32_C(65536); + uint32_t StorePtr = UINT32_C(65536); + + // Return value. + std::array<WasmEdge::ValVariant, 1> Errno = {UINT32_C(0)}; + + // Get the function "load". + auto *FuncInst = NNMod->findFuncExports("load"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncLoad = + dynamic_cast<WasmEdge::Host::WasiNNLoad &>(FuncInst->getHostFunc()); + // Get the function "init_execution_context". + FuncInst = NNMod->findFuncExports("init_execution_context"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncInit = dynamic_cast<WasmEdge::Host::WasiNNInitExecCtx &>( + FuncInst->getHostFunc()); + // Get the function "set_input". + FuncInst = NNMod->findFuncExports("set_input"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSetInput = + dynamic_cast<WasmEdge::Host::WasiNNSetInput &>(FuncInst->getHostFunc()); + // Get the function "get_output". + FuncInst = NNMod->findFuncExports("get_output"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncGetOutput = + dynamic_cast<WasmEdge::Host::WasiNNGetOutput &>(FuncInst->getHostFunc()); + // Get the function "compute". + FuncInst = NNMod->findFuncExports("compute"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncCompute = + dynamic_cast<WasmEdge::Host::WasiNNCompute &>(FuncInst->getHostFunc()); + + // Whisper WASI-NN load tests. + // Test: load -- meaningless binaries. + { + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::Whisper), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: load -- graph id ptr out of bounds. + { + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::Whisper), + static_cast<uint32_t>(Device::CPU), OutBoundPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: load -- graph builder ptr out of bounds. + { + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + OutBoundPtr, UINT32_C(1), static_cast<uint32_t>(Backend::Whisper), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: load -- Whisper model bin ptr out of bounds. + BuilderPtr = LoadEntryPtr; + writeFatPointer(MemInst, OutBoundPtr, + static_cast<uint32_t>(WeightRead.size()), BuilderPtr); + { + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::Whisper), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: load -- load successfully. + BuilderPtr = LoadEntryPtr; + writeFatPointer(MemInst, StorePtr, WeightRead.size(), BuilderPtr); + writeBinaries<uint8_t>(MemInst, WeightRead, StorePtr); + StorePtr += WeightRead.size(); + { + EXPECT_TRUE(HostFuncLoad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), static_cast<uint32_t>(Backend::Whisper), + static_cast<uint32_t>(Device::CPU), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); + BuilderPtr += 4; + } + + // Whisper WASI-NN init_execution_context tests. + // Test: init_execution_context -- graph id invalid. + { + EXPECT_TRUE(HostFuncInit.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{UINT32_C(2), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + + // Test: init_execution_context -- init second context. + { + EXPECT_TRUE(HostFuncInit.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{UINT32_C(0), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); + BuilderPtr += 4; + } + + // Whisper WASI-NN set_input tests. + SetInputEntryPtr = BuilderPtr; + writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), + BuilderPtr); + writeBinaries<uint32_t>(MemInst, TensorDim, StorePtr); + writeBinaries<uint8_t>(MemInst, TensorData, StorePtr + TensorDim.size() * 4); + + // Test: set_input -- context id exceeds. + { + EXPECT_TRUE( + HostFuncSetInput.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(3), UINT32_C(0), SetInputEntryPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: set_input -- set input successfully. + { + EXPECT_TRUE( + HostFuncSetInput.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), SetInputEntryPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } + StorePtr += (TensorDim.size() * 4 + TensorData.size()); + + // Whisper WASI-NN compute tests. + // Test: compute -- context id exceeds. + { + EXPECT_TRUE(HostFuncCompute.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(3)}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: compute -- compute successfully. + { + EXPECT_TRUE(HostFuncCompute.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(0)}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } + + // Whisper WASI-NN get_output tests. + // Test: get_output -- output bytes ptr out of bounds. + { + EXPECT_TRUE(HostFuncGetOutput.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), StorePtr, 65532, OutBoundPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: get_output -- output buffer ptr out of bounds. + { + EXPECT_TRUE(HostFuncGetOutput.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), OutBoundPtr, 65532, BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: get_output -- get output successfully. + { + EXPECT_TRUE(HostFuncGetOutput.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), StorePtr, 65532, BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + // Should output more than 50 bytes. + auto BytesWritten = *MemInst.getPointer<uint32_t *>(BuilderPtr); + EXPECT_GE(BytesWritten, 50); + } +} +#endif // WASMEDGE_PLUGIN_WASI_NN_BACKEND_WHISPER + +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_PIPER +TEST(WasiNNTest, PiperBackend) { + // Create the wasmedge_process module instance. + auto NNMod = createModule(); + ASSERT_TRUE(NNMod); + + // Create the calling frame with memory instance. + WasmEdge::Runtime::Instance::ModuleInstance Mod(""); + Mod.addHostMemory( + "memory", std::make_unique<WasmEdge::Runtime::Instance::MemoryInstance>( + WasmEdge::AST::MemoryType(400))); + auto *MemInstPtr = Mod.findMemoryExports("memory"); + ASSERT_TRUE(MemInstPtr != nullptr); + auto &MemInst = *MemInstPtr; + WasmEdge::Runtime::CallingFrame CallFrame(nullptr, &Mod); + + // Load the files. + (void)readEntireFile; + std::string Text = "This is a test."; + std::vector<uint8_t> TensorData(Text.begin(), Text.end()); + + std::vector<uint32_t> TensorDim{1}; + uint32_t BuilderPtr = UINT32_C(0); + uint32_t LoadEntryPtr = UINT32_C(0); + uint32_t SetInputEntryPtr = UINT32_C(0); + uint32_t OutBoundPtr = UINT32_C(410 * 65536); + uint32_t StorePtr = UINT32_C(65536); + + // Return value. + std::array<WasmEdge::ValVariant, 1> Errno = {UINT32_C(0)}; + + // Get the function "load". + auto *FuncInst = NNMod->findFuncExports("load"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncLoad = + dynamic_cast<WasmEdge::Host::WasiNNLoad &>(FuncInst->getHostFunc()); + // Get the function "init_execution_context". + FuncInst = NNMod->findFuncExports("init_execution_context"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncInit = dynamic_cast<WasmEdge::Host::WasiNNInitExecCtx &>( + FuncInst->getHostFunc()); + // Get the function "set_input". + FuncInst = NNMod->findFuncExports("set_input"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSetInput = + dynamic_cast<WasmEdge::Host::WasiNNSetInput &>(FuncInst->getHostFunc()); + // Get the function "get_output". + FuncInst = NNMod->findFuncExports("get_output"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncGetOutput = + dynamic_cast<WasmEdge::Host::WasiNNGetOutput &>(FuncInst->getHostFunc()); + // Get the function "compute". + FuncInst = NNMod->findFuncExports("compute"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncCompute = + dynamic_cast<WasmEdge::Host::WasiNNCompute &>(FuncInst->getHostFunc()); + + // Piper WASI-NN load tests. + // Test: load -- graph id ptr out of bounds. + { + EXPECT_TRUE(HostFuncLoad.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), + static_cast<uint32_t>(Backend::Piper), + UINT32_C(0), OutBoundPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + + // Test: load -- graph builder ptr out of bounds. + { + EXPECT_TRUE(HostFuncLoad.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + OutBoundPtr, UINT32_C(1), + static_cast<uint32_t>(Backend::Piper), + UINT32_C(0), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + + // Test: load -- Piper config ptr out of bounds. + BuilderPtr = LoadEntryPtr; + writeFatPointer(MemInst, OutBoundPtr, 1, BuilderPtr); + { + EXPECT_TRUE(HostFuncLoad.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), + static_cast<uint32_t>(Backend::Piper), + UINT32_C(0), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + + // Test: load -- wrong config encoding. + BuilderPtr = LoadEntryPtr; + writeFatPointer(MemInst, StorePtr, 0, BuilderPtr); + { + EXPECT_TRUE(HostFuncLoad.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), + static_cast<uint32_t>(Backend::Piper), + UINT32_C(0), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidEncoding)); + } + + // Test: load -- load successfully. + std::string Config = + "{\"model\": \"./wasinn_piper_fixtures/test_voice.onnx\", " + "\"espeak_data\": \"./wasinn_piper_fixtures/piper/espeak-ng-data\"}"; + std::vector<uint8_t> ConfigData(Config.begin(), Config.end()); + BuilderPtr = LoadEntryPtr; + writeFatPointer(MemInst, StorePtr, ConfigData.size(), BuilderPtr); + writeBinaries<uint8_t>(MemInst, ConfigData, StorePtr); + { + EXPECT_TRUE(HostFuncLoad.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), + static_cast<uint32_t>(Backend::Piper), + UINT32_C(0), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); + BuilderPtr += 4; + } + + // Piper WASI-NN init_execution_context tests. + // Test: init_execution_context -- graph id invalid. + { + EXPECT_TRUE(HostFuncInit.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{UINT32_C(2), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + + // Test: init_execution_context -- init context successfully. + { + EXPECT_TRUE(HostFuncInit.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{UINT32_C(0), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); + BuilderPtr += 4; + } + + // Piper WASI-NN set_input tests. + SetInputEntryPtr = BuilderPtr; + writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); + writeUInt32(MemInst, 2, BuilderPtr); + writeFatPointer(MemInst, + StorePtr + TensorDim.size() * + sizeof(decltype(TensorDim)::value_type), + TensorData.size(), BuilderPtr); + writeBinaries<uint32_t>(MemInst, TensorDim, StorePtr); + writeBinaries<uint8_t>( + MemInst, TensorData, + StorePtr + TensorDim.size() * sizeof(decltype(TensorDim)::value_type)); + + // Test: set_input -- context id exceeds. + { + EXPECT_TRUE( + HostFuncSetInput.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(3), UINT32_C(0), SetInputEntryPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: set_input -- set input successfully. + { + EXPECT_TRUE( + HostFuncSetInput.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), SetInputEntryPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } + StorePtr += TensorDim.size() * sizeof(decltype(TensorDim)::value_type) + + TensorData.size(); + + // Piper WASI-NN compute tests. + // Test: compute -- context id exceeds. + { + EXPECT_TRUE(HostFuncCompute.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(3)}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: compute -- compute successfully. + { + EXPECT_TRUE(HostFuncCompute.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(0)}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } + + // Piper WASI-NN get_output tests. + // Test: get_output -- output bytes ptr out of bounds. + { + EXPECT_TRUE(HostFuncGetOutput.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), StorePtr, 65532, OutBoundPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + + // Test: get_output -- output buffer ptr out of bounds. + { + EXPECT_TRUE(HostFuncGetOutput.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), OutBoundPtr, 65532, BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: get_output -- get output successfully. + { + EXPECT_TRUE(HostFuncGetOutput.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), StorePtr, 65532, BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + // Should output more than 10000 bytes. + auto BytesWritten = *MemInst.getPointer<uint32_t *>(BuilderPtr); + EXPECT_GE(BytesWritten, 10000); + } +} +#endif // WASMEDGE_PLUGIN_WASI_NN_BACKEND_PIPER + +#ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_CHATTTS +TEST(WasiNNTest, ChatTTSBackend) { + // Create the wasmedge_process module instance. + auto NNMod = createModule(); + ASSERT_TRUE(NNMod); + + // Create the calling frame with memory instance. + WasmEdge::Runtime::Instance::ModuleInstance Mod(""); + Mod.addHostMemory( + "memory", std::make_unique<WasmEdge::Runtime::Instance::MemoryInstance>( + WasmEdge::AST::MemoryType(60000))); + auto *MemInstPtr = Mod.findMemoryExports("memory"); + ASSERT_TRUE(MemInstPtr != nullptr); + auto &MemInst = *MemInstPtr; + WasmEdge::Runtime::CallingFrame CallFrame(nullptr, &Mod); + + // Load the files. + std::string Prompt = "This is test prompt."; + std::vector<uint8_t> TensorData(Prompt.begin(), Prompt.end()); + std::string config = + "{\"prompt\":\"[oral_2][laugh_0][break_6]\",\"spk_emb\":\"random\"," + "\"temperature\":0.5,\"top_k\":0,\"top_p\":0.9}"; + std::vector<uint8_t> ConfigData(config.begin(), config.end()); + + std::vector<uint32_t> TensorDim{1}; + uint32_t BuilderPtr = UINT32_C(0); + uint32_t LoadEntryPtr = UINT32_C(0); + uint32_t SetInputEntryPtr = UINT32_C(0); + uint32_t OutBoundPtr = UINT32_C(61000) * UINT32_C(65536); + uint32_t StorePtr = UINT32_C(65536); + + // Return value. + std::array<WasmEdge::ValVariant, 1> Errno = {UINT32_C(0)}; + + // Get the function "load". + auto *FuncInst = NNMod->findFuncExports("load"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncLoad = + dynamic_cast<WasmEdge::Host::WasiNNLoad &>(FuncInst->getHostFunc()); + // Get the function "init_execution_context". + FuncInst = NNMod->findFuncExports("init_execution_context"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncInit = dynamic_cast<WasmEdge::Host::WasiNNInitExecCtx &>( + FuncInst->getHostFunc()); + // Get the function "set_input". + FuncInst = NNMod->findFuncExports("set_input"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSetInput = + dynamic_cast<WasmEdge::Host::WasiNNSetInput &>(FuncInst->getHostFunc()); + // Get the function "get_output". + FuncInst = NNMod->findFuncExports("get_output"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncGetOutput = + dynamic_cast<WasmEdge::Host::WasiNNGetOutput &>(FuncInst->getHostFunc()); + // Get the function "compute". + FuncInst = NNMod->findFuncExports("compute"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncCompute = + dynamic_cast<WasmEdge::Host::WasiNNCompute &>(FuncInst->getHostFunc()); + // Get the function "unload". + FuncInst = NNMod->findFuncExports("unload"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncUnload = + dynamic_cast<WasmEdge::Host::WasiNNUnload &>(FuncInst->getHostFunc()); + + // ChatTTS WASI-NN load tests. + // Test: load -- graph id ptr out of bounds. + { + EXPECT_TRUE(HostFuncLoad.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), + static_cast<uint32_t>(Backend::ChatTTS), + UINT32_C(0), OutBoundPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + + // Test: load -- graph builder ptr out of bounds. + { + EXPECT_TRUE(HostFuncLoad.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + OutBoundPtr, UINT32_C(1), + static_cast<uint32_t>(Backend::ChatTTS), + UINT32_C(0), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + + // Test: load -- load successfully. + BuilderPtr = LoadEntryPtr; + { + EXPECT_TRUE(HostFuncLoad.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + LoadEntryPtr, UINT32_C(1), + static_cast<uint32_t>(Backend::ChatTTS), + UINT32_C(0), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); + BuilderPtr += 4; + } + // ChatTTS WASI-NN init_execution_context tests. + // Test: init_execution_context -- graph id invalid. + { + EXPECT_TRUE(HostFuncInit.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{UINT32_C(2), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + + // Test: init_execution_context -- init second context. + { + EXPECT_TRUE(HostFuncInit.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{UINT32_C(0), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + EXPECT_EQ(*MemInst.getPointer<uint32_t *>(BuilderPtr), 0); + BuilderPtr += 4; + } + + // ChatTTS WASI-NN set_input tests. + SetInputEntryPtr = BuilderPtr; + writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); + writeUInt32(MemInst, UINT32_C(2), BuilderPtr); + writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, TensorData.size(), + BuilderPtr); + writeBinaries<uint32_t>(MemInst, TensorDim, StorePtr); + writeBinaries<uint8_t>(MemInst, TensorData, StorePtr + TensorDim.size() * 4); + + // Test: set_input -- context id exceeds. + { + EXPECT_TRUE( + HostFuncSetInput.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(3), UINT32_C(0), SetInputEntryPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: set_input -- set input successfully. + { + EXPECT_TRUE( + HostFuncSetInput.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), SetInputEntryPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } + StorePtr += (TensorDim.size() * 4 + TensorData.size()); + + // ChatTTS WASI-NN compute tests. + // Test: compute -- context id exceeds. + { + EXPECT_TRUE(HostFuncCompute.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(3)}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: compute -- compute successfully. + { + EXPECT_TRUE(HostFuncCompute.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(0)}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } + + // Test: setInput -- set metadata successfully. + SetInputEntryPtr = BuilderPtr; + writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); + writeUInt32(MemInst, UINT32_C(2), BuilderPtr); + writeFatPointer(MemInst, StorePtr + TensorDim.size() * 4, ConfigData.size(), + BuilderPtr); + writeBinaries<uint32_t>(MemInst, TensorDim, StorePtr); + writeBinaries<uint8_t>(MemInst, ConfigData, StorePtr + TensorDim.size() * 4); + { + EXPECT_TRUE( + HostFuncSetInput.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(1), SetInputEntryPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } + StorePtr += (TensorDim.size() * 4 + ConfigData.size()); + + // Test: compute -- compute successfully. + { + EXPECT_TRUE(HostFuncCompute.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(0)}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } + + // ChatTTS WASI-NN get_output tests. + // Test: get_output -- output bytes ptr out of bounds. + { + EXPECT_TRUE(HostFuncGetOutput.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), StorePtr, 65532, OutBoundPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + + // Test: get_output -- output buffer ptr out of bounds. + { + EXPECT_TRUE(HostFuncGetOutput.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), OutBoundPtr, 65532, BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), + static_cast<uint32_t>(ErrNo::InvalidArgument)); + } + // Test: get_output -- get output successfully. + { + EXPECT_TRUE(HostFuncGetOutput.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + UINT32_C(0), UINT32_C(0), StorePtr, 65532, BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + // Should output more than 50 bytes. + auto BytesWritten = *MemInst.getPointer<uint32_t *>(BuilderPtr); + EXPECT_GE(BytesWritten, 50); + } + + // ChatTTS WASI-NN unload tests. + // Test: unload -- unload successfully. + { + EXPECT_TRUE(HostFuncUnload.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(0)}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + } +} +#endif // WASMEDGE_PLUGIN_WASI_NN_BACKEND_CHATTTS diff --git a/test/plugins/wasm_bpf/CMakeLists.txt b/test/plugins/wasm_bpf/CMakeLists.txt index c91608c5ba89..625bfafe087c 100644 --- a/test/plugins/wasm_bpf/CMakeLists.txt +++ b/test/plugins/wasm_bpf/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmBpfTests simple_map_test.cpp diff --git a/test/plugins/wasm_bpf/assets/bpf-sources/simple_map.bpf.c b/test/plugins/wasm_bpf/assets/bpf-sources/simple_map.bpf.c index a787ceaa4edf..1049aa5f20d3 100644 --- a/test/plugins/wasm_bpf/assets/bpf-sources/simple_map.bpf.c +++ b/test/plugins/wasm_bpf/assets/bpf-sources/simple_map.bpf.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #define SEC(name) __attribute__((section(name), used)) #define __uint(name, val) int(*name)[val] diff --git a/test/plugins/wasm_bpf/assets/bpf-sources/simple_ringbuf.bpf.c b/test/plugins/wasm_bpf/assets/bpf-sources/simple_ringbuf.bpf.c index 888c6e1a7342..0a0b0e8dccd5 100644 --- a/test/plugins/wasm_bpf/assets/bpf-sources/simple_ringbuf.bpf.c +++ b/test/plugins/wasm_bpf/assets/bpf-sources/simple_ringbuf.bpf.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #define SEC(name) __attribute__((section(name), used)) #define __uint(name, val) int(*name)[val] diff --git a/test/plugins/wasm_bpf/simple_map_test.cpp b/test/plugins/wasm_bpf/simple_map_test.cpp index 9a86892cc795..b6c4c00c02e2 100644 --- a/test/plugins/wasm_bpf/simple_map_test.cpp +++ b/test/plugins/wasm_bpf/simple_map_test.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #include "executor/executor.h" @@ -23,9 +23,9 @@ namespace { WasmEdge::Runtime::Instance::ModuleInstance *createModule() { using namespace std::literals::string_view_literals; - WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "../../../plugins/wasm_bpf/" - "libwasmedgePluginWasmBpf" WASMEDGE_LIB_EXTENSION)); + WasmEdge::Plugin::Plugin::load( + std::filesystem::u8path("../../../plugins/wasm_bpf/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasmBpf" WASMEDGE_LIB_EXTENSION)); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasm_bpf"sv)) { if (const auto *Module = Plugin->findModule("wasm_bpf"sv)) { return Module->create().release(); diff --git a/test/plugins/wasm_bpf/simple_ringbuf_test.cpp b/test/plugins/wasm_bpf/simple_ringbuf_test.cpp index b615524e360a..81fc935bca99 100644 --- a/test/plugins/wasm_bpf/simple_ringbuf_test.cpp +++ b/test/plugins/wasm_bpf/simple_ringbuf_test.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #include "executor/executor.h" @@ -19,9 +19,9 @@ namespace { WasmEdge::Runtime::Instance::ModuleInstance *createModule() { using namespace std::literals::string_view_literals; - WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "../../../plugins/wasm_bpf/" - "libwasmedgePluginWasmBpf" WASMEDGE_LIB_EXTENSION)); + WasmEdge::Plugin::Plugin::load( + std::filesystem::u8path("../../../plugins/wasm_bpf/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasmBpf" WASMEDGE_LIB_EXTENSION)); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasm_bpf"sv)) { if (const auto *Module = Plugin->findModule("wasm_bpf"sv)) { return Module->create().release(); @@ -186,16 +186,17 @@ TEST(WasmBpfTest, SimpleRingbuf) { // In the following several steps we will prepare for polling // Create an instance of the polling callback function - auto callbackFuncInst = - std::make_unique<WasmEdge::Runtime::Instance::FunctionInstance>( - &moduleInst, std::make_unique<PollCallbackFunction>()); + moduleInst.addHostFunc("__polling_callback_hostfunc"sv, + std::make_unique<PollCallbackFunction>()); + auto *callbackFuncInst = + moduleInst.findFuncExports("__polling_callback_hostfunc"); // Create a function table, and fill the callback function into it auto funcTableInst = std::make_unique<WasmEdge::Runtime::Instance::TableInstance>( WasmEdge::AST::TableType(WasmEdge::TypeCode::FuncRef, 1)); ASSERT_TRUE(funcTableInst->setRefs( - std::initializer_list<const WasmEdge::RefVariant>{callbackFuncInst.get()}, - 0, 0, 1)); + std::initializer_list<const WasmEdge::RefVariant>{callbackFuncInst}, 0, 0, + 1)); // Add the table to the main module moduleInst.addHostTable("__indirect_function_table"sv, std::move(funcTableInst)); diff --git a/test/plugins/wasm_bpf/wasm_bpf.cpp b/test/plugins/wasm_bpf/wasm_bpf.cpp index 5f80042d7ef8..827a491d6cd6 100644 --- a/test/plugins/wasm_bpf/wasm_bpf.cpp +++ b/test/plugins/wasm_bpf/wasm_bpf.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "ast/type.h" #include "common/defines.h" @@ -16,30 +16,41 @@ #include <algorithm> #include <array> #include <chrono> -#include <cinttypes> #include <ctime> #include <filesystem> +#include <fmt/chrono.h> +#include <fmt/format.h> #include <fstream> #include <gtest/gtest.h> -#include <iomanip> -#include <iostream> #include <memory> #include <string> #include <string_view> #include <thread> #include <vector> namespace { -WasmEdge::Runtime::Instance::ModuleInstance *createModule() { + +template <typename T, typename U> +inline std::unique_ptr<T> dynamicPointerCast(std::unique_ptr<U> &&R) noexcept { + static_assert(std::has_virtual_destructor_v<T>); + T *P = dynamic_cast<T *>(R.get()); + if (P) { + R.release(); + } + return std::unique_ptr<T>(P); +} + +std::unique_ptr<WasmEdge::Host::WasmBpfModule> createModule() { using namespace std::literals::string_view_literals; - WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "../../../plugins/wasm_bpf/" - "libwasmedgePluginWasmBpf" WASMEDGE_LIB_EXTENSION)); + WasmEdge::Plugin::Plugin::load( + std::filesystem::u8path("../../../plugins/wasm_bpf/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasmBpf" WASMEDGE_LIB_EXTENSION)); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasm_bpf"sv)) { if (const auto *Module = Plugin->findModule("wasm_bpf"sv)) { - return Module->create().release(); + return dynamicPointerCast<WasmEdge::Host::WasmBpfModule>( + Module->create()); } } - return nullptr; + return {}; } std::filesystem::path getAssertsPath() { @@ -60,8 +71,8 @@ void fillMemContent(WasmEdge::Runtime::Instance::MemoryInstance &memInst, } // namespace TEST(WasmBpfTest, Module) { - auto module = dynamic_cast<WasmEdge::Host::WasmBpfModule *>(createModule()); - EXPECT_NE(module, nullptr); + auto module = createModule(); + ASSERT_TRUE(module); // Test whether functions are exported EXPECT_EQ(module->getFuncExportNum(), 6U); EXPECT_NE(module->findFuncExports("wasm_load_bpf_object"), nullptr); @@ -70,8 +81,6 @@ TEST(WasmBpfTest, Module) { EXPECT_NE(module->findFuncExports("wasm_bpf_buffer_poll"), nullptr); EXPECT_NE(module->findFuncExports("wasm_bpf_map_fd_by_name"), nullptr); EXPECT_NE(module->findFuncExports("wasm_bpf_map_operate"), nullptr); - - delete module; } static const size_t TASK_COMM_LEN = 16; @@ -106,24 +115,18 @@ class PollCallbackFunction if (unlikely(!dataPtr)) { return WasmEdge::Unexpect(WasmEdge::ErrCode::Value::HostFuncError); } - auto nowTime = chrono::system_clock::to_time_t(chrono::system_clock::now()); - tm nowTimeRepr; - localtime_r(&nowTime, &nowTimeRepr); + auto nowTime = chrono::system_clock::now(); if (dataPtr->exit_event == 1) { - cout.setf(ios::left); - cout << std::put_time(&nowTimeRepr, "%H:%M:%S") << " EXIT " << setw(16) - << setfill(' ') << dataPtr->comm << " " << setw(7) << setfill(' ') - << dataPtr->pid << " " << setw(7) << setfill(' ') << dataPtr->ppid - << " [" << dataPtr->exit_code << "]"; + fmt::print("{:%H:%M:%S} EXIT {:<16} {:<7} {:<7} [{}]"sv, nowTime, + dataPtr->comm, dataPtr->pid, dataPtr->ppid, + dataPtr->exit_code); if (dataPtr->duration_ns != 0) { - cout << " (" << dataPtr->duration_ns / 1000000 << ")" << endl; + fmt::print(" ({})"sv, dataPtr->duration_ns / 1000000); } + fmt::print("\n"sv); } else { - cout.setf(ios::left); - cout << std::put_time(&nowTimeRepr, "%H:%M:%S") << " EXEC " << setw(16) - << setfill(' ') << dataPtr->comm << " " << setw(7) << setfill(' ') - << dataPtr->pid << " " << setw(7) << setfill(' ') << dataPtr->ppid - << " " << dataPtr->filename << endl; + fmt::print("{:%H:%M:%S} EXEC {:<16} {:<7} {:<7} {}\n"sv, nowTime, + dataPtr->comm, dataPtr->pid, dataPtr->ppid, dataPtr->filename); } return 0; } @@ -132,8 +135,8 @@ class PollCallbackFunction TEST(WasmBpfTest, RunBpfProgramWithPolling) { using namespace std::literals::string_view_literals; // Test loading and attaching a bpf program, and polling buffer - auto module = dynamic_cast<WasmEdge::Host::WasmBpfModule *>(createModule()); - EXPECT_NE(module, nullptr); + auto module = createModule(); + ASSERT_TRUE(module); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance moduleInst(""); @@ -279,16 +282,17 @@ TEST(WasmBpfTest, RunBpfProgramWithPolling) { // In the following several steps we will prepare for polling // Create an instance of the polling callback function - auto callbackFuncInst = - std::make_unique<WasmEdge::Runtime::Instance::FunctionInstance>( - &moduleInst, std::make_unique<PollCallbackFunction>()); + moduleInst.addHostFunc("__polling_callback_hostfunc"sv, + std::make_unique<PollCallbackFunction>()); + auto *callbackFuncInst = + moduleInst.findFuncExports("__polling_callback_hostfunc"); // Create a function table, and fill the callback function into it auto funcTableInst = std::make_unique<WasmEdge::Runtime::Instance::TableInstance>( WasmEdge::AST::TableType(WasmEdge::TypeCode::FuncRef, 1)); EXPECT_TRUE(funcTableInst->setRefs( - std::initializer_list<const WasmEdge::RefVariant>{callbackFuncInst.get()}, - 0, 0, 1)); + std::initializer_list<const WasmEdge::RefVariant>{callbackFuncInst}, 0, 0, + 1)); // Add the table to the main module moduleInst.addHostTable("__indirect_function_table"sv, std::move(funcTableInst)); @@ -345,8 +349,8 @@ struct hist { TEST(WasmBpfTest, RunBpfProgramWithMapOperation) { // Test loading and attaching a bpf program, and polling buffer - auto module = dynamic_cast<WasmEdge::Host::WasmBpfModule *>(createModule()); - EXPECT_NE(module, nullptr); + auto module = createModule(); + ASSERT_TRUE(module); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance moduleInst(""); @@ -542,9 +546,7 @@ TEST(WasmBpfTest, RunBpfProgramWithMapOperation) { for (size_t i = 0; i < maxIdx; i++) { auto low = UINT64_C(1) << (i); auto high = (UINT64_C(1) << (i + 1)) - 1; - cout.setf(ios::left); - cout << setw(6) << low << "..." << setw(6) << high << " " << setw(6) - << histRef.slots[i] << endl; + fmt::print("{:<6}...{:<6} {:<6}\n"sv, low, high, histRef.slots[i]); } writeU32(lookUpKeyOffset, readU32(nextKeyOffset)); } @@ -553,7 +555,7 @@ TEST(WasmBpfTest, RunBpfProgramWithMapOperation) { EXPECT_GE(mapDeleteElem(histsFd, nextKeyOffset), 0); writeU32(lookUpKeyOffset, readU32(nextKeyOffset)); } - cout << endl; + fmt::print("\n"sv); } // Get function `wasm_close_bpf_object` diff --git a/test/plugins/wasmedge_ffmpeg/CMakeLists.txt b/test/plugins/wasmedge_ffmpeg/CMakeLists.txt new file mode 100644 index 000000000000..f1c0ca15b187 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/CMakeLists.txt @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +wasmedge_add_executable(wasmedgeFFmpegTests + main.cpp + + avcodec/avcodec_func.cpp + avcodec/avCodec.cpp + avcodec/avCodecParameters.cpp + avcodec/avPacket.cpp + avcodec/avCodecCtx.cpp + + avfilter/avfilter_func.cpp + avfilter/avfilter.cpp + + avformat/avformat_func.cpp + avformat/avformatContext.cpp + avformat/avInputOutputContext.cpp + avformat/avStream.cpp + avformat/avChapter.cpp + + avutil/avRational.cpp + avutil/avDictionary.cpp + avutil/avFrame.cpp + avutil/avutil_func.cpp + avutil/avError.cpp + avutil/avSampleFmt.cpp + avutil/avPixfmt.cpp + + swresample/swresample_func.cpp + + swscale/swscale_func.cpp + + utils.cpp +) + +# Downloading a sample file +execute_process( + COMMAND bash ${CMAKE_SOURCE_DIR}/utils/ffmpeg/download-ffmpeg-sample-video.sh ${CMAKE_CURRENT_BINARY_DIR}/ffmpeg-assets + RESULT_VARIABLE DOWNLOAD_ERROR + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +add_dependencies(wasmedgeFFmpegTests + wasmedgePluginWasmEdgeFFmpeg +) + +target_include_directories(wasmedgeFFmpegTests + PUBLIC + $<TARGET_PROPERTY:wasmedgePlugin,INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:wasmedgePluginWasmEdgeFFmpeg,INCLUDE_DIRECTORIES> + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(wasmedgeFFmpegTests + PRIVATE + ${GTEST_BOTH_LIBRARIES} +) + +# Link to the WasmEdge library +if(WASMEDGE_LINK_PLUGINS_STATIC) + target_link_libraries(wasmedgeFFmpegTests + PRIVATE + wasmedgeCAPI + ) +else() + target_link_libraries(wasmedgeFFmpegTests + PRIVATE + wasmedge_shared + ) +endif() + +add_test(wasmedgeFFmpegTests wasmedgeFFmpegTests) diff --git a/test/plugins/wasmedge_ffmpeg/avcodec/avCodec.cpp b/test/plugins/wasmedge_ffmpeg/avcodec/avCodec.cpp new file mode 100644 index 000000000000..17dc5a49ff02 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avcodec/avCodec.cpp @@ -0,0 +1,367 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avcodec/avCodec.h" +#include "avcodec/module.h" +#include "utils.h" + +#include <gtest/gtest.h> + +// Testing all AVCodecstruct + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVCodec) { + ASSERT_TRUE(AVCodecMod != nullptr); + + uint32_t AVCodecPtr = UINT32_C(20); + uint32_t StringPtr = UINT32_C(68); + uint32_t NumeratorPtr = UINT32_C(72); + uint32_t DenominatorPtr = UINT32_C(76); + std::string FileName = "ffmpeg-assets/sample_video.mp4"; // 32 chars + spdlog::info("Init FFmpeg Structs"sv); + initFFmpegStructs(AVCodecPtr, UINT32_C(24), UINT32_C(28), FileName, + UINT32_C(60), UINT32_C(64), UINT32_C(68), UINT32_C(72)); + + uint32_t AVCodecId = readUInt32(MemInst, AVCodecPtr); + auto *FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_id"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecID = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecID &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecId"sv); + { + EXPECT_TRUE(HostFuncAVCodecID.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 27); // H264 + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_type"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecType = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecType &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecType"sv); + { + EXPECT_TRUE(HostFuncAVCodecType.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), + 0); // MediaType is Video + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_max_lowres"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecMaxLowres = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecMaxLowres &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecMaxLowres"sv); + { + EXPECT_TRUE(HostFuncAVCodecMaxLowres.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_capabilities"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCapabilities = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCapabilities &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecCapabilities"sv); + { + EXPECT_TRUE(HostFuncAVCodecCapabilities.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() > 0); + } + + int32_t Length = 0; + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_get_name_len"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecGetNameLen = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecGetNameLen &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecGetNameLen"sv); + { + EXPECT_TRUE(HostFuncAVCodecGetNameLen.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId}, + Result)); + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_get_name"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecGetName = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecGetName &>( + FuncInst->getHostFunc()); + + // Fill the Memory with 0. + fillMemContent(MemInst, StringPtr, Length); + spdlog::info("Testing AVCodecGetName"sv); + { + EXPECT_TRUE( + HostFuncAVCodecGetName.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + AVCodecId, StringPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_get_long_name_len"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecGetLongNameLen = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecGetLongNameLen &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecGetLongNameLen"sv); + { + EXPECT_TRUE(HostFuncAVCodecGetLongNameLen.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId}, + Result)); + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_get_long_name"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecGetLongName = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecGetLongName &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecGetLongName"sv); + { + EXPECT_TRUE(HostFuncAVCodecGetLongName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecId, StringPtr, + Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_profiles"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecProfiles = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecProfiles &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecProfiles"sv); + { + EXPECT_TRUE(HostFuncAVCodecProfiles.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_pix_fmts_is_null"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecPixFmtIsNull = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecPixFmtsIsNull &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecPixFmtsIsNull"sv); + { + EXPECT_TRUE(HostFuncAVCodecPixFmtIsNull.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_pix_fmts_iter"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecPixFmtIter = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecPixFmtsIter &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecPixFmtsIter"sv); + { + uint32_t Idx = 0; + EXPECT_TRUE(HostFuncAVCodecPixFmtIter.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId, Idx}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_supported_framerate_is_null"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecSupportedFrameratesIsNull = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecSupportedFrameratesIsNull + &>(FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecSupportedFramratesIsNull"sv); + { + EXPECT_TRUE(HostFuncAVCodecSupportedFrameratesIsNull.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_supported_framerate_iter"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecSupportedFrameratesIter = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecSupportedFrameratesIter + &>(FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecSupportedFrameratesIter"sv); + { + EXPECT_TRUE(HostFuncAVCodecSupportedFrameratesIter.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecId, 1, NumeratorPtr, + DenominatorPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_supported_samplerates_is_null"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecSupportedSampleRatesIsNull = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecSupportedSampleRatesIsNull + &>(FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecSupportedSampleRatesIsNull"sv); + { + EXPECT_TRUE(HostFuncAVCodecSupportedSampleRatesIsNull.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_supported_samplerates_iter"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecSupportedSampleRatesIter = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecSupportedSampleRatesIter + &>(FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecSupportedSampleRatesIter"sv); + { + EXPECT_TRUE(HostFuncAVCodecSupportedSampleRatesIter.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId, 0}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_channel_layouts_is_null"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecChannelLayoutIsNull = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecChannelLayoutIsNull &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecChannelLayoutIsNull"sv); + { + EXPECT_TRUE(HostFuncAVCodecChannelLayoutIsNull.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_channel_layouts_iter"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecChannelLayoutIter = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecChannelLayoutIter &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecChannelLayoutIter"sv); + { + EXPECT_TRUE(HostFuncAVCodecChannelLayoutIter.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId, 0}, + Result)); + EXPECT_EQ(Result[0].get<int64_t>(), 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_sample_fmts_is_null"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecSampleFmtsIsNull = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecSampleFmtsIsNull &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecSampleFmtsIsNull"sv); + { + EXPECT_TRUE(HostFuncAVCodecSampleFmtsIsNull.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_sample_fmts_iter"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecSampleFmtsIter = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecSampleFmtsIter &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecSampleFmtsIter"sv); + { + EXPECT_TRUE(HostFuncAVCodecSampleFmtsIter.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecId, 0}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } +} +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avcodec/avCodecCtx.cpp b/test/plugins/wasmedge_ffmpeg/avcodec/avCodecCtx.cpp new file mode 100644 index 000000000000..d7adca941276 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avcodec/avCodecCtx.cpp @@ -0,0 +1,1661 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avcodec/avCodecContext.h" +#include "avcodec/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +// Testing all AVCodecCtxstruct +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVCodecCtx) { + ASSERT_TRUE(AVCodecMod != nullptr); + + uint32_t AVCodecCtxPtr = UINT32_C(64); + + std::string FileName = "ffmpeg-assets/sample_video.mp4"; // 32 chars + initFFmpegStructs(UINT32_C(20), UINT32_C(24), UINT32_C(28), FileName, + UINT32_C(60), AVCodecCtxPtr, UINT32_C(68), UINT32_C(72)); + uint32_t NumPtr = UINT32_C(76); + uint32_t DenPtr = UINT32_C(80); + uint32_t AVCodecPtr = UINT32_C(84); + + uint32_t AVCodecCtxId = readUInt32(MemInst, AVCodecCtxPtr); + + auto *FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_codec_id"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxCodecID = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxCodecID &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxCodecID.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<uint32_t>(), 27); // H264 + } + + int32_t CodecType = 0; // MediaType Video + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_codec_type"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetCodecType = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetCodecType &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetCodecType.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, CodecType}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_codec_type"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxCodecType = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxCodecType &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxCodecType.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), CodecType); // MediaType Video + } + + int32_t Num = 5; + int32_t Den = 10; + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_time_base"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetTimebase = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetTimebase &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetTimebase.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, Num, Den}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_time_base"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxTimeBase = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxTimeBase &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxTimeBase.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, NumPtr, + DenPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + int32_t Numerator = readSInt32(MemInst, NumPtr); + int32_t Denominator = readSInt32(MemInst, DenPtr); + EXPECT_EQ(Numerator, Num); + EXPECT_EQ(Denominator, Den); + } + + int32_t Dimension = 200; + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_width"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetWidth = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetWidth &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetWidth.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, Dimension}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_width"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxWidth = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxWidth &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxWidth.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), Dimension); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_height"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetHeight = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetHeight &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetHeight.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, Dimension}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_height"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxHeight = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxHeight &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxHeight.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), Dimension); + } + + Num = 10; + Den = 20; + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_sample_aspect_ratio"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetSampleAspectRatio = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetSampleAspectRatio + &>(FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetSampleAspectRatio.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, Num, Den}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_sample_aspect_ratio"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSampleAspectRatio = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSampleAspectRatio &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSampleAspectRatio.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, NumPtr, + DenPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + int32_t Numerator = readSInt32(MemInst, NumPtr); + int32_t Denominator = readSInt32(MemInst, DenPtr); + EXPECT_EQ(Numerator, Num); + EXPECT_EQ(Denominator, Den); + } + + uint64_t ChannelLayoutId = 1; // FRONT_LEFT; + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_channel_layout"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetChannelLayout = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetChannelLayout &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetChannelLayout.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + ChannelLayoutId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_channel_layout"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxChannelLayout = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxChannelLayout &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxChannelLayout.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<uint64_t>(), ChannelLayoutId); + } + + uint32_t PixFormatId = 1; // YUV420P + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_pix_fmt"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetPixFormat = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetPixFormat &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetPixFormat.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, PixFormatId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_pix_fmt"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxPixFormat = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxPixFormat &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxPixFormat.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), PixFormatId); + } + + uint32_t SampleFmtId = 1; // SAMPLE_FMT_U8 + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_sample_format"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetSampleFormat = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetSampleFormat &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetSampleFormat.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, SampleFmtId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_sample_format"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSampleFormat = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSampleFormat &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSampleFormat.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), SampleFmtId); + } + + int32_t SampleRate = 500; + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_sample_rate"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetSampleRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetSampleRate &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetSampleRate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, SampleRate}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_sample_rate"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSampleRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSampleRate &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSampleRate.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), SampleRate); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_gop_size"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetGopSize = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetGopSize &>( + FuncInst->getHostFunc()); + + { + int32_t GopSize = 20; + EXPECT_TRUE(HostFuncAVCodecCtxSetGopSize.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, GopSize}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_max_b_frames"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetMaxBFrames = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetMaxBFrames &>( + FuncInst->getHostFunc()); + + { + int32_t MaxBFrames = 30; + EXPECT_TRUE(HostFuncAVCodecCtxSetMaxBFrames.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, MaxBFrames}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_b_quant_factor"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetBQuantFactor = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetBQuantFactor &>( + FuncInst->getHostFunc()); + + { + float BQuantFactor = 12.32; + EXPECT_TRUE(HostFuncAVCodecCtxSetBQuantFactor.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, BQuantFactor}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_b_quant_offset"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetBQuantOffset = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetBQuantOffset &>( + FuncInst->getHostFunc()); + + { + float BQuantOffset = 3.53; + EXPECT_TRUE(HostFuncAVCodecCtxSetBQuantOffset.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, BQuantOffset}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_i_quant_factor"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetIQuantFactor = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetIQuantFactor &>( + FuncInst->getHostFunc()); + + { + float IQuantFactor = 3.435; + EXPECT_TRUE(HostFuncAVCodecCtxSetIQuantFactor.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, IQuantFactor}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_i_quant_offset"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetIQuantOffset = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetIQuantOffset &>( + FuncInst->getHostFunc()); + + { + float IQuantOffset = 6.322; + EXPECT_TRUE(HostFuncAVCodecCtxSetIQuantOffset.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, IQuantOffset}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_lumi_masking"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetLumiMasking = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetLumiMasking &>( + FuncInst->getHostFunc()); + + { + float LumiMasking = 54.32432; + EXPECT_TRUE(HostFuncAVCodecCtxSetLumiMasking.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, LumiMasking}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_temporal_cplx_masking"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetTemporalCplxMasking = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetTemporalCplxMasking + &>(FuncInst->getHostFunc()); + + { + float TemporialCplxMasking = 642.32; + EXPECT_TRUE(HostFuncAVCodecCtxSetTemporalCplxMasking.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + TemporialCplxMasking}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_spatial_cplx_masking"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetSpatialCplxMasking = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetSpatialCplxMasking + &>(FuncInst->getHostFunc()); + + { + float SpatialCplxMasking = 324.32; + EXPECT_TRUE(HostFuncAVCodecCtxSetSpatialCplxMasking.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + SpatialCplxMasking}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_p_masking"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetPMasking = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetPMasking &>( + FuncInst->getHostFunc()); + + { + float PMasking = 65.3245; + EXPECT_TRUE(HostFuncAVCodecCtxSetPMasking.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, PMasking}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_dark_masking"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetDarkMasking = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetDarkMasking &>( + FuncInst->getHostFunc()); + + { + float DarkMasking = 83.32; + EXPECT_TRUE(HostFuncAVCodecCtxSetDarkMasking.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, DarkMasking}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_cmp"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetMeCmp = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetMeCmp &>( + FuncInst->getHostFunc()); + + { + int32_t MeCmp = 532; + EXPECT_TRUE(HostFuncAVCodecCtxSetMeCmp.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, MeCmp}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_sub_cmp"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetMeSubCmp = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetMeSubCmp &>( + FuncInst->getHostFunc()); + + { + int32_t MeSubCmp = 321; + EXPECT_TRUE(HostFuncAVCodecCtxSetMeSubCmp.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, MeSubCmp}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_mb_cmp"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetMbCmp = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetMbCmp &>( + FuncInst->getHostFunc()); + + { + int32_t MbCmp = 243; + EXPECT_TRUE(HostFuncAVCodecCtxSetMbCmp.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, MbCmp}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_ildct_cmp"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetIldctCmp = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetIldctCmp &>( + FuncInst->getHostFunc()); + + { + int32_t IldctCmp = 3; + EXPECT_TRUE(HostFuncAVCodecCtxSetIldctCmp.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, IldctCmp}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_dia_size"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetDiaSize = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetDiaSize &>( + FuncInst->getHostFunc()); + + { + int32_t DiaSize = 9; + EXPECT_TRUE(HostFuncAVCodecCtxSetDiaSize.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, DiaSize}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_last_predictor_count"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetLastPredictorsCount = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetLastPredictorsCount + &>(FuncInst->getHostFunc()); + + { + int32_t LastPredictorCount = 21; + EXPECT_TRUE(HostFuncAVCodecCtxSetLastPredictorsCount.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + LastPredictorCount}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_pre_cmp"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetMePreCmp = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetMePreCmp &>( + FuncInst->getHostFunc()); + + { + int32_t MePreCmp = 53; + EXPECT_TRUE(HostFuncAVCodecCtxSetMePreCmp.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, MePreCmp}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_pre_dia_size"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetPreDiaSize = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetPreDiaSize &>( + FuncInst->getHostFunc()); + + { + int32_t PreDiaSize = 74; + EXPECT_TRUE(HostFuncAVCodecCtxSetPreDiaSize.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, PreDiaSize}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_subpel_quality"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetMeSubpelQuality = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetMeSubpelQuality &>( + FuncInst->getHostFunc()); + + { + int32_t MeSubpelQuality = 85; + EXPECT_TRUE(HostFuncAVCodecCtxSetMeSubpelQuality.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + MeSubpelQuality}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_range"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetMeRange = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetMeRange &>( + FuncInst->getHostFunc()); + + { + int32_t SetMeRange = 31; + EXPECT_TRUE(HostFuncAVCodecCtxSetMeRange.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, SetMeRange}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_mb_decision"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetMbDecision = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetMbDecision &>( + FuncInst->getHostFunc()); + + { + int32_t MbDecision = 78; + EXPECT_TRUE(HostFuncAVCodecCtxSetMbDecision.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, MbDecision}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_mb_lmin"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetMbLMin = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetMbLMin &>( + FuncInst->getHostFunc()); + + { + int32_t MbLMin = 11; + EXPECT_TRUE(HostFuncAVCodecCtxSetMbLMin.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, MbLMin}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_mb_lmax"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetMbLMax = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetMbLMax &>( + FuncInst->getHostFunc()); + + { + int32_t MbLMax = 18; + EXPECT_TRUE(HostFuncAVCodecCtxSetMbLMax.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, MbLMax}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_intra_dc_precision"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + int32_t IntraDcPrecision = 323; + auto &HostFuncAVCodecCtxSetIntraDcPrecision = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetIntraDcPrecision &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetIntraDcPrecision.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + IntraDcPrecision}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_intra_dc_precision"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxIntraDcPrecision = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxIntraDcPrecision &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxIntraDcPrecision.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), IntraDcPrecision); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_qmin"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetQMin = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetQMin &>( + FuncInst->getHostFunc()); + + { + int32_t QMin = 10; + EXPECT_TRUE(HostFuncAVCodecCtxSetQMin.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, QMin}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_qmax"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetQMax = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetQMax &>( + FuncInst->getHostFunc()); + + { + int32_t QMax = 20; + EXPECT_TRUE(HostFuncAVCodecCtxSetQMax.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, QMax}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_global_quality"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetGlobalQuality = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetGlobalQuality &>( + FuncInst->getHostFunc()); + + { + int32_t GlobalQuality = 93; + EXPECT_TRUE(HostFuncAVCodecCtxSetGlobalQuality.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + GlobalQuality}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_colorspace"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetColorspace = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetColorspace &>( + FuncInst->getHostFunc()); + + int32_t ColorspaceId = 1; // AVCOL_SPC_BT709 + { + EXPECT_TRUE(HostFuncAVCodecCtxSetColorspace.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, ColorspaceId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_colorspace"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxColorspace = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxColorspace &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxColorspace.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), ColorspaceId); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_color_range"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetColorRange = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetColorRange &>( + FuncInst->getHostFunc()); + + int32_t ColorRangeId = 1; // MPEG + { + EXPECT_TRUE(HostFuncAVCodecCtxSetColorRange.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, ColorRangeId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_color_range"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxColorRange = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxColorRange &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxColorRange.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), ColorRangeId); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_frame_size"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxFrameSize = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxFrameSize &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxFrameSize.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_bit_rate"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetBitRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetBitRate &>( + FuncInst->getHostFunc()); + + int64_t BitRate = 9932; + { + EXPECT_TRUE(HostFuncAVCodecCtxSetBitRate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, BitRate}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_bit_rate"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxBitRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxBitRate &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxBitRate.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), BitRate); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_rc_max_rate"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + int64_t RcMaxRate = 3245; + auto &HostFuncAVCodecCtxSetRcMaxRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetRcMaxRate &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetRcMaxRate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, RcMaxRate}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_rc_max_rate"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxRcMaxRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxRcMaxRate &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxRcMaxRate.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), RcMaxRate); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_bit_rate_tolerance"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetBitRateTolerance = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetBitRateTolerance &>( + FuncInst->getHostFunc()); + + { + int32_t BitRateTolerance = 9543; + EXPECT_TRUE(HostFuncAVCodecCtxSetBitRateTolerance.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + BitRateTolerance}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_compression_level"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetCompressionLevel = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetCompressionLevel &>( + FuncInst->getHostFunc()); + + { + int32_t CompressionLevel = 934; + EXPECT_TRUE(HostFuncAVCodecCtxSetCompressionLevel.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + CompressionLevel}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_framerate"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + Num = 20; + Den = 30; + auto &HostFuncAVCodecCtxSetFrameRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetFrameRate &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetFrameRate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, Num, Den}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_framerate"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxFrameRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxFrameRate &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxFrameRate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, NumPtr, + DenPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + int32_t Numerator = readSInt32(MemInst, NumPtr); + int32_t Denominator = readSInt32(MemInst, DenPtr); + EXPECT_EQ(Numerator, Num); + EXPECT_EQ(Denominator, Den); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_flags"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetFlags = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetFlags &>( + FuncInst->getHostFunc()); + + { + int32_t Flags = 3; + EXPECT_TRUE(HostFuncAVCodecCtxSetFlags.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, Flags}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_strict_std_compliance"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetStrictStdCompliance = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetStrictStdCompliance + &>(FuncInst->getHostFunc()); + + { + int32_t ComplianceId = 3; + EXPECT_TRUE(HostFuncAVCodecCtxSetStrictStdCompliance.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, ComplianceId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_debug"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetDebug = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetDebug &>( + FuncInst->getHostFunc()); + + { + int32_t Debug = 50; + EXPECT_TRUE(HostFuncAVCodecCtxSetDebug.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, Debug}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_codec"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxCodec = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxCodec &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxCodec.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, AVCodecPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + ASSERT_TRUE(readUInt32(MemInst, AVCodecPtr) > 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_channels"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetChannels = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetChannels &>( + FuncInst->getHostFunc()); + + int32_t Channels = 10; + { + EXPECT_TRUE(HostFuncAVCodecCtxSetChannels.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, Channels}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_channels"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxChannels = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxChannels &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxChannels.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), Channels); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_loop_filter"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetSkipLoopFilter = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetSkipLoopFilter &>( + FuncInst->getHostFunc()); + + int32_t DiscardId = 16; // Bidirectional + { + EXPECT_TRUE(HostFuncAVCodecCtxSetSkipLoopFilter.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, DiscardId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_frame"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetSkipFrame = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetSkipFrame &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetSkipFrame.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, DiscardId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_idct"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetSkipIdct = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetSkipIdct &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetSkipIdct.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, DiscardId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_error_concealment"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetErrorConcealment = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetErrorConcealment &>( + FuncInst->getHostFunc()); + + { + int32_t ErrorConcealment = 99; + EXPECT_TRUE(HostFuncAVCodecCtxSetErrorConcealment.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + ErrorConcealment}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_err_recognition"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetErrorRecognition = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetErrorRecognition &>( + FuncInst->getHostFunc()); + + { + int32_t ErrorRecognition = 88; + EXPECT_TRUE(HostFuncAVCodecCtxSetErrorRecognition.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + ErrorRecognition}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_delay"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxDelay = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxDelay &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxDelay.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_top"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetSkipTop = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetSkipTop &>( + FuncInst->getHostFunc()); + + { + int32_t Value = 50; + EXPECT_TRUE(HostFuncAVCodecCtxSetSkipTop.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, Value}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_bottom"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetSkipBottom = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetSkipBottom &>( + FuncInst->getHostFunc()); + + { + int32_t Value = 60; + EXPECT_TRUE(HostFuncAVCodecCtxSetSkipBottom.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, Value}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_refs"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxRefs = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxRefs &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxRefs.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 4); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_slice_flags"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetSliceFlags = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetSliceFlags &>( + FuncInst->getHostFunc()); + + { + int32_t Value = 70; + EXPECT_TRUE(HostFuncAVCodecCtxSetSliceFlags.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, Value}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_slice_count"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetSliceCount = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetSliceCount &>( + FuncInst->getHostFunc()); + + { + int32_t Value = 100; + EXPECT_TRUE(HostFuncAVCodecCtxSetSliceCount.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, Value}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_field_order"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetFieldOrder = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetFieldOrder &>( + FuncInst->getHostFunc()); + + { + int32_t Value = 200; + EXPECT_TRUE(HostFuncAVCodecCtxSetFieldOrder.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, Value}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_color_trc"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxColorTrc = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxColorTrc &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxColorTrc.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() > 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_chroma_sample_location"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxChromaSampleLocation = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxChromaSampleLocation + &>(FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxChromaSampleLocation.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_frame_number"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxFrameNumber = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxFrameNumber &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxFrameNumber.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_block_align"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxBlockAlign = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxBlockAlign &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxBlockAlign.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_request_sample_fmt"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetRequestSampleFmt = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetRequestSampleFmt &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetRequestSampleFmt.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, SampleFmtId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_audio_service_type"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxAudioServiceType = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxAudioServiceType &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxAudioServiceType.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_has_b_frames"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxHasBFrames = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxHasBFrames &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxHasBFrames.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() > 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_request_channel_layout"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetRequestChannelLayout = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetRequestChannelLayout + &>(FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxSetRequestChannelLayout.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + ChannelLayoutId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_active_thread_type"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxActiveThreadType = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxActiveThreadType &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxActiveThreadType.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_thread_type"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetThreadType = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetThreadType &>( + FuncInst->getHostFunc()); + + { + int32_t ThreadType = 1; // Frame + EXPECT_TRUE(HostFuncAVCodecCtxSetThreadType.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, ThreadType}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_thread_count"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxSetThreadCount = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxSetThreadCount &>( + FuncInst->getHostFunc()); + + int32_t ThreadCount = 50; + { + EXPECT_TRUE(HostFuncAVCodecCtxSetThreadCount.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, ThreadCount}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_thread_count"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxThreadCount = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxThreadCount &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxThreadCount.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), ThreadCount); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_color_primaries"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxColorPrimaries = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxColorPrimaries &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxColorPrimaries.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() >= 0); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.cpp b/test/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.cpp new file mode 100644 index 000000000000..2bcfdfd4ee23 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.cpp @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avcodec/avCodecParameters.h" +#include "avcodec/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +// Testing all AVCodecstruct + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVCodecParameters) { + ASSERT_TRUE(AVCodecMod != nullptr); + + uint32_t AVCodecParamPtr = UINT32_C(60); + + std::string FileName = "ffmpeg-assets/sample_video.mp4"; // 32 chars + initFFmpegStructs(UINT32_C(20), UINT32_C(24), UINT32_C(28), FileName, + AVCodecParamPtr, UINT32_C(64), UINT32_C(68), UINT32_C(72)); + + uint32_t AVCodecParamId = readUInt32(MemInst, AVCodecParamPtr); + + auto *FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodecparam_codec_id"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecParamCodecId = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecParamCodecId &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecParamCodecId.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecParamId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 27); // H264 + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodecparam_codec_type"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecParamCodecType = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecParamCodecType &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecParamCodecType.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecParamId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); // MediaType Video + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodecparam_set_codec_tag"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecParamSetCodecTag = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecParamSetCodecTag &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecParamSetCodecTag.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecParamId, 20}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } +} +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avcodec/avPacket.cpp b/test/plugins/wasmedge_ffmpeg/avcodec/avPacket.cpp new file mode 100644 index 000000000000..fa163e49c6e1 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avcodec/avPacket.cpp @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avcodec/avPacket.h" +#include "avcodec/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +// Testing all AVPacket + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVPacketTest) { + ASSERT_TRUE(AVCodecMod != nullptr); + + uint32_t PacketPtr = UINT32_C(4); + uint32_t PacketPtr2 = UINT32_C(8); + uint32_t DataPtr = UINT32_C(12); + + auto *FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_alloc"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVPacketAlloc = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketAlloc &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketAlloc.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVPacketAlloc.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketPtr2}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + uint32_t PacketId = readUInt32(MemInst, PacketPtr); + uint32_t PacketId2 = readUInt32(MemInst, PacketPtr2); + ASSERT_TRUE(PacketId > 0); + ASSERT_TRUE(PacketId2 > 0); + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_new_packet"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVNewPacket = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVNewPacket &>( + FuncInst->getHostFunc()); + + { + uint32_t Size = 40; + EXPECT_TRUE(HostFuncAVNewPacket.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId, Size}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_grow_packet"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVGrowPacket = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVGrowPacket &>( + FuncInst->getHostFunc()); + + { + uint32_t Size = 40; + EXPECT_TRUE(HostFuncAVGrowPacket.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId, Size}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_shrink_packet"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVShrinkPacket = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVShrinkPacket &>( + FuncInst->getHostFunc()); + + { + uint32_t Size = 40; + EXPECT_TRUE(HostFuncAVShrinkPacket.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId, Size}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + uint32_t StreamIdx = 3; + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_av_packet_set_stream_index"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketSetStreamIndex = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketSetStreamIndex &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketSetStreamIndex.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{PacketId, StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_av_packet_stream_index"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketStreamIndex = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketStreamIndex &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketStreamIndex.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), StreamIdx); + } + + uint32_t Size = 0; + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_size"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketSize = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketSize &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketSize.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId}, + Result)); + Size = Result[0].get<int32_t>(); + EXPECT_TRUE(Size > 0); + } + + uint32_t Flags = 5; + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_av_packet_set_flags"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketSetFlags = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketSetFlags &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketSetFlags.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId, Flags}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_flags"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketFlags = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketFlags &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketFlags.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), Flags); + } + + int64_t Pos = 500; + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_set_pos"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketSetPos = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketSetPos &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketSetPos.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId, Pos}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_pos"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketPos = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketPos &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketPos.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId}, + Result)); + EXPECT_EQ(Result[0].get<int64_t>(), Pos); + } + + int64_t Duration = 100; + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_av_packet_set_duration"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketSetDuration = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketSetDuration &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketSetDuration.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{PacketId, Duration}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_duration"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketDuration = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketDuration &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketDuration.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId}, + Result)); + EXPECT_EQ(Result[0].get<int64_t>(), Duration); + } + + int64_t Dts = 1000; + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_set_dts"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketSetDts = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketSetDts &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketSetDts.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId, Dts}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_dts"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketDts = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketDts &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketDts.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId}, + Result)); + EXPECT_EQ(Result[0].get<int64_t>(), Dts); + } + + int64_t Pts = 5000; + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_set_pts"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketSetPts = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketSetPts &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketSetPts.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId, Pts}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_pts"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketPts = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketPts &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketPts.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId}, + Result)); + EXPECT_EQ(Result[0].get<int64_t>(), Pts); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_av_packet_is_data_null"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketIsDataNull = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketIsDataNull &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketIsDataNull.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_data"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketData = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketData &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketData.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{PacketId, DataPtr, Size}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_ref"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVPacketRef = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketRef &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketRef.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{PacketId2, PacketId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_unref"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVPacketUnref = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketUnref &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketUnref.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } +} +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avcodec/avcodec_func.cpp b/test/plugins/wasmedge_ffmpeg/avcodec/avcodec_func.cpp new file mode 100644 index 000000000000..e85bb7699286 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avcodec/avcodec_func.cpp @@ -0,0 +1,577 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avcodec/avcodec_func.h" +#include "avcodec/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +// TODO: Commented functions need to be tested. + +TEST_F(FFmpegTest, AVCodecFunc) { + ASSERT_TRUE(AVCodecMod != nullptr); + + uint32_t CodecCtxPtr = UINT32_C(4); + uint32_t CodecParamPtr = UINT32_C(8); + uint32_t CodecParamPtr2 = UINT32_C(20); + uint32_t CodecDecoderPtr = UINT32_C(12); + uint32_t CodecEncoderPtr = UINT32_C(16); + uint32_t StrPtr = UINT32_C(32); + + uint32_t CodecNamePtr = UINT32_C(150); + std::string CodecName = "mpeg1video"; + spdlog::info("Filling memory CodecName into CodecNamePtr"sv); + fillMemContent(MemInst, CodecNamePtr, CodecName); + + uint32_t ID = 1; + + auto *FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_alloc_context3"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecAllocContext3 = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecAllocContext3 &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AvCodecAllocContext3"sv); + { + EXPECT_TRUE(HostFuncAVCodecAllocContext3.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{0, CodecCtxPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + uint32_t AVCodecCtxId = readUInt32(MemInst, CodecCtxPtr); + ASSERT_TRUE(AVCodecCtxId > 0); + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_parameters_alloc"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecParametersAlloc = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecParametersAlloc &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecParametersAlloc"sv); + { + EXPECT_TRUE(HostFuncAVCodecParametersAlloc.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{CodecParamPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVCodecParametersAlloc.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{CodecParamPtr2}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + uint32_t AVCodecParamId = readUInt32(MemInst, CodecParamPtr); + ASSERT_TRUE(AVCodecParamId > 0); + + uint32_t AVCodecParamId2 = readUInt32(MemInst, CodecParamPtr2); + ASSERT_TRUE(AVCodecParamId2 > 0); + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_parameters_from_context"sv); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecParametersFromContext = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecParametersFromContext &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecParametersFromContext"sv); + { + EXPECT_TRUE(HostFuncAVCodecParametersFromContext.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecParamId, + AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_get_type"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecGetType = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecGetType &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecGetType"sv); + { + EXPECT_TRUE(HostFuncAVCodecGetType.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{ID}, Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); // Video Type + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_find_decoder"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecFindDecoder = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecFindDecoder &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecFindDecoder"sv); + { + EXPECT_TRUE(HostFuncAVCodecFindDecoder.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ID, CodecDecoderPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + uint32_t AVCodecDecoderId = readUInt32(MemInst, CodecDecoderPtr); + ASSERT_TRUE(AVCodecDecoderId > 0); + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_find_encoder"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecFindEncoder = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecFindEncoder &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecFindEncoder"sv); + { + EXPECT_TRUE(HostFuncAVCodecFindEncoder.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ID, CodecEncoderPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + uint32_t AVCodecEncoderId = readUInt32(MemInst, CodecEncoderPtr); + ASSERT_TRUE(AVCodecEncoderId > 0); + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_open2"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecOpen2 = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecOpen2 &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecOpen2"sv); + // Invalid argument passed. Return -22 Error code. Means functionality + // working. + { + EXPECT_TRUE( + HostFuncAVCodecOpen2.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + AVCodecCtxId, AVCodecEncoderId, 0}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), -22); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_av_codec_is_encoder"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecIsEncoder = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecIsEncoder &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecIsEncoder"sv); + { + EXPECT_TRUE(HostFuncAVCodecIsEncoder.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecEncoderId}, Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_av_codec_is_decoder"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecIsDecoder = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecIsDecoder &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecIsDecoder"sv); + { + EXPECT_TRUE(HostFuncAVCodecIsDecoder.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecDecoderId}, Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_find_decoder_by_name"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecFindDecoderByName = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecFindDecoderByName &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecFindDecoderByName"sv); + { + uint32_t Length = CodecName.length(); + EXPECT_TRUE(HostFuncAVCodecFindDecoderByName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{CodecDecoderPtr, + CodecNamePtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_find_encoder_by_name"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecFindEncoderByName = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecFindEncoderByName &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecFindEncoderByName"sv); + { + uint32_t Length = CodecName.length(); + EXPECT_TRUE(HostFuncAVCodecFindEncoderByName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{CodecEncoderPtr, + CodecNamePtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_parameters_to_context"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecParametersToContext = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecParametersToContext &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecParametersToContext"sv); + { + EXPECT_TRUE(HostFuncAVCodecParametersToContext.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + AVCodecParamId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + // TODO: Need FormatCtxId To test this func. + // FuncInst = AVCodecMod->findFuncExports( + // "wasmedge_ffmpeg_avcodec_avcodec_parameters_copy"); + // EXPECT_NE(FuncInst, nullptr); + // EXPECT_TRUE(FuncInst->isHostFunction()); + // + // auto &HostFuncAVCodecParametersCopy = dynamic_cast< + // WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecParametersCopy &>( + // FuncInst->getHostFunc()); + // + // { + // EXPECT_TRUE(HostFuncAVCodecParametersCopy.run( + // CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + // EXPECT_EQ(Result[0].get<int32_t>(), + // static_cast<int32_t>(ErrNo::Success)); + // } + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_version"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecVersion = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecVersion &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecVersion"sv); + { + EXPECT_TRUE(HostFuncAVCodecVersion.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + EXPECT_TRUE(Result[0].get<int32_t>() > 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_configuration_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecConfigurationLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecConfigurationLength &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecConfigurationLength"sv); + int32_t Length = 0; + { + EXPECT_TRUE(HostFuncAVCodecConfigurationLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_configuration"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecConfiguration = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecConfiguration &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecConfiguration"sv); + { + EXPECT_TRUE(HostFuncAVCodecConfiguration.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_license_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecLicenseLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecLicenseLength &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecLicenseLength"sv); + { + EXPECT_TRUE(HostFuncAVCodecLicenseLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_license"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecLicense = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecLicense &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecLicense"sv); + { + EXPECT_TRUE(HostFuncAVCodecLicense.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_free_context"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecFreeContext = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecFreeContext &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecFreeContext"sv); + { + EXPECT_TRUE(HostFuncAVCodecFreeContext.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_parameters_free"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecParametersFree = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecParametersFree &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecParametersFree"sv); + { + EXPECT_TRUE(HostFuncAVCodecParametersFree.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecParamId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } +} + +TEST_F(FFmpegTest, SendPacketReceiveFrame) { + std::string FileName = "ffmpeg-assets/dummy.mp4"; // 32 chars + uint32_t CodecCtxPtr = UINT32_C(64); + uint32_t FramePtr = UINT32_C(72); + uint32_t PacketPtr = UINT32_C(68); + initFFmpegStructs(UINT32_C(20), UINT32_C(24), UINT32_C(28), FileName, + UINT32_C(60), CodecCtxPtr, PacketPtr, FramePtr); + + uint32_t FrameId = readUInt32(MemInst, FramePtr); + uint32_t PacketId = readUInt32(MemInst, PacketPtr); + uint32_t CodecCtxId = readUInt32(MemInst, CodecCtxPtr); + + auto *FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_send_frame"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecSendFrame = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecSendFrame &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecSendFrame"sv); + // Invalid Argument Error. Should Use Encoder, I'm using decoder + // Aim is to test the functionality. + { + EXPECT_TRUE(HostFuncAVCodecSendFrame.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{CodecCtxId, FrameId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), -22); + } + + // Invalid Argument Error. Should Use Encoder, I'm using decoder + // Aim is to test the functionality. + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_receive_packet"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecReceivePacket = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecReceivePacket &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecReceivePacket"sv); + { + EXPECT_TRUE(HostFuncAVCodecReceivePacket.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{CodecCtxId, PacketId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), -22); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_send_packet"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecSendPacket = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecSendPacket &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecSendPacket"sv); + // Send packet to Decoder. + { + EXPECT_TRUE(HostFuncAVCodecSendPacket.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{CodecCtxId, PacketId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_receive_frame"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + // Decoder Receives the Packet as Frame. + auto &HostFuncAVCodecReceiveFrame = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecReceiveFrame &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecReceiveFrame"sv); + { + EXPECT_TRUE(HostFuncAVCodecReceiveFrame.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{CodecCtxId, FrameId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_av_packet_rescale_ts"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVPacketRescaleTs = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketRescaleTs &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVPacketRescaleTs"sv); + { + int32_t SrcNum = 2; + int32_t SrcDen = 3; + int32_t DestNum = 5; + int32_t DestDen = 9; + EXPECT_TRUE(HostFuncAVPacketRescaleTs.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{PacketId, SrcNum, SrcDen, + DestNum, DestDen}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_av_packet_make_writable"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVPacketMakeWritable = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketMakeWritable &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVPacketMakeWritable"sv); + { + EXPECT_TRUE(HostFuncAVPacketMakeWritable.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_flush_buffers"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecFlushBuffers = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecFlushBuffers &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecFlushBuffers"sv); + { + EXPECT_TRUE(HostFuncAVCodecFlushBuffers.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{CodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_close"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecClose = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecClose &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecClose"sv); + { + EXPECT_TRUE(HostFuncAVCodecClose.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{CodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avfilter/avfilter.cpp b/test/plugins/wasmedge_ffmpeg/avfilter/avfilter.cpp new file mode 100644 index 000000000000..c96448a2e500 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avfilter/avfilter.cpp @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avfilter/avFilter.h" +#include "avfilter//avfilter_func.h" +#include "avfilter/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVFilterStructs) { + ASSERT_TRUE(AVFilterMod != nullptr); + + uint32_t FilterPtr = UINT32_C(8); + uint32_t InputFilterPadPtr = UINT32_C(12); + uint32_t OutputFilterPadPtr = UINT32_C(16); + uint32_t InputNamePtr = UINT32_C(100); + uint32_t StrPtr = UINT32_C(150); + + std::string InputName = std::string("abuffer"); + fillMemContent(MemInst, InputNamePtr, InputName); + + // ================================================================== + // Start Initialize AVFilter + // ================================================================== + + auto *FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_get_by_name"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterGetByName = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterGetByName &>( + FuncInst->getHostFunc()); + + { + int32_t Length = InputName.length(); + EXPECT_TRUE(HostFuncAVFilterGetByName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FilterPtr, InputNamePtr, + Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + uint32_t FilterId = readUInt32(MemInst, FilterPtr); + ASSERT_TRUE(FilterId > 0); + // ================================================================== + // End Initialize AVFilter + // ================================================================== + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_name_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterNameLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterNameLength &>( + FuncInst->getHostFunc()); + + int32_t Length = 0; + { + EXPECT_TRUE(HostFuncAVFilterNameLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FilterId}, + Result)); + Length = Result[0].get<int32_t>(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = + AVFilterMod->findFuncExports("wasmedge_ffmpeg_avfilter_avfilter_name"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterName = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterName &>( + FuncInst->getHostFunc()); + + fillMemContent(MemInst, StrPtr, Length); + { + EXPECT_TRUE(HostFuncAVFilterName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FilterId, StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_description_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterDescriptionLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterDescriptionLength &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterDescriptionLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FilterId}, + Result)); + + Length = Result[0].get<int32_t>(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_description"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterDescription = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterDescription &>( + FuncInst->getHostFunc()); + + fillMemContent(MemInst, StrPtr, Length); + { + EXPECT_TRUE(HostFuncAVFilterDescription.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FilterId, StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_nb_inputs"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterNbInputs = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterNbInputs &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterNbInputs.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FilterId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_nb_outputs"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterNbOutputs = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterNbOutputs &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterNbOutputs.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FilterId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = + AVFilterMod->findFuncExports("wasmedge_ffmpeg_avfilter_avfilter_flags"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterFlags = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterFlags &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterFlags.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FilterId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_get_inputs_filter_pad"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterGetInputsFilterPad = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterGetInputsFilterPad &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterGetInputsFilterPad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FilterId, + InputFilterPadPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_get_outputs_filter_pad"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterGetOutputsFilterPad = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterGetOutputsFilterPad &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterGetOutputsFilterPad.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FilterId, + OutputFilterPadPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + uint32_t OutputFilterPadId = readUInt32(MemInst, OutputFilterPadPtr); + ASSERT_TRUE(OutputFilterPadId > 0); + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_pad_get_name_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterPadGetNameLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterPadGetNameLength &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterPadGetNameLength.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{OutputFilterPadId, 0}, + Result)); + Length = Result[0].get<int32_t>(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_pad_get_name"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterPadGetName = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterPadGetName &>( + FuncInst->getHostFunc()); + + { + int32_t Idx = 0; + EXPECT_TRUE(HostFuncAVFilterPadGetName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{OutputFilterPadId, Idx, + StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_pad_get_type"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterPadGetType = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterPadGetType &>( + FuncInst->getHostFunc()); + + { + int32_t Idx = 0; + EXPECT_TRUE(HostFuncAVFilterPadGetType.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{OutputFilterPadId, Idx}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 1); // Audio + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_pad_drop"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterPadDrop = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterPadDrop &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterPadDrop.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{OutputFilterPadId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avfilter/avfilter_func.cpp b/test/plugins/wasmedge_ffmpeg/avfilter/avfilter_func.cpp new file mode 100644 index 000000000000..1e50b4014358 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avfilter/avfilter_func.cpp @@ -0,0 +1,685 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avfilter//avfilter_func.h" +#include "avfilter/avFilter.h" +#include "avfilter/buffer_source_sink.h" +#include "avfilter/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVFilterFunc) { + ASSERT_TRUE(AVFilterMod != nullptr); + + // Structs Ptr + uint32_t FilterGraphPtr = UINT32_C(4); + uint32_t FilterPtr = UINT32_C(8); + uint32_t Filter2Ptr = UINT32_C(12); + uint32_t InputFilterCtxPtr = UINT32_C(28); // AVFilterContext + uint32_t OutputFilterCtxPtr = UINT32_C(24); // AVFilterContext + uint32_t InputInOutPtr = UINT32_C(32); + uint32_t OutputInOutPtr = UINT32_C(36); + uint32_t FramePtr = UINT32_C(40); + + // Strings. + uint32_t InputNamePtr = UINT32_C(100); + uint32_t OutputNamePtr = UINT32_C(150); + uint32_t InputFilterNamePtr = UINT32_C(200); + uint32_t OutputFilterNamePtr = UINT32_C(250); + uint32_t ArgsPtr = UINT32_C(300); + uint32_t SpecPtr = UINT32_C(450); + uint32_t StrPtr = UINT32_C(500); + + std::string InputName = std::string("abuffer"); + fillMemContent(MemInst, InputNamePtr, InputName); + + std::string OutputName = std::string("abuffersink"); + fillMemContent(MemInst, OutputNamePtr, OutputName); + + std::string InputFilterName = std::string("in"); + fillMemContent(MemInst, InputFilterNamePtr, InputFilterName); + + std::string OutputFilterName = std::string("out"); + fillMemContent(MemInst, OutputFilterNamePtr, OutputFilterName); + + std::string Args = std::string( + "time_base=1/44100:sample_rate=44100:sample_fmt=fltp:channel_layout=0x3"); + fillMemContent(MemInst, ArgsPtr, Args); + + std::string SpecStr = std::string("anull"); + fillMemContent(MemInst, SpecPtr, SpecStr); + + initEmptyFrame(FramePtr); + uint32_t FrameId = readUInt32(MemInst, FramePtr); + + auto *FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_graph_alloc"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterGraphAlloc = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterGraphAlloc &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterGraphAlloc.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FilterGraphPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + uint32_t FilterGraphId = readUInt32(MemInst, FilterGraphPtr); + ASSERT_TRUE(FilterGraphId > 0); + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_get_by_name"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterGetByName = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterGetByName &>( + FuncInst->getHostFunc()); + + { + int32_t Length = InputName.length(); + EXPECT_TRUE(HostFuncAVFilterGetByName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FilterPtr, InputNamePtr, + Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + Length = OutputName.length(); + EXPECT_TRUE(HostFuncAVFilterGetByName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{Filter2Ptr, OutputNamePtr, + Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + uint32_t FilterId = readUInt32(MemInst, FilterPtr); + uint32_t Filter2Id = readUInt32(MemInst, Filter2Ptr); + ASSERT_TRUE(FilterId > 0); + ASSERT_TRUE(Filter2Id > 0); + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_graph_create_filter"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterGraphCreateFilter = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterGraphCreateFilter &>( + FuncInst->getHostFunc()); + + { + int32_t NameLen = InputFilterName.length(); + int32_t ArgsLen = Args.length(); + EXPECT_TRUE(HostFuncAVFilterGraphCreateFilter.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + InputFilterCtxPtr, FilterId, InputFilterNamePtr, NameLen, ArgsPtr, + ArgsLen, FilterGraphId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() >= 0); + writeUInt32(MemInst, 0, InputFilterCtxPtr); // Setting InputFilterCtx to 0 + + NameLen = OutputFilterName.length(); + EXPECT_TRUE(HostFuncAVFilterGraphCreateFilter.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + OutputFilterCtxPtr, Filter2Id, OutputFilterNamePtr, NameLen, 0, 0, + FilterGraphId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() >= 0); + writeUInt32(MemInst, 0, OutputFilterCtxPtr); // Setting OutputFilterCtx to 0 + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_inout_alloc"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterInOutAlloc = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterInOutAlloc &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterInOutAlloc.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{InputInOutPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVFilterInOutAlloc.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{OutputInOutPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + uint32_t InputInOutId = readUInt32(MemInst, InputInOutPtr); + ASSERT_TRUE(InputInOutId > 0); + + uint32_t OutputInOutId = readUInt32(MemInst, OutputInOutPtr); + ASSERT_TRUE(OutputInOutId > 0); + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_graph_get_filter"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterGraphGetFilter = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterGraphGetFilter &>( + FuncInst->getHostFunc()); + + { + int32_t Length = OutputFilterName.length(); + EXPECT_TRUE(HostFuncAVFilterGraphGetFilter.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + OutputFilterCtxPtr, FilterGraphId, OutputFilterNamePtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + Length = InputFilterName.length(); + EXPECT_TRUE(HostFuncAVFilterGraphGetFilter.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + InputFilterCtxPtr, FilterGraphId, InputFilterNamePtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + uint32_t OutputFilterCtxId = readUInt32(MemInst, OutputFilterCtxPtr); + ASSERT_TRUE(OutputFilterCtxId > 0); + + uint32_t InputFilterCtxId = readUInt32(MemInst, InputFilterCtxPtr); + ASSERT_TRUE(InputFilterCtxId > 0); + + // ================================================================== + // Setting InOutId Values for Filtering + // ================================================================== + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_inout_set_name"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterInOutSetName = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterInOutSetName &>( + FuncInst->getHostFunc()); + + { + int32_t Length = InputFilterName.length(); + EXPECT_TRUE(HostFuncAVFilterInOutSetName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{OutputInOutId, + InputFilterNamePtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + Length = OutputFilterName.length(); + EXPECT_TRUE(HostFuncAVFilterInOutSetName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + InputInOutId, OutputFilterNamePtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_inout_set_filter_ctx"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterInOutSetFilterCtx = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterInOutSetFilterCtx &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterInOutSetFilterCtx.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{OutputInOutId, + InputFilterCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVFilterInOutSetFilterCtx.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{InputInOutId, + OutputFilterCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_inout_set_pad_idx"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterInOutSetPadIdx = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterInOutSetPadIdx &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterInOutSetPadIdx.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{OutputInOutId, 0}, Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVFilterInOutSetPadIdx.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{InputInOutId, 0}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_inout_set_next"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterInOutSetNext = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterInOutSetNext &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterInOutSetNext.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{OutputInOutId, 0}, Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVFilterInOutSetNext.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{InputInOutId, 0}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + // ================================================================== + // End Setting InOutId Values for Filtering + // ================================================================== + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_graph_parse_ptr"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterGraphParsePtr = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterGraphParsePtr &>( + FuncInst->getHostFunc()); + + { + int32_t Length = SpecStr.length(); + EXPECT_TRUE(HostFuncAVFilterGraphParsePtr.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + FilterGraphId, SpecPtr, Length, InputInOutId, OutputInOutId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_graph_config"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterGraphConfig = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterGraphConfig &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterGraphConfig.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FilterGraphId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_graph_dump_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterGraphDumpLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterGraphDumpLength &>( + FuncInst->getHostFunc()); + + int32_t GraphStrLen = 0; + { + EXPECT_TRUE(HostFuncAVFilterGraphDumpLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FilterGraphId}, + Result)); + GraphStrLen = Result[0].get<int32_t>(); + ASSERT_TRUE(GraphStrLen > 0); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_graph_dump"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterGraphDump = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterGraphDump &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterGraphDump.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FilterGraphId, StrPtr, + GraphStrLen}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + // Crashing the program. Checked even from Rust side. + + // FuncInst = AVFilterMod->findFuncExports( + // "wasmedge_ffmpeg_avfilter_avfilter_inout_free"); + // EXPECT_NE(FuncInst, nullptr); + // EXPECT_TRUE(FuncInst->isHostFunction()); + // + // auto &HostFuncAVFilterInOutFree = dynamic_cast< + // WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterInOutFree &>( + // FuncInst->getHostFunc()); + // + // { + // EXPECT_TRUE(HostFuncAVFilterInOutFree.run( + // CallFrame, + // std::initializer_list<WasmEdge::ValVariant>{InputInOutId}, Result)); + // EXPECT_EQ(Result[0].get<int32_t>(), + // static_cast<int32_t>(ErrNo::Success)); + // + // EXPECT_TRUE(HostFuncAVFilterInOutFree.run( + // CallFrame, + // std::initializer_list<WasmEdge::ValVariant>{OutputInOutId}, + // Result)); + // EXPECT_EQ(Result[0].get<int32_t>(), + // static_cast<int32_t>(ErrNo::Success)); + // } + + FuncInst = + AVFilterMod->findFuncExports("wasmedge_ffmpeg_avfilter_avfilter_version"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterVersion = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterVersion &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterVersion.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + ASSERT_TRUE(Result[0].get<int32_t>() > 0); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_configuration_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterConfigurationLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterConfigurationLength &>( + FuncInst->getHostFunc()); + + int32_t Length = 0; + { + EXPECT_TRUE(HostFuncAVFilterConfigurationLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + Length = Result[0].get<int32_t>(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_configuration"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterConfiguration = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterConfiguration &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterConfiguration.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_license_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterLicenseLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterLicenseLength &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterLicenseLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + Length = Result[0].get<int32_t>(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = + AVFilterMod->findFuncExports("wasmedge_ffmpeg_avfilter_avfilter_license"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterLicense = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterLicense &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterLicense.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + // ================================================================== + // Start Test AVBufferSource, AVBufferSink Funcs + // ================================================================== + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_av_buffersrc_get_nb_failed_requests"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVBufferSrcGetNbFailedRequests = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVBufferSrcGetNbFailedRequests + &>(FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVBufferSrcGetNbFailedRequests.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{InputFilterCtxId}, Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_av_buffersrc_add_frame"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVBufferSrcAddFrame = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVBufferSrcAddFrame &>( + FuncInst->getHostFunc()); + + // Returning Error Code -22 (Invalid Argument), Due to Passing Empty Frame. + { + EXPECT_TRUE(HostFuncAVBufferSrcAddFrame.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{InputFilterCtxId, FrameId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>()); + } + + // Need to send the last frame. Then only this test will pass. Else Null + // pointer exception. + // FuncInst = AVFilterMod->findFuncExports( + // "wasmedge_ffmpeg_avfilter_av_buffersrc_close"); + // EXPECT_NE(FuncInst, nullptr); + // EXPECT_TRUE(FuncInst->isHostFunction()); + // + // auto &HostFuncAVBufferSrcClose = dynamic_cast< + // WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVBufferSrcClose &>( + // FuncInst->getHostFunc()); + // + // { + // int64_t Pts = 20; + // uint32_t Flags = 30; + // EXPECT_TRUE(HostFuncAVBufferSrcClose.run( + // CallFrame, + // std::initializer_list<WasmEdge::ValVariant>{InputFilterCtxPtr, Pts, + // Flags}, + // Result)); + // EXPECT_EQ(Result[0].get<int32_t>(), + // static_cast<int32_t>(ErrNo::Success)); + // } + + // Passing Empty frames. Return AVERROR due to no frames presen Return AVERROR + // due to no frames present. + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_av_buffersink_get_frame"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVBufferSinkGetFrame = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVBufferSinkGetFrame &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVBufferSinkGetFrame.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{OutputFilterCtxId, FrameId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>()); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_av_buffersink_get_samples"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVBufferSinkGetSamples = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVBufferSinkGetSamples &>( + FuncInst->getHostFunc()); + + // Passing Empty frames. Return AVERROR due to no frames presen Return AVERROR + // due to no frames present. + { + EXPECT_TRUE(HostFuncAVBufferSinkGetSamples.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{OutputFilterCtxId, FrameId, + 20}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>()); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_av_buffersink_set_frame_size"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAvBufferSinkSetFrameSize = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AvBufferSinkSetFrameSize &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAvBufferSinkSetFrameSize.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{OutputFilterCtxId, 30}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + // ================================================================== + // End Test AVBufferSource, AVBufferSink Funcs + // ================================================================== + + // ================================================================== + // Clean Memory + // ================================================================== + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_free_graph_str"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterFreeGraphStr = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterFreeGraphStr &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterFreeGraphStr.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FilterGraphId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVFilterMod->findFuncExports("wasmedge_ffmpeg_avfilter_avfilter_drop"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterDrop = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterDrop &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterDrop.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FilterId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_context_drop"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterContextDrop = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterContextDrop &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterContextDrop.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{InputFilterCtxId}, Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVFilterContextDrop.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{OutputFilterCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_graph_free"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterGraphFree = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::AVFilterGraphFree &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterGraphFree.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FilterGraphId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + // ================================================================== + // End Clean Memory + // ================================================================== +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avformat/avChapter.cpp b/test/plugins/wasmedge_ffmpeg/avformat/avChapter.cpp new file mode 100644 index 000000000000..299d26f94c42 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avformat/avChapter.cpp @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avformat/avChapter.h" +#include "avformat/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +// Sample Video under test has only Single Chapter. +TEST_F(FFmpegTest, AVChapter) { + ASSERT_TRUE(AVFormatMod != nullptr); + + uint32_t ChapterIdx = 0; + + uint32_t FormatCtxPtr = UINT32_C(4); + uint32_t NumPtr = UINT32_C(12); + uint32_t DenPtr = UINT32_C(16); + uint32_t DictionaryPtr = UINT32_C(20); + uint32_t FilePtr = UINT32_C(100); + + std::string FileName = "ffmpeg-assets/sample_video.mp4"; // 32 chars + initFormatCtx(FormatCtxPtr, FilePtr, FileName); + uint32_t FormatCtxId = readUInt32(MemInst, FormatCtxPtr); + + auto *FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avChapter_id"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVChapterId = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVChapterId &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVChapterId.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, ChapterIdx}, + Result)); + EXPECT_TRUE(Result[0].get<int64_t>() >= 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avChapter_timebase"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVChapterTimebase = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVChapterTimebase &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVChapterTimebase.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{NumPtr, DenPtr, FormatCtxId, + ChapterIdx}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + EXPECT_EQ(readSInt32(MemInst, NumPtr), 1); + EXPECT_TRUE(readSInt32(MemInst, DenPtr) >= 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avChapter_start"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVChapterStart = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVChapterStart &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVChapterStart.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, ChapterIdx}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avChapter_end"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVChapterEnd = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVChapterEnd &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVChapterEnd.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, ChapterIdx}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avChapter_metadata"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVChapterMetadata = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVChapterMetadata &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVChapterMetadata.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, ChapterIdx, + DictionaryPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + EXPECT_TRUE(readUInt32(MemInst, DictionaryPtr) > 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avChapter_set_id"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVChapterSetId = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVChapterSetId &>( + FuncInst->getHostFunc()); + + { + int64_t ChapterId = 10000; + EXPECT_TRUE( + HostFuncAVChapterSetId.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + FormatCtxId, ChapterIdx, ChapterId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + // Verify Set Data + EXPECT_TRUE(HostFuncAVChapterId.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, ChapterIdx}, + Result)); + EXPECT_EQ(Result[0].get<int64_t>(), ChapterId); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avChapter_set_timebase"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVChapterSetTimebase = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVChapterSetTimebase &>( + FuncInst->getHostFunc()); + + { + int32_t Num = 3; + int32_t Den = 4; + EXPECT_TRUE(HostFuncAVChapterSetTimebase.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{Num, Den, FormatCtxId, + ChapterIdx}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + // Verify Set Data + EXPECT_TRUE(HostFuncAVChapterTimebase.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{NumPtr, DenPtr, FormatCtxId, + ChapterIdx}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + EXPECT_EQ(readSInt32(MemInst, NumPtr), Num); + EXPECT_EQ(readSInt32(MemInst, DenPtr), Den); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avChapter_set_start"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVChapterSetStart = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVChapterSetStart &>( + FuncInst->getHostFunc()); + + { + int64_t StartValue = 1000; + EXPECT_TRUE(HostFuncAVChapterSetStart.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, ChapterIdx, + StartValue}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + // Verify Set Data + EXPECT_TRUE(HostFuncAVChapterStart.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, ChapterIdx}, + Result)); + EXPECT_EQ(Result[0].get<int64_t>(), StartValue); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avChapter_set_end"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVChapterSetEnd = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVChapterSetEnd &>( + FuncInst->getHostFunc()); + + { + int64_t EndValue = 99999; + EXPECT_TRUE( + HostFuncAVChapterSetEnd.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + FormatCtxId, ChapterIdx, EndValue}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + // Verify Set Data + EXPECT_TRUE(HostFuncAVChapterEnd.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, ChapterIdx}, + Result)); + EXPECT_EQ(Result[0].get<int64_t>(), EndValue); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avformat/avInputOutputContext.cpp b/test/plugins/wasmedge_ffmpeg/avformat/avInputOutputContext.cpp new file mode 100644 index 000000000000..99a1fcbec66e --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avformat/avInputOutputContext.cpp @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avformat/avInputOutputFormat.h" +#include "avformat/avformatContext.h" +#include "avformat/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVInputFormat) { + std::string FileName = "ffmpeg-assets/sample_video.mp4"; // 32 chars + uint32_t FormatCtxPtr = UINT32_C(24); + uint32_t InputFormatPtr = UINT32_C(28); + + uint32_t StrBuf = UINT32_C(100); + initFFmpegStructs(UINT32_C(20), FormatCtxPtr, UINT32_C(28), FileName, + UINT32_C(60), UINT32_C(64), UINT32_C(68), UINT32_C(72)); + + uint32_t FormatCtxId = readUInt32(MemInst, FormatCtxPtr); + + // ==================================================================== + // Initialize AVInputFormat + // ==================================================================== + + auto *FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformatContext_iformat"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatCtxIFormat = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatCtxIFormat &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFormatCtxIFormat.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, + InputFormatPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + EXPECT_TRUE(readUInt32(MemInst, InputFormatPtr) > 0); + } + uint32_t InputFormatId = readUInt32(MemInst, InputFormatPtr); + + // ==================================================================== + // End Initialize AVInputFormat + // ==================================================================== + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avIOFormat_name_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVIOFormatNameLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVIOFormatNameLength &>( + FuncInst->getHostFunc()); + + int32_t Length = 0; + { + EXPECT_TRUE(HostFuncAVIOFormatNameLength.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{InputFormatId, 0}, Result)); + Length = Result[0].get<int32_t>(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avInputFormat_name"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVInputFormatName = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVInputFormatName &>( + FuncInst->getHostFunc()); + + fillMemContent(MemInst, StrBuf, Length); + { + EXPECT_TRUE(HostFuncAVInputFormatName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{InputFormatId, StrBuf, + Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avIOFormat_long_name_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVIOFormatLongNameLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVIOFormatLongNameLength &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVIOFormatLongNameLength.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{InputFormatId, 0}, Result)); + + Length = Result[0].get<int32_t>(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avInputFormat_long_name"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVInputFormatLongName = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVInputFormatLongName &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVInputFormatLongName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{InputFormatId, StrBuf, + Length}, + Result)); + + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avIOFormat_extensions_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVIOFormatExtensionsLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVIOFormatExtensionsLength &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVIOFormatExtensionsLength.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{InputFormatId, 0}, Result)); + + Length = Result[0].get<int32_t>(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avInputFormat_extensions"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVInputFormatExtensions = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVInputFormatExtensions &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVInputFormatExtensions.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{InputFormatId, StrBuf, + Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avIOFormat_mime_type_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVIOFormatMimeTypeLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVIOFormatMimeTypeLength &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVIOFormatMimeTypeLength.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{InputFormatId, 0}, Result)); + + Length = Result[0].get<int32_t>(); + ASSERT_TRUE(Length >= 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avInputFormat_mime_type"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVInputFormatMimeType = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVInputFormatMimeType &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVInputFormatMimeType.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{InputFormatId, StrBuf, + Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avInputOutputFormat_free"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVInputOutputFormatFree = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVInputOutputFormatFree &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVInputOutputFormatFree.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{InputFormatId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avformat/avStream.cpp b/test/plugins/wasmedge_ffmpeg/avformat/avStream.cpp new file mode 100644 index 000000000000..0cc0655be496 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avformat/avStream.cpp @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avformat/avStream.h" +#include "avformat/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +// Testing all AVFormat_funcs. +TEST_F(FFmpegTest, AVStreamStruct) { + ASSERT_TRUE(AVFormatMod != nullptr); + + uint32_t StreamIdx = 0; + + uint32_t FormatCtxPtr = UINT32_C(4); + uint32_t CodecParameterPtr = UINT32_C(8); + uint32_t NumPtr = UINT32_C(12); + uint32_t DenPtr = UINT32_C(16); + uint32_t DictPtr = UINT32_C(20); + uint32_t FilePtr = UINT32_C(100); + + std::string FileName = "ffmpeg-assets/sample_video.mp4"; // 32 chars + initFormatCtx(FormatCtxPtr, FilePtr, FileName); + uint32_t FormatCtxId = readUInt32(MemInst, FormatCtxPtr); + + auto *FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avStream_id"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamId = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamId &>( + FuncInst->getHostFunc()); + + uint32_t AvFormatCtxId = readUInt32(MemInst, FormatCtxPtr); + { + EXPECT_TRUE(HostFuncAVStreamId.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AvFormatCtxId, StreamIdx}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avStream_index"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamIndex = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamIndex &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVStreamIndex.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, StreamIdx}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_codecpar"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamCodecPar = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamCodecPar &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVStreamCodecPar.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, StreamIdx, + CodecParameterPtr}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + ASSERT_TRUE(readUInt32(MemInst, CodecParameterPtr) > 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_timebase"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamTimebase = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamTimebase &>( + FuncInst->getHostFunc()); + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_set_timebase"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamSetTimebase = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamSetTimebase &>( + FuncInst->getHostFunc()); + + { + int32_t Num = 3; + int32_t Den = 4; + EXPECT_TRUE(HostFuncAVStreamSetTimebase.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{Num, Den, FormatCtxId, + StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVStreamTimebase.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{NumPtr, DenPtr, FormatCtxId, + StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + EXPECT_EQ(readUInt32(MemInst, NumPtr), Num); + EXPECT_EQ(readUInt32(MemInst, DenPtr), Den); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_duration"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamDuration = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamDuration &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVStreamDuration.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, StreamIdx}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_start_time"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamStartTime = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamStartTime &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVStreamStartTime.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, StreamIdx}, + Result)); + EXPECT_TRUE(Result[0].get<int64_t>() >= 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_nb_frames"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamNbFrames = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamNbFrames &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVStreamNbFrames.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, StreamIdx}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_disposition"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamDisposition = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamDisposition &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVStreamDisposition.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, StreamIdx}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_set_r_frame_rate"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamSetRFrameRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamSetRFrameRate &>( + FuncInst->getHostFunc()); + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_r_frame_rate"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamRFrameRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamRFrameRate &>( + FuncInst->getHostFunc()); + + { + int32_t Num = 3; + int32_t Den = 4; + EXPECT_TRUE(HostFuncAVStreamSetRFrameRate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{Num, Den, FormatCtxId, + StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVStreamRFrameRate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{NumPtr, DenPtr, FormatCtxId, + StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + EXPECT_EQ(readUInt32(MemInst, NumPtr), Num); + EXPECT_EQ(readUInt32(MemInst, DenPtr), Den); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_set_avg_frame_rate"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamSetAvgFrameRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamSetAvgFrameRate &>( + FuncInst->getHostFunc()); + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_avg_frame_rate"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamAvgFrameRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamAvgFrameRate &>( + FuncInst->getHostFunc()); + + { + int32_t Num = 3; + int32_t Den = 4; + + EXPECT_TRUE(HostFuncAVStreamSetAvgFrameRate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{Num, Den, FormatCtxId, + StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVStreamAvgFrameRate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{NumPtr, DenPtr, FormatCtxId, + StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + EXPECT_EQ(readUInt32(MemInst, NumPtr), Num); + EXPECT_EQ(readUInt32(MemInst, DenPtr), Den); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_metadata"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamMetadata = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamMetadata &>( + FuncInst->getHostFunc()); + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_set_metadata"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamSetMetadata = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamSetMetadata &>( + FuncInst->getHostFunc()); + { + EXPECT_TRUE(HostFuncAVStreamMetadata.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, StreamIdx, + DictPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + uint32_t DictId = readUInt32(MemInst, DictPtr); + EXPECT_TRUE(HostFuncAVStreamSetMetadata.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, StreamIdx, + DictId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avStream_discard"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamDiscard = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamDiscard &>( + FuncInst->getHostFunc()); + { + EXPECT_TRUE(HostFuncAVStreamDiscard.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avformat/avformatContext.cpp b/test/plugins/wasmedge_ffmpeg/avformat/avformatContext.cpp new file mode 100644 index 000000000000..3d23d403b57a --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avformat/avformatContext.cpp @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avformat/avformatContext.h" +#include "avformat/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +// Testing all AVFormat_funcs. +TEST_F(FFmpegTest, AVFormatContextStruct) { + uint32_t FormatCtxPtr = UINT32_C(4); + uint32_t InputFormatPtr = UINT32_C(8); + uint32_t OutputFormatPtr = UINT32_C(12); + uint32_t DicPtr = uint32_t(16); + uint32_t FilePtr = UINT32_C(100); + + std::string FileName = "ffmpeg-assets/sample_video.mp4"; // 32 chars + initFormatCtx(FormatCtxPtr, FilePtr, FileName); + uint32_t FormatCtxId = readUInt32(MemInst, FormatCtxPtr); + + auto *FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformatContext_iformat"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatCtxIFormat = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatCtxIFormat &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFormatCtxIFormat.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, + InputFormatPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + EXPECT_TRUE(readUInt32(MemInst, InputFormatPtr) > 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformatContext_oformat"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatCtxOFormat = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatCtxOFormat &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFormatCtxOFormat.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, + OutputFormatPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + EXPECT_TRUE(readUInt32(MemInst, InputFormatPtr) > 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformatContext_probescope"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatCtxProbeScore = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatCtxProbeScore &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFormatCtxProbeScore.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FormatCtxId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 100); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformatContext_nb_streams"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatCtxNbStreams = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatCtxNbStreams &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFormatCtxNbStreams.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FormatCtxId}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() > 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformatContext_duration"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatCtxDuration = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatCtxDuration &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFormatCtxDuration.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FormatCtxId}, + Result)); + EXPECT_TRUE(Result[0].get<int64_t>() >= 0 || Result[0].get<int64_t>() < 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformatContext_bit_rate"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatCtxBitRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatCtxBitRate &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFormatCtxBitRate.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FormatCtxId}, + Result)); + EXPECT_EQ(Result[0].get<uint32_t>(), 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformatContext_set_nb_chapters"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatCtxSetNbChapters = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatCtxSetNbChapters &>( + FuncInst->getHostFunc()); + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformatContext_nb_chapters"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatCtxNbChapters = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatCtxNbChapters &>( + FuncInst->getHostFunc()); + { + uint32_t NbChapters = 200; + EXPECT_TRUE(HostFuncAVFormatCtxSetNbChapters.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, NbChapters}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVFormatCtxNbChapters.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FormatCtxId}, + Result)); + EXPECT_EQ(Result[0].get<uint32_t>(), NbChapters); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformatContext_metadata"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatCtxMetadata = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatCtxMetadata &>( + FuncInst->getHostFunc()); + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformatContext_set_metadata"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatCtxSetMetadata = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatCtxSetMetadata &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFormatCtxMetadata.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, DicPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + EXPECT_TRUE(readUInt32(MemInst, DicPtr) > 0); + + uint32_t DictId = readUInt32(MemInst, DicPtr); + EXPECT_TRUE(HostFuncAVFormatCtxSetMetadata.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, DictId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avformat/avformat_func.cpp b/test/plugins/wasmedge_ffmpeg/avformat/avformat_func.cpp new file mode 100644 index 000000000000..788e74953a20 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avformat/avformat_func.cpp @@ -0,0 +1,591 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avformat/avformat_func.h" +#include "avformat/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +// Testing all AVFormat_funcs. +TEST_F(FFmpegTest, AVInputFormatFunc) { + uint32_t FormatCtxPtr = UINT32_C(4); + uint32_t DictPtr = UINT32_C(16); + uint32_t KeyPtr = UINT32_C(100); + uint32_t ValuePtr = UINT32_C(200); + uint32_t StrPtr = UINT32_C(400); + + initDict(DictPtr, KeyPtr, std::string("Key"), ValuePtr, std::string("Value")); + uint32_t DictId = readUInt32(MemInst, DictPtr); + + uint32_t UrlStart = UINT32_C(300); + uint32_t UrlSize = 30; + fillMemContent(MemInst, UrlStart, UrlSize); + fillMemContent(MemInst, UrlStart, + std::string("ffmpeg-assets/sample_video.mp4")); + + auto *FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformat_open_input"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatOpenInput = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatOpenInput &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatOpenInput"sv); + { + // AVDict only + EXPECT_TRUE(HostFuncAVFormatOpenInput.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + FormatCtxPtr, UrlStart, UrlSize, UINT32_C(0), DictId}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + EXPECT_TRUE(readUInt32(MemInst, FormatCtxPtr) > 0); + + // No AVDict, No AVInputFormat + EXPECT_TRUE(HostFuncAVFormatOpenInput.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + FormatCtxPtr, UrlStart, UrlSize, UINT32_C(0), UINT32_C(0)}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + EXPECT_TRUE(readUInt32(MemInst, FormatCtxPtr) > 0); + } + + uint32_t FormatCtxId = readUInt32(MemInst, FormatCtxPtr); + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformat_find_stream_info"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatFindStreamInfo = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatFindStreamInfo &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatFindStreamInfo"sv); + { + EXPECT_TRUE(HostFuncAVFormatFindStreamInfo.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, UINT32_C(0)}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_av_dump_format"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatAVDumpFormat = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVDumpFormat &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVDumpFormat"sv); + { + EXPECT_TRUE(HostFuncAVFormatAVDumpFormat.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + FormatCtxId, 0, UINT32_C(100), UINT32_C(30), 0}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_av_find_best_stream"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFindBestStream = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFindBestStream &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFindBestStream"sv); + { + EXPECT_TRUE(HostFuncAVFindBestStream.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + FormatCtxId, UINT32_C(0), INT32_C(-1), INT32_C(-1), 0, 0}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_av_read_frame"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVReadFrame = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVReadFrame &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVReadFrame"sv); + { + uint32_t PacketPtr = UINT32_C(520); + allocPacket(PacketPtr); + uint32_t PacketId = readUInt32(MemInst, PacketPtr); + EXPECT_TRUE(HostFuncAVReadFrame.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, PacketId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformat_network_init"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatNetworkInit = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatNetworkInit &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatNetworkInit"sv); + { + EXPECT_TRUE(HostFuncAVFormatNetworkInit.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformat_seek_file"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatSeekFile = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatSeekFile &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatSeekFile"sv); + { + uint32_t StreamIdx = -1; + int64_t MinTs = -10; + int64_t Ts = 0; + int64_t MaxTs = 10; + int32_t Flags = 0; + + // Try a network Fetch. + EXPECT_TRUE(HostFuncAVFormatSeekFile.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, StreamIdx, + MinTs, Ts, MaxTs, Flags}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_av_read_play"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatAVReadPlay = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVReadPlay &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVReadPlay"sv); + { + // Try a network Fetch. + EXPECT_TRUE(HostFuncAVFormatAVReadPlay.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FormatCtxId}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() < 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_av_read_pause"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatAVReadPause = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVReadPause &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVReadPause"sv); + { + // Try a network Fetch. + EXPECT_TRUE(HostFuncAVFormatAVReadPause.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FormatCtxId}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() < 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformat_network_deinit"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatNetworkDeInit = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatNetworkDeInit &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatNetworkDeInit"sv); + { + EXPECT_TRUE(HostFuncAVFormatNetworkDeInit.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformat_close_input"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatCloseInput = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatCloseInput &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatCloseInput"sv); + { + EXPECT_TRUE(HostFuncAVFormatCloseInput.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FormatCtxId}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformat_free_context"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFreeContext = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatFreeContext &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatFreeContext"sv); + { + EXPECT_TRUE(HostFuncAVFreeContext.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FormatCtxId}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avformat_version"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatVersion = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatVersion &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatVersion"sv); + { + EXPECT_TRUE(HostFuncAVFormatVersion.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformat_configuration_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatConfigurationLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatConfigurationLength &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatConfigurationLength"sv); + int32_t Length = 0; + { + EXPECT_TRUE(HostFuncAVFormatConfigurationLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformat_configuration"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatConfiguration = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatConfiguration &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatConfiguration"sv); + { + EXPECT_TRUE(HostFuncAVFormatConfiguration.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{StrPtr, Length}, + Result)); + + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformat_license_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatLicenseLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatLicenseLength &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatLicenseLength"sv); + { + EXPECT_TRUE(HostFuncAVFormatLicenseLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avformat_license"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatLicense = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatLicense &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatLicense"sv); + { + EXPECT_TRUE(HostFuncAVFormatLicense.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{StrPtr, Length}, + Result)); + + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } +} + +TEST_F(FFmpegTest, AVOutputFormatFunc) { + + uint32_t FormatCtxPtr = UINT32_C(4); + uint32_t DictPtr = UINT32_C(16); + uint32_t ChapterPtr = UINT32_C(20); + uint32_t FramePtr = UINT32_C(24); + uint32_t KeyPtr = UINT32_C(100); + uint32_t ValuePtr = UINT32_C(200); + + initDict(DictPtr, KeyPtr, std::string("Key"), ValuePtr, std::string("Value")); + initEmptyFrame(FramePtr); + uint32_t DictId = readUInt32(MemInst, DictPtr); + uint32_t FrameId = readUInt32(MemInst, FramePtr); + + uint32_t FormatStart = 300; + uint32_t FormatLen = 3; + uint32_t FileStart = 350; + uint32_t FileLen = 8; + fillMemContent(MemInst, FormatStart, FormatLen + FileLen); + + fillMemContent(MemInst, FormatStart, "mp4"sv); + fillMemContent(MemInst, FileStart, "test.mp4"sv); + + auto *FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformat_alloc_output_context2"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatAllocOutputContext2 = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatAllocOutputContext2 &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatAllocOutputContext2"sv); + { + EXPECT_TRUE(HostFuncAVFormatAllocOutputContext2.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + FormatCtxPtr, 0, FormatStart, FormatLen, FileStart, FileLen}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + + EXPECT_TRUE(HostFuncAVFormatAllocOutputContext2.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + FormatCtxPtr, readUInt32(MemInst, FormatCtxPtr), FormatStart, + FormatLen, FileStart, FileLen}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + + EXPECT_TRUE(HostFuncAVFormatAllocOutputContext2.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxPtr, 0, 0, 0, + FileStart, FileLen}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avio_open"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVIOOpen = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVIOOpen &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVIOOpen"sv); + { + uint32_t AvFormatCtxId = readUInt32(MemInst, FormatCtxPtr); + EXPECT_TRUE( + HostFuncAVIOOpen.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + AvFormatCtxId, FileStart, FileLen, 2}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avio_open2"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVIOOpen2 = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVIOOpen2 &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVIOOpen2"sv); + { + uint32_t FormatCtxId = readUInt32(MemInst, FormatCtxPtr); + EXPECT_TRUE(HostFuncAVIOOpen2.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, FileStart, + FileLen, 2, 0, DictId}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + // TODO: This test modifies the input file. Unable to test. + // Added test on rust side. + // spdlog::info("Testing AVGuessCodec"sv); + // uint32_t EmptyStrPtr = UINT32_C(520); + // writeUInt32(MemInst, 0, EmptyStrPtr); + // { + // uint32_t FormatCtxId = readUInt32(MemInst, FormatCtxPtr); + // int32_t MediaTypeId = 0; // Video + // EXPECT_TRUE(HostFuncAVGuessCodec.run( + // CallFrame, + // std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, + // EmptyStrPtr, 0, + // FilePtr, 32, + // EmptyStrPtr, 0, + // MediaTypeId}, + // Result)); + // EXPECT_EQ(Result[0].get<int32_t>(), 1); // AV_CODEC_ID_MPEG1VIDEO: + // } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformat_write_header"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatWriteHeader = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatWriteHeader &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatWriteHeader"sv); + { + // Did not set AVParameters, etc. Hence Giving Invalid Argument Error. + uint32_t FormatCtxId = readUInt32(MemInst, FormatCtxPtr); + EXPECT_TRUE(HostFuncAVFormatWriteHeader.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, DictId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), -22); + } + + // Write Header above return invalid argument due to which below test won't + // work. The OutputFormatContext should Be configured using the input format + // context. Test on the Rust side. This is working as expected. + + // FuncInst = AVFormatMod->findFuncExports( + // "wasmedge_ffmpeg_avformat_avformat_write_trailer"); + // EXPECT_NE(FuncInst, nullptr); + // EXPECT_TRUE(FuncInst->isHostFunction()); + // auto &HostFuncAVFormatTrailer = dynamic_cast< + // WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatWriteTrailer &>( + // FuncInst->getHostFunc()); + // { + // // Did not set AVParameters, etc. Hence Giving Invalid Argument Error. + // uint32_t FormatCtxId = readUInt32(MemInst, FormatCtxPtr); + // EXPECT_TRUE(HostFuncAVFormatTrailer.run( + // CallFrame, std::initializer_list<WasmEdge::ValVariant>{FormatCtxId}, + // Result)); + // EXPECT_EQ(Result[0].get<int32_t>(), -22); + // } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avchapter_mallocz"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVIOClose = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVChapterMallocz &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVChapterMallocz"sv); + { + EXPECT_TRUE(HostFuncAVIOClose.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{ChapterPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + // How to pass IntPtr + // + // FuncInst = AVFormatMod->findFuncExports( + // "wasmedge_ffmpeg_avformat_avchapter_dynarray_add"); + // EXPECT_NE(FuncInst, nullptr); + // EXPECT_TRUE(FuncInst->isHostFunction()); + // auto &HostFuncAVChapterDynarrayAdd = dynamic_cast< + // WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVChapterDynarrayAdd &>( + // FuncInst->getHostFunc()); + // // For the give input file, nb_chapter is 0; + // { + // uint32_t AvChapterId = readUInt32(MemInst, AvFormatCtxPtr); + // uint32_t AvFormatCtxId = readUInt32(MemInst, AvFormatCtxPtr); + // EXPECT_TRUE(HostFuncAVChapterDynarrayAdd.run( + // CallFrame, + // std::initializer_list<WasmEdge::ValVariant>{AvFormatCtxId, + // UINT32_C(0), + // AvChapterId}, + // Result)); + // EXPECT_EQ(Result[0].get<int32_t>(), + // static_cast<int32_t>(ErrNo::Success)); + // } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avformat_avfreep"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatAVFreep = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFreeP &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFreeP"sv); + { + uint32_t ChapterId = readUInt32(MemInst, ChapterPtr); + EXPECT_TRUE(HostFuncAVFormatAVFreep.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{ChapterId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_av_write_frame"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVWriteFrame = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVWriteFrame &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVWriteFrame"sv); + // Passing Empty Frame, Hence giving Invalid Argument Error. + { + uint32_t FormatCtxId = readUInt32(MemInst, FormatCtxPtr); + EXPECT_TRUE(HostFuncAVWriteFrame.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, FrameId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), -22); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_av_interleaved_write_frame"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVInterleavedWriteFrame = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVInterleavedWriteFrame &>( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVInterleavedWriteFrame"sv); + // Passing Empty Frame, Hence giving Invalid Argument Error. + { + uint32_t FormatCtxId = readUInt32(MemInst, FormatCtxPtr); + EXPECT_TRUE(HostFuncAVInterleavedWriteFrame.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FormatCtxId, FrameId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), -22); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp b/test/plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp new file mode 100644 index 000000000000..bba090c898d8 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avutil/avDictionary.h" +#include "avutil/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVDictionary) { + using namespace std::literals::string_view_literals; + + uint32_t KeyStart = UINT32_C(1); + uint32_t KeyLen = 3; + uint32_t ValueStart = UINT32_C(4); + uint32_t ValueLen = 5; + uint32_t PrevDictEntryIdx = 0; // The Fetch the next Key value Node using an + // index. Passing Index from Rust side. + int32_t Flags = 0; + uint32_t NullDictId = UINT32_C(0); + + uint32_t DictPtr = UINT32_C(80); + + auto *FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_dict_set"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVDictSet = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVDictSet &>( + FuncInst->getHostFunc()); + + // Fill 0 in WasmMemory. + fillMemContent(MemInst, KeyStart, KeyLen + ValueLen); + fillMemContent(MemInst, KeyStart, "KEY"sv); + fillMemContent(MemInst, ValueStart, "VALUE"sv); + + // Storing the above Key and Value in dict and using these in below tests + // (dict_get) to fetch Key,values. + { + EXPECT_TRUE(HostFuncAVDictSet.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + DictPtr, KeyStart, KeyLen, ValueStart, ValueLen, Flags}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + ASSERT_TRUE(readUInt32(MemInst, DictPtr) > 0); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_dict_copy"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVDictCopy = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVDictCopy &>( + FuncInst->getHostFunc()); + + { + uint32_t DestDictPtr = UINT32_C(80); + uint32_t SrcDictId = readUInt32(MemInst, DictPtr); + EXPECT_TRUE( + HostFuncAVDictCopy.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + DestDictPtr, SrcDictId, Flags}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_dict_get"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVDictGet = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVDictGet &>( + FuncInst->getHostFunc()); + + { + // Store the string length of Key and value in below Pointers. + uint32_t KeyLenPtr = UINT32_C(56); + uint32_t ValueLenPtr = UINT32_C(60); + uint32_t DictId = readUInt32(MemInst, DictPtr); + EXPECT_TRUE(HostFuncAVDictGet.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{DictId, KeyStart, KeyLen, + PrevDictEntryIdx, Flags, + KeyLenPtr, ValueLenPtr}, + Result)); + EXPECT_TRUE(Result[0].get<int32_t>() == 1); + EXPECT_EQ(readUInt32(MemInst, KeyLenPtr), KeyLen); + EXPECT_EQ(readUInt32(MemInst, ValueLenPtr), ValueLen); + + // Pass a Null Dict and testing. + EXPECT_TRUE(HostFuncAVDictGet.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + NullDictId, KeyStart, KeyLen, PrevDictEntryIdx, Flags, KeyLenPtr, + ValueLenPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), + static_cast<int32_t>(ErrNo::InternalError)); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_dict_get_key_value"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVDictGetKeyValue = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVDictGetKeyValue &>( + FuncInst->getHostFunc()); + + { + // Store the string of Key and value in below Buffer Pointers. + uint32_t KeyBufPtr = UINT32_C(36); + uint32_t ValueBufPtr = UINT32_C(40); + uint32_t DictId = readUInt32(MemInst, DictPtr); + EXPECT_TRUE(HostFuncAVDictGetKeyValue.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + DictId, KeyStart, KeyLen, ValueBufPtr, ValueLen, KeyBufPtr, + UINT32_C(3), PrevDictEntryIdx, Flags}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + // Verify String. Read String from MemInst + + // Pass a Null Dict and testing. + EXPECT_TRUE(HostFuncAVDictGetKeyValue.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + NullDictId, KeyStart, KeyLen, ValueBufPtr, ValueLen, KeyBufPtr, + UINT32_C(3), PrevDictEntryIdx, Flags}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), + static_cast<int32_t>(ErrNo::InternalError)); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_dict_free"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVDictFree = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVDictFree &>( + FuncInst->getHostFunc()); + + { + uint32_t DictId = readUInt32(MemInst, DictPtr); + EXPECT_TRUE(HostFuncAVDictFree.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{DictId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avutil/avError.cpp b/test/plugins/wasmedge_ffmpeg/avutil/avError.cpp new file mode 100644 index 000000000000..8584c97b11f7 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avError.cpp @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avutil/error.h" +#include "avutil/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVError) { + using namespace std::literals::string_view_literals; + ASSERT_TRUE(AVUtilMod != nullptr); + + int32_t ErrNum = 35; + uint32_t ErrStartPtr = UINT32_C(100); + uint32_t ErrSize = 10; + fillMemContent(MemInst, ErrStartPtr, ErrSize); + fillMemContent(MemInst, ErrStartPtr, "Test Error"sv); + + auto *FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_strerror"); + auto &HostFuncAVUtilAVStrError = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVUtilAVStrError &>( + FuncInst->getHostFunc()); + + { + HostFuncAVUtilAVStrError.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result); + + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_AVERROR"); + auto &HostFuncAVUtilAVError = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVUtilAVError &>( + FuncInst->getHostFunc()); + + { + HostFuncAVUtilAVError.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{ErrNum}, Result); + + EXPECT_EQ(Result[0].get<int32_t>(), + ErrNum * -1); // Returns Negative, convert to Positive + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_AVUNERROR"); + auto &HostFuncAVUtilAVUNError = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVUtilAVUNError &>( + FuncInst->getHostFunc()); + + { + HostFuncAVUtilAVUNError.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{ErrNum}, Result); + + EXPECT_EQ(Result[0].get<int32_t>(), + ErrNum * -1); // Returns Negative, convert to Positive + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avutil/avFrame.cpp b/test/plugins/wasmedge_ffmpeg/avutil/avFrame.cpp new file mode 100644 index 000000000000..b30fe2ab9692 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avFrame.cpp @@ -0,0 +1,784 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avutil/avFrame.h" +#include "avutil/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVFrame) { + uint32_t AVFramePtr = UINT32_C(72); + uint32_t AVFrame2Ptr = UINT32_C(40); + uint32_t DictPtr = UINT32_C(36); + uint32_t NumPtr = UINT32_C(80); + uint32_t DenPtr = UINT32_C(84); + uint32_t BufPtr = UINT32_C(200); // TO store Frame Data; + + std::string FileName = "ffmpeg-assets/sample_video.mp4"; // 32 chars + initFFmpegStructs(UINT32_C(12), UINT32_C(24), UINT32_C(28), FileName, + UINT32_C(60), UINT32_C(64), UINT32_C(68), AVFramePtr); + + initFFmpegStructs(UINT32_C(100), UINT32_C(104), UINT32_C(108), FileName, + UINT32_C(112), UINT32_C(116), UINT32_C(120), AVFrame2Ptr); + + uint32_t AVFrameId = readUInt32(MemInst, AVFramePtr); + uint32_t AVFrame2Id = readUInt32(MemInst, AVFrame2Ptr); + + auto *FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_alloc"); + auto &HostFuncAVFrameAlloc = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameAlloc &>( + FuncInst->getHostFunc()); + + uint32_t EmptyFramePtr = UINT32_C(64); + + { + HostFuncAVFrameAlloc.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{EmptyFramePtr}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + EXPECT_TRUE(readUInt32(MemInst, EmptyFramePtr) > 0); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_free"); + auto &HostFuncAVFrameFree = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameFree &>( + FuncInst->getHostFunc()); + + { + uint32_t EmptyFrameId = readUInt32(MemInst, EmptyFramePtr); + HostFuncAVFrameFree.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{EmptyFrameId}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_width"); + auto &HostFuncAVFrameWidth = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameWidth &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameWidth.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), 1920); // Width + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_height"); + auto &HostFuncAVFrameHeight = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameHeight &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameHeight.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), 1080); // Height + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_video_format"); + auto &HostFuncAVFrameVideoFormat = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameVideoFormat &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameVideoFormat.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), 1); // Video Format + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_isnull"); + auto &HostFuncAVFrameIsNull = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameIsNull &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameIsNull.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_linesize"); + auto &HostFuncAVFrameLinesize = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameLinesize &>( + FuncInst->getHostFunc()); + + int32_t Stride = 0; + uint32_t Idx = 0; + { + HostFuncAVFrameLinesize.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId, Idx}, + Result); + + Stride = Result[0].get<int32_t>(); + EXPECT_EQ(Stride, 1920); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_get_buffer"); + auto &HostFuncAVFrameGetBuffer = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameGetBuffer &>( + FuncInst->getHostFunc()); + { + // For video, it is 32. + int32_t Align = 32; + HostFuncAVFrameGetBuffer.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, Align}, Result); + + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_best_effort_timestamp"); + auto &HostFuncAVFrameBestEffortTimestamp = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameBestEffortTimestamp &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameBestEffortTimestamp.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int64_t>(), 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_pict_type"); + auto &HostFuncAVFramePictType = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFramePictType &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFramePictType.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_interlaced_frame"); + auto &HostFuncAVFrameInterlacedFrame = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameInterlacedFrame &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameInterlacedFrame.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_TRUE(Result[0].get<int32_t>() == 0); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_top_field_first"); + auto &HostFuncAVFrameTopFieldFirst = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameTopFieldFirst &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameTopFieldFirst.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_TRUE(Result[0].get<int32_t>() == 0); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_palette_has_changed"); + auto &HostFuncAVFramePaletteHasChanged = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFramePaletteHasChanged &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFramePaletteHasChanged.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_TRUE(Result[0].get<int32_t>() == 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_colorspace"); + auto &HostFuncAVFrameColorspace = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameColorSpace &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameColorspace.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), 2); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_color_range"); + auto &HostFuncAVFrameColorRange = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameColorRange &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameColorRange.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_color_trc"); + auto &HostAVFrameColorTransferCharacteristic = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameColorTransferCharacteristic + &>(FuncInst->getHostFunc()); + + { + HostAVFrameColorTransferCharacteristic.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), 2); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_chroma_location"); + auto &HostAVFrameChromaLocation = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameChromaLocation &>( + FuncInst->getHostFunc()); + + { + HostAVFrameChromaLocation.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_coded_picture_number"); + auto &HostAVFrameCodedPictureNumber = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameCodedPictureNumber &>( + FuncInst->getHostFunc()); + + { + HostAVFrameCodedPictureNumber.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_display_picture_number"); + auto &HostAVFrameDisplayPictureNumber = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameDisplayPictureNumber &>( + FuncInst->getHostFunc()); + + { + HostAVFrameDisplayPictureNumber.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_repeat_pict"); + auto &HostAVFrameRepeatPict = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameRepeatPict &>( + FuncInst->getHostFunc()); + + { + HostAVFrameRepeatPict.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_flags"); + auto &HostAVFrameFlags = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameFlags &>( + FuncInst->getHostFunc()); + + { + HostAVFrameFlags.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_TRUE(Result[0].get<int32_t>() != 1 << 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_quality"); + auto &HostAVFrameQuality = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameQuality &>( + FuncInst->getHostFunc()); + + { + HostAVFrameQuality.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_metadata"); + auto &HostAVFrameMetadata = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameMetadata &>( + FuncInst->getHostFunc()); + + { + HostAVFrameMetadata.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, DictPtr}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + uint32_t DictId = readUInt32(MemInst, DictPtr); + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_set_metadata"); + auto &HostAVFrameSetMetadata = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetMetadata &>( + FuncInst->getHostFunc()); + + { + HostAVFrameSetMetadata.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, DictId}, Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_key_frame"); + auto &HostAVFrameKeyFrame = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameKeyFrame &>( + FuncInst->getHostFunc()); + + { + HostAVFrameKeyFrame.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_pts"); + auto &HostAVFramePts = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFramePts &>( + FuncInst->getHostFunc()); + + { + HostAVFramePts.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int64_t>(), 0); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_copy"); + auto &HostAVFrameCopy = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameCopy &>( + FuncInst->getHostFunc()); + + { + HostAVFrameCopy.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrame2Id, AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int64_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_copy_props"); + auto &HostAVFrameCopyProps = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameCopyProps &>( + FuncInst->getHostFunc()); + + { + HostAVFrameCopyProps.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrame2Id, AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int64_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_set_width"); + auto &HostFuncAVFrameSetWidth = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetWidth &>( + FuncInst->getHostFunc()); + + { + int32_t Width = 100; + HostFuncAVFrameSetWidth.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, Width}, Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + HostFuncAVFrameWidth.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), Width); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_set_height"); + auto &HostFuncAVFrameSetHeight = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetHeight &>( + FuncInst->getHostFunc()); + + int32_t Height = 100; + { + HostFuncAVFrameSetHeight.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, Height}, Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + HostFuncAVFrameHeight.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), Height); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_data"); + auto &HostFuncAVFrameData = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameData &>( + FuncInst->getHostFunc()); + + { + int32_t Size = 1; // Just reading One byte data for test. + fillMemContent(MemInst, BufPtr, Size); + HostFuncAVFrameData.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + AVFrameId, BufPtr, Size, Idx}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_set_video_format"); + auto &HostFuncAVFrameSetVideoFormat = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetVideoFormat &>( + FuncInst->getHostFunc()); + + { + uint32_t PixFormatId = 10; // GRAY8 + HostFuncAVFrameSetVideoFormat.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, PixFormatId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + HostFuncAVFrameVideoFormat.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), PixFormatId); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_set_pict_type"); + auto &HostFuncAVFrameSetPictType = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetPictType &>( + FuncInst->getHostFunc()); + + { + int32_t PictureId = 4; // AV_PICTURE_TYPE_S + HostFuncAVFrameSetPictType.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, PictureId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + HostFuncAVFramePictType.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), PictureId); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_set_colorspace"); + auto &HostFuncAVFrameSetColorSpace = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetColorSpace &>( + FuncInst->getHostFunc()); + + { + int32_t ColorSpaceId = 4; // FCC + HostFuncAVFrameSetColorSpace.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, ColorSpaceId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + HostFuncAVFrameColorspace.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), ColorSpaceId); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_set_color_range"); + auto &HostFuncAVFrameSetColorRange = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetColorRange &>( + FuncInst->getHostFunc()); + + { + int32_t ColorRangeId = 1; // MPEG + HostFuncAVFrameSetColorRange.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, ColorRangeId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + HostFuncAVFrameColorRange.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), ColorRangeId); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_set_color_trc"); + auto &HostFuncAVFrameSetColorTransferCharacteristic = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil:: + AVFrameSetColorTransferCharacteristic &>( + FuncInst->getHostFunc()); + + { + int32_t ColorTrcId = 5; // GAMMA28 + HostFuncAVFrameSetColorTransferCharacteristic.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, ColorTrcId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + HostAVFrameColorTransferCharacteristic.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), ColorTrcId); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_set_pts"); + auto &HostFuncAVFrameSetPts = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetPts &>( + FuncInst->getHostFunc()); + + { + int64_t Pts = 10; + HostFuncAVFrameSetPts.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId, Pts}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + HostAVFramePts.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), Pts); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_sample_aspect_ratio"); + auto &HostFuncAVFrameSampleAspectRatio = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSampleAspectRatio &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameSampleAspectRatio.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, NumPtr, DenPtr}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + int32_t ColorPrimariesId = 1; // BT709 + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_set_color_primaries"); + auto &HostFuncAVFrameSetColorPrimaries = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetColorPrimaries &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameSetColorPrimaries.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, + ColorPrimariesId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_color_primaries"); + auto &HostFuncAVFrameColorPrimaries = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameColorPrimaries &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameColorPrimaries.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), ColorPrimariesId); + } + + // ========================================================================== + // AVFrame Audio Funcs. + // ========================================================================== + + // Setting the fields to Video Frame itself. + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_set_audio_format"); + auto &HostFuncAVFrameSetAudioFormat = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetAudioFormat &>( + FuncInst->getHostFunc()); + + uint32_t SampleFormatId = 4; + { + HostFuncAVFrameSetAudioFormat.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, SampleFormatId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_audio_format"); + auto &HostFuncAVFrameAudioFormat = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameAudioFormat &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameAudioFormat.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), SampleFormatId); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_set_nb_samples"); + auto &HostFuncAVFrameSetNbSamples = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetNbSamples &>( + FuncInst->getHostFunc()); + + int32_t NbSamples = 32; + { + HostFuncAVFrameSetNbSamples.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, NbSamples}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_nb_samples"); + auto &HostFuncAVFrameNbSamples = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameNbSamples &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameNbSamples.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), NbSamples); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_set_sample_rate"); + auto &HostFuncAVFrameSetSampleRate = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetSampleRate &>( + FuncInst->getHostFunc()); + + int32_t SampleRate = 10; + { + HostFuncAVFrameSetSampleRate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, SampleRate}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_sample_rate"); + auto &HostFuncAVFrameSampleRate = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSampleRate &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameSampleRate.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), SampleRate); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_set_channels"); + auto &HostFuncAVFrameSetChannels = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetChannels &>( + FuncInst->getHostFunc()); + + int32_t Channels = 3; + { + HostFuncAVFrameSetChannels.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, Channels}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_channels"); + auto &HostFuncAVFrameChannels = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameChannels &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameChannels.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), Channels); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_set_channel_layout"); + auto &HostFuncAVFrameSetChannelLayout = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameSetChannelLayout &>( + FuncInst->getHostFunc()); + + uint64_t ChannelLayout = 1UL << 10; + { + HostFuncAVFrameSetChannelLayout.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVFrameId, ChannelLayout}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_channel_layout"); + auto &HostFuncAVFrameChannelLayout = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameChannelLayout &>( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameChannelLayout.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get<uint64_t>(), ChannelLayout); + } + + // ========================================================================== + // AVFrame Audio Funcs. + // ========================================================================== +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avutil/avPixfmt.cpp b/test/plugins/wasmedge_ffmpeg/avutil/avPixfmt.cpp new file mode 100644 index 000000000000..625acd100314 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avPixfmt.cpp @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avutil/module.h" +#include "avutil/pixfmt.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVPixFmt) { + uint32_t NamePtr = UINT32_C(4); + + auto *FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_avpixfmtdescriptor_nb_components"); + auto &HostFuncAVPixFmtDescriptorNbComponents = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AvPixFmtDescriptorNbComponents &>( + FuncInst->getHostFunc()); + + uint32_t PixFmtId = 3; // RGB24 + + { + HostFuncAVPixFmtDescriptorNbComponents.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PixFmtId}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), PixFmtId); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_avpixfmtdescriptor_log2_chromaw"); + auto &HostFuncAvPixFmtDescriptorLog2ChromaW = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AvPixFmtDescriptorLog2ChromaW &>( + FuncInst->getHostFunc()); + + { + HostFuncAvPixFmtDescriptorLog2ChromaW.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{1}, Result); + + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_avpixfmtdescriptor_log2_chromah"); + auto &HostFuncAvPixFmtDescriptorLog2ChromaH = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AvPixFmtDescriptorLog2ChromaH &>( + FuncInst->getHostFunc()); + + { + HostFuncAvPixFmtDescriptorLog2ChromaH.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PixFmtId}, + Result); + + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + int32_t Length = 0; + int32_t TransferCharacteristicId = 6; // (SMPTE170M) + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_color_transfer_name_length"); + auto &HostFuncAVColorTransferNameLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVColorTransferNameLength &>( + FuncInst->getHostFunc()); + + { + HostFuncAVColorTransferNameLength.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{TransferCharacteristicId}, + Result); + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + // Fill memory with zero. + fillMemContent(MemInst, NamePtr, Length); + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_color_transfer_name"); + auto &HostFuncAVColorTransferName = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVColorTransferName &>( + FuncInst->getHostFunc()); + + { + HostFuncAVColorTransferName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{TransferCharacteristicId, + NamePtr, Length}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + int32_t ColorRangeId = 2; //; JPEG + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_color_range_name_length"); + auto &HostFuncAVColorRangeNameLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVColorRangeNameLength &>( + FuncInst->getHostFunc()); + + { + HostFuncAVColorRangeNameLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{ColorRangeId}, + Result); + + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + // Fill memory with zero. + fillMemContent(MemInst, NamePtr, Length); + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_color_range_name"); + auto &HostFuncAVColorRangeName = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVColorRangeName &>( + FuncInst->getHostFunc()); + + { + HostFuncAVColorRangeName.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + ColorRangeId, NamePtr, Length}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + int32_t ColorSpaceId = 1; // BT709 + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_color_space_name_length"); + auto &HostFuncAVColorSpaceNameLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVColorSpaceNameLength &>( + FuncInst->getHostFunc()); + + { + HostFuncAVColorSpaceNameLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{ColorSpaceId}, + Result); + + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + // Fill memory with zero. + fillMemContent(MemInst, NamePtr, Length); + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_color_space_name"); + auto &HostFuncAVColorSpaceName = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVColorSpaceName &>( + FuncInst->getHostFunc()); + + { + HostFuncAVColorSpaceName.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + ColorSpaceId, NamePtr, Length}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + int32_t ColorPrimariesId = 1; // BT709 + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_color_primaries_name_length"); + auto &HostFuncAVColorPrimariesNameLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVColorPrimariesNameLength &>( + FuncInst->getHostFunc()); + + { + HostFuncAVColorPrimariesNameLength.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ColorPrimariesId}, Result); + + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + // Fill memory with zero. + fillMemContent(MemInst, NamePtr, Length); + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_color_primaries_name"); + auto &HostFuncAVColorPrimariesName = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVColorPrimariesName &>( + FuncInst->getHostFunc()); + + { + HostFuncAVColorPrimariesName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ColorPrimariesId, NamePtr, + Length}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + PixFmtId = 1; // YUV420P + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_pix_format_name_length"); + auto &HostFuncAVPixFormatNameLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVPixelFormatNameLength &>( + FuncInst->getHostFunc()); + + { + HostFuncAVPixFormatNameLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PixFmtId}, + Result); + + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + // Fill memory with zero. + fillMemContent(MemInst, NamePtr, Length); + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_pix_format_name"); + auto &HostFuncAVPixFormatName = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVPixelFormatName &>( + FuncInst->getHostFunc()); + + { + HostFuncAVPixFormatName.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{PixFmtId, NamePtr, Length}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_pix_format_mask"); + auto &HostFuncAVPixFormatMask = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVPixelFormatMask &>( + FuncInst->getHostFunc()); + + { + uint32_t PixId = 3; // AV_PIX_FMT_RGB24: + HostFuncAVPixFormatMask.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PixId}, Result); + + EXPECT_EQ(Result[0].get<int32_t>(), + 2); // Verify Mask. Position of Pix in Enum. + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avutil/avRational.cpp b/test/plugins/wasmedge_ffmpeg/avutil/avRational.cpp new file mode 100644 index 000000000000..85223ad958ff --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avRational.cpp @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avutil/avRational.h" +#include "avutil/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVRational) { + ASSERT_TRUE(AVUtilMod != nullptr); + + uint32_t NumPtr = UINT32_C(4); + uint32_t DenPtr = UINT32_C(8); + + // Addition Function + auto *FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_add_q"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVAddQ = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVAddQ &>( + FuncInst->getHostFunc()); + + { + int32_t ANum = 3; + int32_t ADen = 4; + int32_t BNum = -6; + int32_t BDen = 7; + EXPECT_TRUE(HostFuncAVAddQ.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + ANum, ADen, BNum, BDen, NumPtr, DenPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_EQ(readSInt32(MemInst, NumPtr), -3); + EXPECT_EQ(readSInt32(MemInst, DenPtr), 28); + } + + // Subtraction Function + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_sub_q"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVSubQ = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVSubQ &>( + FuncInst->getHostFunc()); + + { + int32_t ANum = -843; + int32_t ADen = 11; + int32_t BNum = 38; + int32_t BDen = 12; + + writeSInt32(MemInst, 0, NumPtr); // Setting value of pointer to 0. + writeSInt32(MemInst, 0, DenPtr); // Setting value of pointer to 0. + EXPECT_TRUE(HostFuncAVSubQ.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + ANum, ADen, BNum, BDen, NumPtr, DenPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_EQ(readSInt32(MemInst, NumPtr), -5267); + EXPECT_EQ(readSInt32(MemInst, DenPtr), 66); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_mul_q"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVMulQ = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVMulQ &>( + FuncInst->getHostFunc()); + + { + int32_t ANum = -6; + int32_t ADen = 7; + int32_t BNum = 3; + int32_t BDen = 4; + + writeSInt32(MemInst, 0, NumPtr); // Setting value of pointer to 0. + writeSInt32(MemInst, 0, DenPtr); // Setting value of pointer to 0. + EXPECT_TRUE(HostFuncAVMulQ.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + ANum, ADen, BNum, BDen, NumPtr, DenPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_EQ(readSInt32(MemInst, NumPtr), -9); + EXPECT_EQ(readSInt32(MemInst, DenPtr), 14); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_div_q"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVDivQ = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVDivQ &>( + FuncInst->getHostFunc()); + + { + int32_t ANum = -6; + int32_t ADen = 7; + int32_t BNum = 3; + int32_t BDen = 4; + + writeSInt32(MemInst, 0, NumPtr); // Setting value of pointer to 0. + writeSInt32(MemInst, 0, DenPtr); // Setting value of pointer to 0. + EXPECT_TRUE(HostFuncAVDivQ.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + ANum, ADen, BNum, BDen, NumPtr, DenPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_EQ(readSInt32(MemInst, NumPtr), -8); + EXPECT_EQ(readSInt32(MemInst, DenPtr), 7); + } + + // How to Pass a Double functions. + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_d2q"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVD2Q = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVD2Q &>( + FuncInst->getHostFunc()); + + { + double D = 5; + int32_t Max = 10; + + writeSInt32(MemInst, 0, NumPtr); // Setting value of pointer to 0. + writeSInt32(MemInst, 0, DenPtr); // Setting value of pointer to 0. + + EXPECT_TRUE(HostFuncAVD2Q.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{D, Max, NumPtr, DenPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + + EXPECT_EQ(readSInt32(MemInst, NumPtr), 5); + EXPECT_EQ(readSInt32(MemInst, DenPtr), 1); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_q2d"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVQ2d = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVQ2d &>( + FuncInst->getHostFunc()); + + { + // Convert Rational Number to Double. + int32_t ANum = 1; + int32_t ADen = 2; + + writeSInt32(MemInst, 0, NumPtr); // Setting value of pointer to 0. + writeSInt32(MemInst, 0, DenPtr); // Setting value of pointer to 0. + EXPECT_TRUE(HostFuncAVQ2d.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{ANum, ADen}, + Result)); + EXPECT_EQ(Result[0].get<double_t>(), 0.5); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_inv_q"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncInvQ = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVInvQ &>( + FuncInst->getHostFunc()); + + { + // Inverse a Rational Number. + int32_t ANum = -3; + int32_t ADen = 4; + + writeSInt32(MemInst, 0, NumPtr); // Setting value of pointer to 0. + writeSInt32(MemInst, 0, DenPtr); // Setting value of pointer to 0. + EXPECT_TRUE(HostFuncInvQ.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ANum, ADen, NumPtr, DenPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + + EXPECT_EQ(readSInt32(MemInst, NumPtr), 4); + EXPECT_EQ(readSInt32(MemInst, DenPtr), -3); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_q2intfloat"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVQ2IntFloat = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVQ2IntFloat &>( + FuncInst->getHostFunc()); + + { + int32_t ANum = 1; + int32_t ADen = 5; + + EXPECT_TRUE(HostFuncAVQ2IntFloat.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{ANum, ADen}, + Result)); + EXPECT_EQ(Result[0].get<uint32_t>(), static_cast<uint32_t>(1045220557)); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_nearer_q"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVNearerQ = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVNearerQ &>( + FuncInst->getHostFunc()); + + { + int32_t ANum = 1; + int32_t ADen = 3; + int32_t BNum = 1; + int32_t BDen = 2; + int32_t CNum = -1; + int32_t CDen = 2; + + // B nearer to A + EXPECT_TRUE( + HostFuncAVNearerQ.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + ANum, ADen, BNum, BDen, CNum, CDen}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(1)); + + ANum = -1; + + // C nearer to A + EXPECT_TRUE( + HostFuncAVNearerQ.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + ANum, ADen, BNum, BDen, CNum, CDen}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(-1)); + + ANum = 0; + ADen = 0; + + // Both are at same distance + EXPECT_TRUE( + HostFuncAVNearerQ.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + ANum, ADen, BNum, BDen, CNum, CDen}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(0)); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_cmp_q"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVCmpQ = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVCmpQ &>( + FuncInst->getHostFunc()); + + { + int32_t ANum = 1; + int32_t ADen = 2; + int32_t BNum = 2; + int32_t BDen = 1; + // A < B + EXPECT_TRUE(HostFuncAVCmpQ.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ANum, ADen, BNum, BDen}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(-1)); + + ANum = 2; + ADen = 1; + BNum = 1; + BDen = 2; + // A > B + EXPECT_TRUE(HostFuncAVCmpQ.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ANum, ADen, BNum, BDen}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(1)); + + ANum = 2; + ADen = 1; + BNum = 2; + BDen = 1; + // A == B + EXPECT_TRUE(HostFuncAVCmpQ.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ANum, ADen, BNum, BDen}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(0)); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_reduce"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVReduce = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVReduce &>( + FuncInst->getHostFunc()); + + { + int64_t ANum = 1; + int64_t ADen = 2; + int64_t Max = 3; + EXPECT_TRUE( + HostFuncAVReduce.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + NumPtr, DenPtr, ANum, ADen, Max}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(1)); + } +} +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avutil/avSampleFmt.cpp b/test/plugins/wasmedge_ffmpeg/avutil/avSampleFmt.cpp new file mode 100644 index 000000000000..d12cd16d6db2 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avSampleFmt.cpp @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avutil/module.h" +#include "avutil/samplefmt.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVSampleFmt) { + using namespace std::literals::string_view_literals; + ASSERT_TRUE(AVUtilMod != nullptr); + + uint32_t BufferPtr = UINT32_C(160); + uint32_t NamePtr = UINT32_C(80); + uint32_t LinesizePtr = UINT32_C(20); + + uint32_t SampleFmtId = 1; // AV_SAMPLE_FMT_S32 + auto *FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_get_packed_sample_fmt"); + auto &HostFuncAVGetPackedSampleFmt = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVGetPackedSampleFmt &>( + FuncInst->getHostFunc()); + + { + HostFuncAVGetPackedSampleFmt.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{SampleFmtId}, + Result); + + EXPECT_EQ(Result[0].get<uint32_t>(), SampleFmtId); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_get_planar_sample_fmt"); + auto &HostFuncAVGetPlanarSampleFmt = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVGetPlanarSampleFmt &>( + FuncInst->getHostFunc()); + + { + HostFuncAVGetPlanarSampleFmt.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{SampleFmtId}, + Result); + + EXPECT_EQ(Result[0].get<uint32_t>(), 6); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_sample_fmt_is_planar"); + auto &HostFuncAVSampleFmtIsPlanar = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVSampleFmtIsPlanar &>( + FuncInst->getHostFunc()); + + { + HostFuncAVSampleFmtIsPlanar.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{SampleFmtId}, + Result); + + EXPECT_EQ(Result[0].get<uint32_t>(), 0); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_get_bytes_per_sample"); + auto &HostFuncAVGetBytesPerSample = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVGetBytesPerSample &>( + FuncInst->getHostFunc()); + + { + HostFuncAVGetBytesPerSample.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{SampleFmtId}, + Result); + + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_get_sample_fmt"); + auto &HostFuncAVGetSampleFmt = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVGetSampleFmt &>( + FuncInst->getHostFunc()); + + uint32_t SampleFmtStart = 100; + uint32_t SampleFmtSize = 2; + fillMemContent(MemInst, SampleFmtSize, SampleFmtSize); + + fillMemContent(MemInst, SampleFmtStart, "u8"sv); + { + HostFuncAVGetSampleFmt.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + SampleFmtStart, SampleFmtSize}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_samples_get_buffer_size"); + auto &HostFuncAVSamplesGetBufferSize = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVSamplesGetBufferSize &>( + FuncInst->getHostFunc()); + + int32_t NbChannels = 1; + int32_t NbSamples = 5; + int32_t Align = 1; + int32_t BufSize = 0; + { + HostFuncAVSamplesGetBufferSize.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{NbChannels, NbSamples, + SampleFmtId, Align}, + Result); + + BufSize = Result[0].get<int32_t>(); + EXPECT_TRUE(BufSize); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_samples_alloc_array_and_samples"); + auto &HostFuncAVSamplesAllocArrayAndSamples = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVSamplesAllocArrayAndSamples &>( + FuncInst->getHostFunc()); + + { + HostFuncAVSamplesAllocArrayAndSamples.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + BufferPtr, LinesizePtr, NbChannels, NbSamples, SampleFmtId, Align}, + Result); + + EXPECT_TRUE(Result[0].get<int32_t>() >= 0); + } + + uint32_t BufId = readUInt32(MemInst, BufferPtr); + ASSERT_TRUE(BufId > 0); + + int32_t Length = 0; + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_get_sample_fmt_name_length"); + auto &HostFuncAVGetSampleFmtNameLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVGetSampleFmtNameLength &>( + FuncInst->getHostFunc()); + + { + HostFuncAVGetSampleFmtNameLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{SampleFmtId}, + Result); + + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_get_sample_fmt_name"); + auto &HostFuncAVGetSampleFmtName = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVGetSampleFmtName &>( + FuncInst->getHostFunc()); + + // Fill Memory with 0. + fillMemContent(MemInst, NamePtr, Length); + { + HostFuncAVGetSampleFmtName.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + SampleFmtId, NamePtr, Length}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_get_sample_fmt_mask"); + auto &HostFuncAVGetSampleFmtMask = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVGetSampleFmtMask &>( + FuncInst->getHostFunc()); + + { + uint32_t SampleId = 2; // AV_SAMPLE_FMT_S16; + HostFuncAVGetSampleFmtMask.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{SampleId}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_freep"); + auto &HostFuncAVFreep = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFreep &>( + FuncInst->getHostFunc()); + + { + uint32_t BufferId = readUInt32(MemInst, BufferPtr); + HostFuncAVFreep.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{BufferId}, + Result); + + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/avutil/avutil_func.cpp b/test/plugins/wasmedge_ffmpeg/avutil/avutil_func.cpp new file mode 100644 index 000000000000..2406cea12323 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avutil_func.cpp @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "avutil/avutil_func.h" +#include "avutil/avTime.h" +#include "avutil/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVUtilFunc) { + ASSERT_TRUE(AVUtilMod != nullptr); + + uint32_t NamePtr = UINT32_C(4); + + auto *FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_log_set_level"); + auto &HostFuncAVLogSetLevel = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVLogSetLevel &>( + FuncInst->getHostFunc()); + + int32_t LogLvlId = 32; + { + HostFuncAVLogSetLevel.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{LogLvlId}, + Result); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_log_get_level"); + auto &HostFuncAVLogGetLevel = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVLogGetLevel &>( + FuncInst->getHostFunc()); + + { + HostFuncAVLogGetLevel.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result); + EXPECT_EQ(Result[0].get<int32_t>(), LogLvlId); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_log_set_flags"); + auto &HostFuncAVLogSetFlags = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVLogSetFlags &>( + FuncInst->getHostFunc()); + + { + HostFuncAVLogSetFlags.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{1}, Result); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_log_get_flags"); + auto &HostFuncAVLogGetFlags = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVLogGetFlags &>( + FuncInst->getHostFunc()); + + { + HostFuncAVLogGetFlags.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{1}, Result); + + EXPECT_EQ(Result[0].get<int32_t>(), 32); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_rescale_q"); + auto &HostFuncAVRescaleQ = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVRescaleQ &>( + FuncInst->getHostFunc()); + + int64_t A = 20; + int32_t BNum = 5; + int32_t BDen = 10; + int32_t CNum = 5; + int32_t CDen = 20; + + { + HostFuncAVRescaleQ.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{A, BNum, BDen, CNum, CDen}, + Result); + + EXPECT_TRUE(Result[0].get<int64_t>() > 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_rescale_q_rnd"); + auto &HostFuncAVRescaleQRnd = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVRescaleQRnd &>( + FuncInst->getHostFunc()); + + { + int32_t RoundingId = 2; + HostFuncAVRescaleQRnd.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + A, BNum, BDen, CNum, CDen, RoundingId}, + Result); + + EXPECT_TRUE(Result[0].get<int64_t>() > 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_avutil_version"); + auto &HostFuncAVUtilVersion = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVUtilVersion &>( + FuncInst->getHostFunc()); + + { + HostFuncAVUtilVersion.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result); + + EXPECT_TRUE(Result[0].get<uint32_t>() > 0); + } + + uint64_t ChannelId = 1; // FRONT_LEFT + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_get_channel_layout_nb_channels"); + auto &HostFuncAVGetChannelLayoutNbChannels = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVGetChannelLayoutNbChannels &>( + FuncInst->getHostFunc()); + + { + HostFuncAVGetChannelLayoutNbChannels.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{ChannelId}, + Result); + EXPECT_TRUE(Result[0].get<int32_t>() > 0); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_get_default_channel_layout"); + auto &HostFuncAVGetDefaultChannelLayout = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVGetDefaultChannelLayout &>( + FuncInst->getHostFunc()); + + { + HostFuncAVGetDefaultChannelLayout.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{ChannelId}, + Result); + EXPECT_TRUE(Result[0].get<uint64_t>() > 0); + } + + uint32_t Length = 0; + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_avutil_configuration_length"); + auto &HostFuncAVUtilConfigurationLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVUtilConfigurationLength &>( + FuncInst->getHostFunc()); + + { + HostFuncAVUtilConfigurationLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result); + + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + // Fill NamePtr with 0. + fillMemContent(MemInst, NamePtr, Length); + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_avutil_configuration"); + auto &HostFuncAVUtilConfiguration = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVUtilConfiguration &>( + FuncInst->getHostFunc()); + + { + HostFuncAVUtilConfiguration.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{NamePtr, Length}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_avutil_license_length"); + auto &HostFuncAVUtilLicenseLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVUtilLicenseLength &>( + FuncInst->getHostFunc()); + + { + HostFuncAVUtilLicenseLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result); + + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + // Fill NamePtr with 0. + fillMemContent(MemInst, NamePtr, Length); + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_avutil_license"); + auto &HostFuncAVUtilLicense = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVUtilLicense &>( + FuncInst->getHostFunc()); + + { + HostFuncAVUtilLicense.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{NamePtr, Length}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } +} + +TEST_F(FFmpegTest, AVTime) { + + ASSERT_TRUE(AVUtilMod != nullptr); + + auto *FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_gettime"); + auto &HostFuncAVGetTime = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVGetTime &>( + FuncInst->getHostFunc()); + + { + HostFuncAVGetTime.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result); + + EXPECT_TRUE(Result[0].get<int64_t>() > 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_gettime_relative"); + auto &HostFuncAVGetTimeRelative = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVGetTimeRelative &>( + FuncInst->getHostFunc()); + + { + HostFuncAVGetTimeRelative.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result); + + EXPECT_TRUE(Result[0].get<int64_t>() > 0); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_gettime_relative_is_monotonic"); + auto &HostFuncAVGetTimeRelativeIsMonotonic = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVGetTimeRelativeIsMonotonic &>( + FuncInst->getHostFunc()); + + { + HostFuncAVGetTimeRelativeIsMonotonic.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result); + + EXPECT_EQ(Result[0].get<int32_t>(), 1); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_usleep"); + auto &HostFuncAVUSleep = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVUSleep &>( + FuncInst->getHostFunc()); + + { + HostFuncAVUSleep.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{1000}, Result); + + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/main.cpp b/test/plugins/wasmedge_ffmpeg/main.cpp new file mode 100644 index 000000000000..c2be683bdb8d --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/main.cpp @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include <gtest/gtest.h> + +GTEST_API_ int main(int Argc, char **Argv) { + testing::InitGoogleTest(&Argc, Argv); + return RUN_ALL_TESTS(); +} diff --git a/test/plugins/wasmedge_ffmpeg/swresample/swresample_func.cpp b/test/plugins/wasmedge_ffmpeg/swresample/swresample_func.cpp new file mode 100644 index 000000000000..6f84db6f3cca --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/swresample/swresample_func.cpp @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "swresample/swresample_func.h" +#include "swresample/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, SWResampleFunc) { + ASSERT_TRUE(SWResampleMod != nullptr); + + uint32_t DictPtr = UINT32_C(4); + uint32_t SWResamplePtr = UINT32_C(8); + uint32_t FramePtr = UINT32_C(72); + uint32_t Frame2Ptr = UINT32_C(16); + uint32_t KeyPtr = UINT32_C(100); + uint32_t ValuePtr = UINT32_C(200); + + initDict(DictPtr, KeyPtr, std::string("Key"), ValuePtr, std::string("Value")); + + std::string FileName = "ffmpeg-assets/sample_video.mp4"; // 32 chars + initFFmpegStructs(UINT32_C(20), UINT32_C(24), UINT32_C(28), FileName, + UINT32_C(60), UINT32_C(64), UINT32_C(68), FramePtr); + + uint32_t StrPtr = UINT32_C(76); + initEmptyFrame(Frame2Ptr); + + uint32_t DictId = readUInt32(MemInst, DictPtr); + uint32_t FrameId = readUInt32(MemInst, FramePtr); + uint32_t Frame2Id = readUInt32(MemInst, Frame2Ptr); + + auto *FuncInst = SWResampleMod->findFuncExports( + "wasmedge_ffmpeg_swresample_swresample_version"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSWResampleVersion = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWResample::SWResampleVersion &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncSWResampleVersion.run(CallFrame, {}, Result)); + ASSERT_TRUE(Result[0].get<int32_t>() > 0); + } + + FuncInst = SWResampleMod->findFuncExports( + "wasmedge_ffmpeg_swresample_swr_alloc_set_opts"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwrAllocSetOpts = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWResample::SWRAllocSetOpts &>( + FuncInst->getHostFunc()); + + // Testing with Null Old SwrCtx. Hence 2nd argument is 0. + { + uint32_t SWRCtxId = 0; + uint64_t OutChLayoutId = 1 << 1; // Front Right + uint32_t OutSampleFmtId = 2; // AV_SAMPLE_FMT_S16 + int32_t OutSampleRate = 30; + uint64_t InChLayoutId = 1 << 2; // FRONT_CENTER + uint32_t InSampleFmtId = 3; // AV_SAMPLE_FMT_S32 + int32_t SampleRate = 40; + int32_t LogOffset = 1; + + EXPECT_TRUE(HostFuncSwrAllocSetOpts.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + SWResamplePtr, SWRCtxId, OutChLayoutId, OutSampleFmtId, + OutSampleRate, InChLayoutId, InSampleFmtId, SampleRate, LogOffset}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + ASSERT_TRUE(readUInt32(MemInst, SWResamplePtr) > 0); + } + + // Test with Existing SwrCtx. + uint32_t SwrId = readUInt32(MemInst, SWResamplePtr); + { + uint32_t SWRCtxId = SwrId; + uint64_t OutChLayoutId = 1 << 1; // Front Right + uint32_t OutSampleFmtId = 2; // AV_SAMPLE_FMT_S16 + int32_t OutSampleRate = 30; + uint64_t InChLayoutId = 1 << 2; // FRONT_CENTER + uint32_t InSampleFmtId = 3; // AV_SAMPLE_FMT_S32 + int32_t SampleRate = 40; + int32_t LogOffset = 1; + EXPECT_TRUE(HostFuncSwrAllocSetOpts.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + SWResamplePtr, SWRCtxId, OutChLayoutId, OutSampleFmtId, + OutSampleRate, InChLayoutId, InSampleFmtId, SampleRate, LogOffset}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + ASSERT_TRUE(readUInt32(MemInst, SWResamplePtr) > 0); + } + + FuncInst = + SWResampleMod->findFuncExports("wasmedge_ffmpeg_swresample_swr_free"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwrFree = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWResample::SWRFree &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncSwrFree.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{SwrId}, Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + SWResampleMod->findFuncExports("wasmedge_ffmpeg_swresample_swr_init"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwrInit = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWResample::SWRInit &>( + FuncInst->getHostFunc()); + + { + SwrId = readUInt32(MemInst, SWResamplePtr); + EXPECT_TRUE(HostFuncSwrInit.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{SwrId}, Result)); + ASSERT_TRUE(Result[0].get<int32_t>() >= 0); + } + + FuncInst = SWResampleMod->findFuncExports( + "wasmedge_ffmpeg_swresample_av_opt_set_dict"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVOptSetDict = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWResample::AVOptSetDict &>( + FuncInst->getHostFunc()); + + { + uint32_t EmptyDictId = 0; + SwrId = readUInt32(MemInst, SWResamplePtr); + EXPECT_TRUE(HostFuncAVOptSetDict.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{SwrId, EmptyDictId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + { + SwrId = readUInt32(MemInst, SWResamplePtr); + EXPECT_TRUE(HostFuncAVOptSetDict.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{SwrId, DictId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = SWResampleMod->findFuncExports( + "wasmedge_ffmpeg_swresample_swr_convert_frame"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwrConvertFrame = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWResample::SWRConvertFrame &>( + FuncInst->getHostFunc()); + + { + SwrId = readUInt32(MemInst, SWResamplePtr); + EXPECT_TRUE(HostFuncSwrConvertFrame.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{SwrId, Frame2Id, FrameId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>()); + } + + FuncInst = SWResampleMod->findFuncExports( + "wasmedge_ffmpeg_swresample_swr_get_delay"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwrGetDelay = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWResample::SWRGetDelay &>( + FuncInst->getHostFunc()); + + { + SwrId = readUInt32(MemInst, SWResamplePtr); + EXPECT_TRUE(HostFuncSwrGetDelay.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{SwrId, 1}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), 0); + } + + FuncInst = SWResampleMod->findFuncExports( + "wasmedge_ffmpeg_swresample_swresample_configuration_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwrConfigLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWResample::SWResampleConfigurationLength + &>(FuncInst->getHostFunc()); + + int32_t Length = 0; + { + SwrId = readUInt32(MemInst, SWResamplePtr); + EXPECT_TRUE(HostFuncSwrConfigLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + Length = Result[0].get<int32_t>(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = SWResampleMod->findFuncExports( + "wasmedge_ffmpeg_swresample_swresample_configuration"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwrConfig = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWResample::SWResampleConfiguration &>( + FuncInst->getHostFunc()); + + { + SwrId = readUInt32(MemInst, SWResamplePtr); + EXPECT_TRUE(HostFuncSwrConfig.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = SWResampleMod->findFuncExports( + "wasmedge_ffmpeg_swresample_swresample_license_length"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwrLicenseLen = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWResample::SWResampleLicenseLength &>( + FuncInst->getHostFunc()); + + { + SwrId = readUInt32(MemInst, SWResamplePtr); + EXPECT_TRUE(HostFuncSwrLicenseLen.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result)); + + Length = Result[0].get<int32_t>(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = SWResampleMod->findFuncExports( + "wasmedge_ffmpeg_swresample_swresample_license"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwrLicense = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWResample::SWResampleLicense &>( + FuncInst->getHostFunc()); + + { + SwrId = readUInt32(MemInst, SWResamplePtr); + EXPECT_TRUE(HostFuncSwrLicense.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/swscale/swscale_func.cpp b/test/plugins/wasmedge_ffmpeg/swscale/swscale_func.cpp new file mode 100644 index 000000000000..2f0fa314c0d4 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/swscale/swscale_func.cpp @@ -0,0 +1,540 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "swscale/swscale_func.h" +#include "swscale/module.h" + +#include "utils.h" + +#include <gtest/gtest.h> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +// ============================================================================ +// This test deals with funcs related to SwsContext +// ============================================================================ + +TEST_F(FFmpegTest, SwsContext) { + ASSERT_TRUE(SWScaleMod != nullptr); + + auto *FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_getContext"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsGetContext = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsGetContext &>( + FuncInst->getHostFunc()); + + uint32_t SWScalePtr = UINT32_C(4); + uint32_t SWCachedScalePtr = UINT32_C(8); + uint32_t FramePtr = UINT32_C(72); + uint32_t Frame2Ptr = UINT32_C(124); + + std::string FileName = "ffmpeg-assets/sample_video.mp4"; // 32 chars + initFFmpegStructs(UINT32_C(12), UINT32_C(24), UINT32_C(28), FileName, + UINT32_C(60), UINT32_C(64), UINT32_C(68), FramePtr); + + initEmptyFrame(Frame2Ptr); + + uint32_t FrameId = readUInt32(MemInst, FramePtr); + uint32_t Frame2Id = readUInt32(MemInst, Frame2Ptr); + + uint32_t YUV420PId = 1; // YUV420P AVPixFormatId (From Bindings.h) + uint32_t RGB24Id = 3; // RGB24 AVPixFormatId (From Bindings.h) + uint32_t XVMCId = 174; // XVMC AVPixFormatId (From Bindings.h) + + uint32_t SrcWidth = 100; + uint32_t SrcHeight = 100; + uint32_t DestWidth = 200; + uint32_t DestHeight = 200; + int32_t Flags = 8; + uint32_t SrcFilterId = 0; + uint32_t DestFilterId = 0; + + // Allocating SWScale... + // Filter ID for source and destination is Null. + { + EXPECT_TRUE(HostFuncSwsGetContext.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + SWScalePtr, SrcWidth, SrcHeight, YUV420PId, DestWidth, DestHeight, + RGB24Id, Flags, SrcFilterId, DestFilterId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + ASSERT_TRUE(readUInt32(MemInst, SWScalePtr) > 0); + } + + uint32_t SWSScaleId = readUInt32(MemInst, SWScalePtr); + ASSERT_TRUE(SWSScaleId > 0); + + // Checking correctness of function. Returns Invalid Argument Error. + FuncInst = SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_scale"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsScale = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsScale &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE( + HostFuncSwsScale.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + SWSScaleId, FrameId, 20, 40, Frame2Id}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), -22); + } + + FuncInst = SWScaleMod->findFuncExports( + "wasmedge_ffmpeg_swscale_sws_getCachedContext"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsGetCachedContext = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsGetCachedContext &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncSwsGetCachedContext.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + SWCachedScalePtr, SWSScaleId, SrcWidth, SrcHeight, YUV420PId, + DestWidth, DestHeight, RGB24Id, Flags, SrcFilterId, DestFilterId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + ASSERT_TRUE(readUInt32(MemInst, SWCachedScalePtr) > 0); + } + + FuncInst = SWScaleMod->findFuncExports( + "wasmedge_ffmpeg_swscale_sws_isSupportedInput"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsIsSupportedInput = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsIsSupportedInput &>( + FuncInst->getHostFunc()); + + { + // AV_PIX_FMT_RGB24 is supported Pixel Format + EXPECT_TRUE(HostFuncSwsIsSupportedInput.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{RGB24Id}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() > 0); + + // AV_PIX_FMT_XVMC is not supported Pixel Format + EXPECT_TRUE(HostFuncSwsIsSupportedInput.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{XVMCId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() == 0); + } + + FuncInst = SWScaleMod->findFuncExports( + "wasmedge_ffmpeg_swscale_sws_isSupportedOutput"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsIsSupportedOutput = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsIsSupportedOutput &>( + FuncInst->getHostFunc()); + + { + // AV_PIX_FMT_RGB24 is supported Pixel Format + EXPECT_TRUE(HostFuncSwsIsSupportedOutput.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{RGB24Id}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() > 0); + + // AV_PIX_FMT_XVMC is not supported Pixel Format + EXPECT_TRUE(HostFuncSwsIsSupportedOutput.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{XVMCId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() == 0); + } + + FuncInst = SWScaleMod->findFuncExports( + "wasmedge_ffmpeg_swscale_sws_isSupportedEndiannessConversion"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsIsSupportedEndiannessConversion = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale:: + SwsIsSupportedEndiannessConversion &>( + FuncInst->getHostFunc()); + + { + // AV_PIX_FMT_XVMC is not supported Pixel Format for + EXPECT_TRUE(HostFuncSwsIsSupportedEndiannessConversion.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{XVMCId}, + Result)); + ASSERT_TRUE(Result[0].get<int32_t>() == 0); + } + + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_freeContext"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsFreeContext = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsFreeContext &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncSwsFreeContext.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{SWSScaleId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + { + uint32_t InvalidDestWidth = -200; + uint32_t InvalidDestHeight = -200; + uint32_t SWScalePtrInvalid = UINT32_C(80); + EXPECT_TRUE(HostFuncSwsGetContext.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + SWScalePtrInvalid, SrcWidth, SrcHeight, YUV420PId, InvalidDestWidth, + InvalidDestHeight, RGB24Id, Flags, SrcFilterId, DestFilterId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), + static_cast<int32_t>(ErrNo::InternalError)); + ASSERT_TRUE(readUInt32(MemInst, SWScalePtrInvalid) == 0); + } +} + +// ============================================================================ +// This test deals with funcs related to SwsFilter. +// ============================================================================ + +TEST_F(FFmpegTest, SwsFilter) { + ASSERT_TRUE(SWScaleMod != nullptr); + auto *FuncInst = SWScaleMod->findFuncExports( + "wasmedge_ffmpeg_swscale_sws_getDefaultFilter"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsGetDefaultFilter = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsGetDefaultFilter &>( + FuncInst->getHostFunc()); + + uint32_t SwsFilterPtr = UINT32_C(40); + { + float LumaGBlur = 10.5; + float ChromaGBlur = 10.5; + float LumaSharpen = 10.5; + float ChromaSharpen = 10.5; + float ChromaHShift = 10.5; + float ChromaVShift = 10.5; + int32_t Verbose = 1; + + EXPECT_TRUE(HostFuncSwsGetDefaultFilter.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + SwsFilterPtr, LumaGBlur, ChromaGBlur, LumaSharpen, ChromaSharpen, + ChromaHShift, ChromaVShift, Verbose}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + ASSERT_TRUE(readUInt32(MemInst, SwsFilterPtr) > 0); + } + + uint32_t FilterId = readUInt32(MemInst, SwsFilterPtr); + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_getLumaH"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsGetLumaH = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsGetLumaH &>( + FuncInst->getHostFunc()); + + uint32_t SwsVectorPtr = UINT32_C(20); + { + EXPECT_TRUE(HostFuncSwsGetLumaH.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FilterId, SwsVectorPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + ASSERT_TRUE(readUInt32(MemInst, SwsVectorPtr) > 0); + } + + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_getLumaV"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsGetLumaV = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsGetLumaV &>( + FuncInst->getHostFunc()); + + { + writeUInt32(MemInst, UINT32_C(0), SwsVectorPtr); + EXPECT_TRUE(HostFuncSwsGetLumaV.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FilterId, SwsVectorPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + ASSERT_TRUE(readUInt32(MemInst, SwsVectorPtr) > 0); + } + + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_getChromaH"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsGetChromaH = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsGetChromaH &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncSwsGetChromaH.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FilterId, SwsVectorPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + ASSERT_TRUE(readUInt32(MemInst, SwsVectorPtr) > 0); + } + + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_getChromaV"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsGetChromaV = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsGetChromaV &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncSwsGetChromaV.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{FilterId, SwsVectorPtr}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + ASSERT_TRUE(readUInt32(MemInst, SwsVectorPtr) > 0); + } + + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_freeFilter"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsFreeFilter = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsFreeFilter &>( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncSwsFreeFilter.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FilterId}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } +} + +// ============================================================================ +// This test deals with funcs related to SwsVector. +// ============================================================================ + +TEST_F(FFmpegTest, SwsVector) { + ASSERT_TRUE(SWScaleMod != nullptr); + uint32_t SwsVectorPtr = UINT32_C(40); + uint32_t CoeffPtr = UINT32_C(100); + + auto *FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_allocVec"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsAllocVec = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsAllocVec &>( + FuncInst->getHostFunc()); + + { + writeUInt32(MemInst, UINT32_C(0), SwsVectorPtr); + int32_t Length = 20; + EXPECT_TRUE(HostFuncSwsAllocVec.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{SwsVectorPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + ASSERT_TRUE(readUInt32(MemInst, SwsVectorPtr) > 0); + } + + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_getGaussianVec"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsGetGaussianVec = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsGetGaussianVec &>( + FuncInst->getHostFunc()); + + { + writeUInt32(MemInst, UINT32_C(0), SwsVectorPtr); + double Variance = 20.5; + double Quality = 4.3; + EXPECT_TRUE(HostFuncSwsGetGaussianVec.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{SwsVectorPtr, Variance, + Quality}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + ASSERT_TRUE(readUInt32(MemInst, SwsVectorPtr) > 0); + } + + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_scaleVec"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsScaleVec = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsScaleVec &>( + FuncInst->getHostFunc()); + + { + uint32_t SwsVecId = readUInt32(MemInst, SwsVectorPtr); + double Scalar = 20.35; + EXPECT_TRUE(HostFuncSwsScaleVec.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{SwsVecId, Scalar}, Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_normalizeVec"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsNormalizeVec = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsNormalizeVec &>( + FuncInst->getHostFunc()); + + { + uint32_t SwsVecId = readUInt32(MemInst, SwsVectorPtr); + double Height = 4.3; + EXPECT_TRUE(HostFuncSwsNormalizeVec.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{SwsVecId, Height}, Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = SWScaleMod->findFuncExports( + "wasmedge_ffmpeg_swscale_sws_getCoeffVecLength"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsGetCoeffVecLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsGetCoeffVecLength &>( + FuncInst->getHostFunc()); + + int Length = 0; + { + uint32_t SwsVecId = readUInt32(MemInst, SwsVectorPtr); + EXPECT_TRUE(HostFuncSwsGetCoeffVecLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{SwsVecId}, + Result)); + Length = Result[0].get<int32_t>(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_getCoeff"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsGetCoeff = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsGetCoeff &>( + FuncInst->getHostFunc()); + + fillMemContent(MemInst, CoeffPtr, Length); + { + uint32_t SwsVecId = readUInt32(MemInst, SwsVectorPtr); + EXPECT_TRUE(HostFuncSwsGetCoeff.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{SwsVecId, CoeffPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_freeVec"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsFreeVec = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwsFreeVec &>( + FuncInst->getHostFunc()); + + { + uint32_t SwsVecId = readUInt32(MemInst, SwsVectorPtr); + EXPECT_TRUE(HostFuncSwsFreeVec.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{SwsVecId}, + Result)); + } +} + +// ============================================================================ +// This test deals with funcs related to Version, Configuration and License +// ============================================================================ + +TEST_F(FFmpegTest, SWScaleVersion) { + ASSERT_TRUE(SWScaleMod != nullptr); + + uint32_t Length = 0; + uint32_t NamePtr = UINT32_C(8); + + auto *FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_swscale_version"); + auto &HostFuncSwscaleVersion = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwscaleVersion &>( + FuncInst->getHostFunc()); + + { + HostFuncSwscaleVersion.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result); + + EXPECT_TRUE(Result[0].get<uint32_t>() > 0); + } + + FuncInst = SWScaleMod->findFuncExports( + "wasmedge_ffmpeg_swscale_swscale_configuration_length"); + auto &HostFuncSwscaleConfigurationLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwscaleConfigurationLength &>( + FuncInst->getHostFunc()); + + { + HostFuncSwscaleConfigurationLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result); + + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + // Testing Version, Configuration, License + // Fill NamePtr with 0. + fillMemContent(MemInst, NamePtr, Length); + FuncInst = SWScaleMod->findFuncExports( + "wasmedge_ffmpeg_swscale_swscale_configuration"); + auto &HostFuncSwscaleConfiguration = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwscaleConfiguration &>( + FuncInst->getHostFunc()); + + { + HostFuncSwscaleConfiguration.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{NamePtr, Length}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } + + FuncInst = SWScaleMod->findFuncExports( + "wasmedge_ffmpeg_swscale_swscale_license_length"); + auto &HostFuncSwscaleLicenseLength = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwscaleLicenseLength &>( + FuncInst->getHostFunc()); + + { + HostFuncSwscaleLicenseLength.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{}, Result); + + Length = Result[0].get<int32_t>(); + EXPECT_TRUE(Length > 0); + } + + // Fill NamePtr with 0. + fillMemContent(MemInst, NamePtr, Length); + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_swscale_license"); + auto &HostFuncSwscaleLicense = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale::SwscaleLicense &>( + FuncInst->getHostFunc()); + + { + HostFuncSwscaleLicense.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{NamePtr, Length}, + Result); + EXPECT_EQ(Result[0].get<int32_t>(), static_cast<int32_t>(ErrNo::Success)); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/utils.cpp b/test/plugins/wasmedge_ffmpeg/utils.cpp new file mode 100644 index 000000000000..2656cbb3805f --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/utils.cpp @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "utils.h" + +#include "avcodec/avCodecContext.h" +#include "avcodec/avPacket.h" +#include "avcodec/avcodec_func.h" +#include "avformat/avStream.h" +#include "avformat/avformat_func.h" +#include "avutil/avDictionary.h" +#include "avutil/avFrame.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +void FFmpegTest::initEmptyFrame(uint32_t FramePtr) { + auto *FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_alloc"); + auto &HostFuncAVFrameAlloc = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVFrameAlloc &>( + FuncInst->getHostFunc()); + HostFuncAVFrameAlloc.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{FramePtr}, Result); +} + +void FFmpegTest::initFFmpegStructs(uint32_t AVCodecPtr, uint32_t AVFormatCtxPtr, + uint32_t FilePtr, std::string FileName, + uint32_t CodecParameterPtr, + uint32_t AVCodecCtxPtr, uint32_t PacketPtr, + uint32_t FramePtr) { + initFormatCtx(AVFormatCtxPtr, FilePtr, FileName); + + uint32_t AvFormatCtxId = readUInt32(MemInst, AVFormatCtxPtr); + + auto *FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_av_find_best_stream"); + auto &HostFuncAVFindBestStream = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFindBestStream &>( + FuncInst->getHostFunc()); + uint32_t MediaTypeId = 0; // Video + uint32_t WantedStream = -1; + uint32_t RelatedStream = -1; + uint32_t DecoderRetId = 0; + uint32_t Flags = 0; + HostFuncAVFindBestStream.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + AvFormatCtxId, MediaTypeId, WantedStream, + RelatedStream, DecoderRetId, Flags}, + Result); + + uint32_t StreamIdx = Result[0].get<int32_t>(); + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avStream_codecpar"); + + auto &HostFuncAVStreamCodecpar = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVStreamCodecPar &>( + FuncInst->getHostFunc()); + + HostFuncAVStreamCodecpar.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + AvFormatCtxId, StreamIdx, CodecParameterPtr}, + Result); + + uint32_t CodecParametersId = readUInt32(MemInst, CodecParameterPtr); + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_alloc_context3"); + auto &HostFuncAVCodecAllocContext3 = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecAllocContext3 &>( + FuncInst->getHostFunc()); + + HostFuncAVCodecAllocContext3.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{0, AVCodecCtxPtr}, + Result); + + uint32_t AVCodecCtxId = readUInt32(MemInst, AVCodecCtxPtr); + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_parameters_to_context"); + auto &HostFuncAVCodecParametersToContext = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecParametersToContext &>( + FuncInst->getHostFunc()); + + HostFuncAVCodecParametersToContext.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, + CodecParametersId}, + Result); + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_codec_id"); + auto &HostFuncAVCodecContextCodecId = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecCtxCodecID &>( + FuncInst->getHostFunc()); + + HostFuncAVCodecContextCodecId.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId}, + Result); + + uint32_t CodecId = Result[0].get<int32_t>(); + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_find_decoder"); + auto &HostFuncAVCodecFindDecoder = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecFindDecoder &>( + FuncInst->getHostFunc()); + + HostFuncAVCodecFindDecoder.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{CodecId, AVCodecPtr}, Result); + + uint32_t AVCodecId = readUInt32(MemInst, AVCodecPtr); + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_open2"); + auto &HostFuncAVCodecOpen2 = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecOpen2 &>( + FuncInst->getHostFunc()); + + HostFuncAVCodecOpen2.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, AVCodecId, 0}, + Result); + + initEmptyFrame(FramePtr); + uint32_t FrameId = readUInt32(MemInst, FramePtr); + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_receive_frame"); + auto &HostFuncAVCodecReceiveFrame = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecReceiveFrame &>( + FuncInst->getHostFunc()); + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_av_read_frame"); + auto &HostFuncAVReadFrame = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVReadFrame &>( + FuncInst->getHostFunc()); + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodec_send_packet"); + auto &HostFuncAVCodecSendPacket = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVCodecSendPacket &>( + FuncInst->getHostFunc()); + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_av_packet_stream_index"); + auto &HostFuncAVPacketStreamIndex = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketStreamIndex &>( + FuncInst->getHostFunc()); + + while (true) { + HostFuncAVCodecReceiveFrame.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, FrameId}, + Result); + + // Error returned by FFmpeg are negative. + int32_t Error = Result[0].get<int32_t>() * (-1); + + if (Error == EAGAIN) { + while (true) { + allocPacket(PacketPtr); + + uint32_t PackedId = readUInt32(MemInst, PacketPtr); + + while (true) { + HostFuncAVReadFrame.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + AvFormatCtxId, PackedId}, + Result); + + int32_t Res = Result[0].get<int32_t>(); + if (Res == 0 || Res == AVERROR_EOF) { + break; + } + } + + HostFuncAVPacketStreamIndex.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, FrameId}, + Result); + + uint32_t PacketStreamIdx = Result[0].get<int32_t>(); + + if (PacketStreamIdx != StreamIdx) { + continue; + } + + HostFuncAVCodecSendPacket.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{AVCodecCtxId, PackedId}, + Result); + break; + } + } else { + break; + } + } +} + +void FFmpegTest::initFormatCtx(uint32_t AVFormatCtxPtr, uint32_t FilePtr, + std::string FileName) { + int32_t Length = FileName.length(); + fillMemContent(MemInst, FilePtr, Length); + fillMemContent(MemInst, FilePtr, FileName); + + auto *FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avformat_open_input"); + auto &HostFuncAVFormatOpenInput = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::AVFormatOpenInput &>( + FuncInst->getHostFunc()); + HostFuncAVFormatOpenInput.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + AVFormatCtxPtr, FilePtr, Length, UINT32_C(0), UINT32_C(0)}, + Result); +} + +void FFmpegTest::initDict(uint32_t DictPtr, uint32_t KeyPtr, std::string Key, + uint32_t ValuePtr, std::string Value) { + uint32_t KeyLen = Key.length(); + uint32_t ValueLen = Value.length(); + fillMemContent(MemInst, KeyPtr, KeyLen + ValueLen); + fillMemContent(MemInst, KeyPtr, Key); + fillMemContent(MemInst, ValuePtr, Value); + + auto *FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_dict_set"); + auto &HostFuncAVDictSet = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::AVDictSet &>( + FuncInst->getHostFunc()); + + HostFuncAVDictSet.run(CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + DictPtr, KeyPtr, KeyLen, ValuePtr, ValueLen, 0}, + Result); +} + +void FFmpegTest::allocPacket(uint32_t PacketPtr) { + auto *FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_alloc"); + auto &HostFuncAVPacketAlloc = + dynamic_cast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::AVPacketAlloc &>( + FuncInst->getHostFunc()); + + HostFuncAVPacketAlloc.run( + CallFrame, std::initializer_list<WasmEdge::ValVariant>{PacketPtr}, + Result); +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_ffmpeg/utils.h b/test/plugins/wasmedge_ffmpeg/utils.h new file mode 100644 index 000000000000..ce4d771c4ec4 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/utils.h @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "avcodec/module.h" +#include "avfilter/module.h" +#include "avformat/module.h" +#include "avutil/module.h" +#include "swresample/module.h" +#include "swscale/module.h" + +#include "common/types.h" +#include "runtime/callingframe.h" +#include "runtime/instance/module.h" + +#include <gtest/gtest.h> +#include <memory> + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +template <typename T, typename U> +inline std::unique_ptr<T> dynamicPointerCast(std::unique_ptr<U> &&R) noexcept { + static_assert(std::has_virtual_destructor_v<T>); + T *P = dynamic_cast<T *>(R.get()); + if (P) { + R.release(); + } + return std::unique_ptr<T>(P); +} + +inline void writeUInt32(WasmEdge::Runtime::Instance::MemoryInstance *MemInst, + uint32_t Value, uint32_t &Ptr) { + uint32_t *BufPtr = MemInst->getPointer<uint32_t *>(Ptr); + *BufPtr = Value; +} + +inline void fillMemContent(WasmEdge::Runtime::Instance::MemoryInstance *MemInst, + uint32_t Offset, uint32_t Cnt, + uint8_t C = 0) noexcept { + std::fill_n(MemInst->getPointer<uint8_t *>(Offset), Cnt, C); +} + +inline void fillMemContent(WasmEdge::Runtime::Instance::MemoryInstance *MemInst, + uint32_t Offset, std::string_view Str) noexcept { + char *Buf = MemInst->getPointer<char *>(Offset); + std::copy_n(Str.data(), Str.length(), Buf); +} + +inline void writeSInt32(WasmEdge::Runtime::Instance::MemoryInstance *MemInst, + int32_t Value, uint32_t &Ptr) { + int32_t *BufPtr = MemInst->getPointer<int32_t *>(Ptr); + *BufPtr = Value; +} + +inline int32_t readSInt32(WasmEdge::Runtime::Instance::MemoryInstance *MemInst, + uint32_t &Ptr) { + int32_t *BufPtr = MemInst->getPointer<int32_t *>(Ptr); + return *BufPtr; +} + +inline uint32_t readUInt32(WasmEdge::Runtime::Instance::MemoryInstance *MemInst, + uint32_t &Ptr) { + uint32_t *BufPtr = MemInst->getPointer<uint32_t *>(Ptr); + return *BufPtr; +} + +class FFmpegTest : public ::testing::Test { +public: + FFmpegTest() : Mod(""), CallFrame(nullptr, &Mod) { + Mod.addHostMemory( + "memory", std::make_unique<WasmEdge::Runtime::Instance::MemoryInstance>( + WasmEdge::AST::MemoryType(1))); + MemInst = Mod.findMemoryExports("memory"); + + using namespace std::literals::string_view_literals; + WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( + "../../../plugins/wasmedge_ffmpeg/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasmEdgeFFmpeg" WASMEDGE_LIB_EXTENSION)); + if (const auto *Plugin = + WasmEdge::Plugin::Plugin::find("wasmedge_ffmpeg"sv)) { + if (const auto *Module = + Plugin->findModule("wasmedge_ffmpeg_avformat"sv)) { + AVFormatMod = + dynamicPointerCast<WasmEdge::Host::WasmEdgeFFmpeg::AVFormat:: + WasmEdgeFFmpegAVFormatModule>( + Module->create()); + } + if (const auto *Module = Plugin->findModule("wasmedge_ffmpeg_avutil"sv)) { + AVUtilMod = dynamicPointerCast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::WasmEdgeFFmpegAVUtilModule>( + Module->create()); + } + if (const auto *Module = + Plugin->findModule("wasmedge_ffmpeg_swscale"sv)) { + SWScaleMod = + dynamicPointerCast<WasmEdge::Host::WasmEdgeFFmpeg::SWScale:: + WasmEdgeFFmpegSWScaleModule>( + Module->create()); + } + if (const auto *Module = + Plugin->findModule("wasmedge_ffmpeg_avcodec"sv)) { + AVCodecMod = + dynamicPointerCast<WasmEdge::Host::WasmEdgeFFmpeg::AVcodec:: + WasmEdgeFFmpegAVCodecModule>( + Module->create()); + } + if (const auto *Module = + Plugin->findModule("wasmedge_ffmpeg_swresample"sv)) { + SWResampleMod = + dynamicPointerCast<WasmEdge::Host::WasmEdgeFFmpeg::SWResample:: + WasmEdgeFFmpegSWResampleModule>( + Module->create()); + } + if (const auto *Module = + Plugin->findModule("wasmedge_ffmpeg_avfilter"sv)) { + AVFilterMod = + dynamicPointerCast<WasmEdge::Host::WasmEdgeFFmpeg::AVFilter:: + WasmEdgeFFmpegAVFilterModule>( + Module->create()); + } + } + } + +protected: + void initEmptyFrame(uint32_t FramePtr); + + void initDict(uint32_t DictPtr, uint32_t KeyPtr, std::string Key, + uint32_t ValuePtr, std::string Value); + void initFFmpegStructs(uint32_t AVCodecPtr, uint32_t AVFormatCtxPtr, + uint32_t FilePtr, std::string FileName, + uint32_t CodecParameterPtr, uint32_t AVCodecCtxPtr, + uint32_t PacketPtr, uint32_t FramePtr); + + void initFormatCtx(uint32_t AVFormatCtxPtr, uint32_t FilePtr, + std::string FileName); + void allocPacket(uint32_t PacketPtr); + + // Result of Funcs to be stored here. + std::array<WasmEdge::ValVariant, 1> Result = {UINT32_C(0)}; + + // Create the calling frame with memory instance. + WasmEdge::Runtime::Instance::ModuleInstance Mod; + WasmEdge::Runtime::Instance::MemoryInstance *MemInst; + WasmEdge::Runtime::CallingFrame CallFrame; + + // Wasm Modules. + std::unique_ptr< + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::WasmEdgeFFmpegAVFormatModule> + AVFormatMod; + std::unique_ptr< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::WasmEdgeFFmpegAVUtilModule> + AVUtilMod; + std::unique_ptr<WasmEdge::Host::WasmEdgeFFmpeg::SWResample:: + WasmEdgeFFmpegSWResampleModule> + SWResampleMod; + std::unique_ptr< + WasmEdge::Host::WasmEdgeFFmpeg::SWScale::WasmEdgeFFmpegSWScaleModule> + SWScaleMod; + std::unique_ptr< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::WasmEdgeFFmpegAVCodecModule> + AVCodecMod; + std::unique_ptr< + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::WasmEdgeFFmpegAVFilterModule> + AVFilterMod; +}; + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_image/CMakeLists.txt b/test/plugins/wasmedge_image/CMakeLists.txt index 83a809496b68..62e1bd2541bc 100644 --- a/test/plugins/wasmedge_image/CMakeLists.txt +++ b/test/plugins/wasmedge_image/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeImageTests wasmedge_image.cpp diff --git a/test/plugins/wasmedge_image/wasmedge_image.cpp b/test/plugins/wasmedge_image/wasmedge_image.cpp index 0583c1c762fc..be767b4ee490 100644 --- a/test/plugins/wasmedge_image/wasmedge_image.cpp +++ b/test/plugins/wasmedge_image/wasmedge_image.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #include "image_func.h" @@ -10,35 +10,47 @@ #include <array> #include <cstdint> #include <gtest/gtest.h> +#include <memory> #include <string> #include <vector> namespace { -WasmEdge::Runtime::Instance::ModuleInstance *createModule() { + +template <typename T, typename U> +inline std::unique_ptr<T> dynamicPointerCast(std::unique_ptr<U> &&R) noexcept { + static_assert(std::has_virtual_destructor_v<T>); + T *P = dynamic_cast<T *>(R.get()); + if (P) { + R.release(); + } + return std::unique_ptr<T>(P); +} + +std::unique_ptr<WasmEdge::Host::WasmEdgeImageModule> createModule() { using namespace std::literals::string_view_literals; WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "../../../plugins/wasmedge_image/" - "libwasmedgePluginWasmEdgeImage" WASMEDGE_LIB_EXTENSION)); + "../../../plugins/wasmedge_image/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasmEdgeImage" WASMEDGE_LIB_EXTENSION)); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasmedge_image"sv)) { if (const auto *Module = Plugin->findModule("wasmedge_image"sv)) { - return Module->create().release(); + return dynamicPointerCast<WasmEdge::Host::WasmEdgeImageModule>( + Module->create()); } } - return nullptr; + return {}; } + } // namespace // TODO: unit tests for every functions. TEST(WasmEdgeImageTest, Module) { // Create the wasmedge_image module instance. - auto *ImgMod = - dynamic_cast<WasmEdge::Host::WasmEdgeImageModule *>(createModule()); - EXPECT_FALSE(ImgMod == nullptr); + auto ImgMod = createModule(); + ASSERT_TRUE(ImgMod); EXPECT_EQ(ImgMod->getFuncExportNum(), 2U); EXPECT_NE(ImgMod->findFuncExports("load_jpg"), nullptr); EXPECT_NE(ImgMod->findFuncExports("load_png"), nullptr); - delete ImgMod; } GTEST_API_ int main(int argc, char **argv) { diff --git a/test/plugins/wasmedge_llmc/CMakeLists.txt b/test/plugins/wasmedge_llmc/CMakeLists.txt new file mode 100644 index 000000000000..7fce5e8a63d9 --- /dev/null +++ b/test/plugins/wasmedge_llmc/CMakeLists.txt @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +wasmedge_add_executable(wasmedgeLLMCTests + wasmedge_llmc.cpp +) + +add_dependencies(wasmedgeLLMCTests + wasmedgePluginWasmEdgeLLMC +) + +target_include_directories(wasmedgeLLMCTests + PUBLIC + $<TARGET_PROPERTY:wasmedgePlugin,INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:wasmedgePluginWasmEdgeLLMC,INCLUDE_DIRECTORIES> +) + +target_link_libraries(wasmedgeLLMCTests + PRIVATE + ${GTEST_BOTH_LIBRARIES} +) + +# Link to the WasmEdge library +if(WASMEDGE_LINK_PLUGINS_STATIC) + target_link_libraries(wasmedgeLLMCTests + PRIVATE + wasmedgeCAPI + ) +else() + target_link_libraries(wasmedgeLLMCTests + PRIVATE + wasmedge_shared + ) +endif() + +function(download URL OUTPUT HASH) + file(DOWNLOAD + ${URL} + ${OUTPUT} + SHOW_PROGRESS + EXPECTED_HASH ${HASH} + ) +endfunction() + +message(STATUS "Downloading GPT2 model check point to ${CMAKE_CURRENT_BINARY_DIR}/gpt2_124M.bin") +if (WASMEDGE_PLUGIN_LLMC_CUDA) + download( + https://huggingface.co/datasets/karpathy/llmc-starter-pack/resolve/main/gpt2_124M_bf16.bin + ${CMAKE_CURRENT_BINARY_DIR}/wasmedge_llmc/gpt2_124M.bin + SHA256=6661f45628102b4c6e86835d9057b5ba2c024dbf9b81445175e258b7878a1a6f + ) +else() + download( + https://huggingface.co/datasets/karpathy/llmc-starter-pack/resolve/main/gpt2_124M.bin + ${CMAKE_CURRENT_BINARY_DIR}/wasmedge_llmc/gpt2_124M.bin + SHA256=3da8b207584030bcdcd207cf7a99952e3421dce92da218b351071857511bf162 + ) +endif() +message(STATUS "Downloading training dataset to ${CMAKE_CURRENT_BINARY_DIR}/tiny_shakespeare_train.bin") +download( + https://huggingface.co/datasets/karpathy/llmc-starter-pack/resolve/main/tiny_shakespeare_train.bin + ${CMAKE_CURRENT_BINARY_DIR}/wasmedge_llmc/tiny_shakespeare_train.bin + SHA256=8a70606be574040c26d225694f5f9759973b419852d22f7fe5c118e1b359dcc8 +) +message(STATUS "Downloading validation dataset to ${CMAKE_CURRENT_BINARY_DIR}/tiny_shakespeare_val.bin") +download( + https://huggingface.co/datasets/karpathy/llmc-starter-pack/resolve/main/tiny_shakespeare_val.bin + ${CMAKE_CURRENT_BINARY_DIR}/wasmedge_llmc/tiny_shakespeare_val.bin + SHA256=fe99db720dc7c83e694806d4e047a952909411da1daccde4ccc2e55f40882a62 +) +message(STATUS "Downloading tokenizer data to ${CMAKE_CURRENT_BINARY_DIR}/gpt2_tokenizer.bin") +download( + https://huggingface.co/datasets/karpathy/llmc-starter-pack/resolve/main/gpt2_tokenizer.bin + ${CMAKE_CURRENT_BINARY_DIR}/wasmedge_llmc/gpt2_tokenizer.bin + SHA256=6f3abc21e444e4e8300e225f4e03da48ea121cf17e30f67009b8dad7a66c2f13 +) + +add_test(wasmedgeLLMCTests wasmedgeLLMCTests) diff --git a/test/plugins/wasmedge_llmc/wasmedge_llmc.cpp b/test/plugins/wasmedge_llmc/wasmedge_llmc.cpp new file mode 100644 index 000000000000..4fcbff20bfca --- /dev/null +++ b/test/plugins/wasmedge_llmc/wasmedge_llmc.cpp @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "llmc_func.h" +#include "llmc_module.h" + +#include "common/defines.h" +#include "common/types.h" +#include "plugin/plugin.h" +#include "runtime/callingframe.h" +#include "runtime/instance/module.h" + +#include <algorithm> +#include <array> +#include <cstdint> +#include <gtest/gtest.h> +#include <initializer_list> +#include <memory> +#include <string> +#include <vector> + +using WasmEdge::Host::WasmEdgeLLMC::ErrNo; + +namespace { + +template <typename T, typename U> +inline std::unique_ptr<T> dynamicPointerCast(std::unique_ptr<U> &&R) noexcept { + static_assert(std::has_virtual_destructor_v<T>); + T *P = dynamic_cast<T *>(R.get()); + if (P) { + R.release(); + } + return std::unique_ptr<T>(P); +} + +std::unique_ptr<WasmEdge::Host::WasmEdgeLLMCModule> createModule() { + using namespace std::literals::string_view_literals; + WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( + "../../../plugins/wasmedge_llmc/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasmEdgeLLMC" WASMEDGE_LIB_EXTENSION)); + if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasmedge_llmc"sv)) { + if (const auto *Module = Plugin->findModule("wasmedge_llmc"sv)) { + return dynamicPointerCast<WasmEdge::Host::WasmEdgeLLMCModule>( + Module->create()); + } + } + return {}; +} +} // namespace + +template <typename T> +void writeBinaries(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, + WasmEdge::Span<const T> Binaries, uint32_t Ptr) noexcept { + std::copy(Binaries.begin(), Binaries.end(), MemInst.getPointer<T *>(Ptr)); +} + +void writeUInt32(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, + uint32_t Value, uint32_t &Ptr) { + uint32_t *BufPtr = MemInst.getPointer<uint32_t *>(Ptr); + *BufPtr = Value; + Ptr += 4; +} + +TEST(WasmEdgeLLMTest, TrainGPT2) { + // Create wasmedge_llmc module instance. + auto LLMCMod = createModule(); + ASSERT_TRUE(LLMCMod); + EXPECT_EQ(LLMCMod->getFuncExportNum(), 4U); + + // Create the calling frame with memory instance. + WasmEdge::Runtime::Instance::ModuleInstance Mod(""); + Mod.addHostMemory( + "memory", std::make_unique<WasmEdge::Runtime::Instance::MemoryInstance>( + WasmEdge::AST::MemoryType(60000))); + auto *MemInstPtr = Mod.findMemoryExports("memory"); + EXPECT_NE(MemInstPtr, nullptr); + auto &MemInst = *MemInstPtr; + WasmEdge::Runtime::CallingFrame CallFrame(nullptr, &Mod); + + auto *ModelCreate = LLMCMod->findFuncExports("model_create"); + EXPECT_NE(ModelCreate, nullptr); + EXPECT_TRUE(ModelCreate->isHostFunction()); + auto &HostFuncModelCreate = + dynamic_cast<WasmEdge::Host::WasmEdgeLLMC::ModelCreate &>( + ModelCreate->getHostFunc()); + + auto *DataLoaderCreate = LLMCMod->findFuncExports("dataloader_create"); + EXPECT_NE(DataLoaderCreate, nullptr); + EXPECT_TRUE(DataLoaderCreate->isHostFunction()); + auto &HostFuncDataLoadereCreate = + dynamic_cast<WasmEdge::Host::WasmEdgeLLMC::DataLoaderCreate &>( + DataLoaderCreate->getHostFunc()); + + auto *TokenizerCreate = LLMCMod->findFuncExports("tokenizer_create"); + EXPECT_NE(TokenizerCreate, nullptr); + EXPECT_TRUE(TokenizerCreate->isHostFunction()); + auto &HostFuncTokenizerCreate = + dynamic_cast<WasmEdge::Host::WasmEdgeLLMC::TokenizerCreate &>( + TokenizerCreate->getHostFunc()); + + auto *ModelTrain = LLMCMod->findFuncExports("model_train"); + EXPECT_NE(ModelTrain, nullptr); + EXPECT_TRUE(ModelTrain->isHostFunction()); + auto &HostFuncModelTrain = + dynamic_cast<WasmEdge::Host::WasmEdgeLLMC::ModelTrain &>( + ModelTrain->getHostFunc()); + + std::array<WasmEdge::ValVariant, 1> Errno = {UINT32_C(0)}; + + std::string CheckPointString = "./wasmedge_llmc/gpt2_124M.bin"; + std::vector<char> CheckPointPath(CheckPointString.begin(), + CheckPointString.end()); + uint32_t CheckPointPathPtr = UINT32_C(0); + writeBinaries<char>(MemInst, CheckPointPath, CheckPointPathPtr); + + std::string TrainDataString = "./wasmedge_llmc/tiny_shakespeare_train.bin"; + std::vector<char> TrainDataPath(TrainDataString.begin(), + TrainDataString.end()); + uint32_t TrainDataPathPtr = CheckPointPathPtr + CheckPointPath.size(); + writeBinaries<char>(MemInst, TrainDataPath, TrainDataPathPtr); + + std::string ValDataString = "./wasmedge_llmc/tiny_shakespeare_val.bin"; + std::vector<char> ValDataPath(ValDataString.begin(), ValDataString.end()); + uint32_t ValDataPathPtr = TrainDataPathPtr + TrainDataPath.size(); + writeBinaries<char>(MemInst, ValDataPath, ValDataPathPtr); + + std::string TokenizerBin = "./wasmedge_llmc/gpt2_tokenizer.bin"; + std::vector<char> TokenizerBinPath(TokenizerBin.begin(), TokenizerBin.end()); + uint32_t TokenizerBinPtr = ValDataPathPtr + ValDataPath.size(); + writeBinaries<char>(MemInst, TokenizerBinPath, TokenizerBinPtr); + + uint32_t ModelIdPtr = UINT32_C(0); + uint32_t ModelId = UINT32_C(0); + uint32_t TrainDataLoaderIdPtr = UINT32_C(0); + uint32_t TrainDataLoaderId = UINT32_C(0); + uint32_t ValDataLoaderIdPtr = UINT32_C(0); + uint32_t ValDataLoaderId = UINT32_C(0); + uint32_t TokenizerIdPtr = UINT32_C(0); + uint32_t TokenizerId = UINT32_C(0); + + { + EXPECT_TRUE(HostFuncModelCreate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + CheckPointPathPtr, static_cast<uint32_t>(CheckPointPath.size()), + ModelIdPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + ModelId = *MemInst.getPointer<uint32_t *>(ModelIdPtr); + EXPECT_EQ(ModelId, 0); + } + + { + EXPECT_TRUE(HostFuncDataLoadereCreate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + TrainDataPathPtr, static_cast<uint32_t>(TrainDataPath.size()), + /*B*/ 4, + /*T*/ 64, + /*ProcessRank*/ 0, + /*NumProcesses*/ 1, + /*ShouldShuffle*/ 1, TrainDataLoaderIdPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + TrainDataLoaderId = *MemInst.getPointer<uint32_t *>(TrainDataLoaderIdPtr); + EXPECT_EQ(TrainDataLoaderId, 0); + } + + { + EXPECT_TRUE(HostFuncDataLoadereCreate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + ValDataPathPtr, static_cast<uint32_t>(ValDataPath.size()), + /*B*/ 4, + /*T*/ 64, + /*ProcessRank*/ 0, + /*NumProcesses*/ 1, + /*ShouldShuffle*/ 0, ValDataLoaderIdPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + ValDataLoaderId = *MemInst.getPointer<uint32_t *>(ValDataLoaderIdPtr); + EXPECT_EQ(ValDataLoaderId, 1); + } + + { + EXPECT_TRUE(HostFuncTokenizerCreate.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + TokenizerBinPtr, static_cast<uint32_t>(TokenizerBinPath.size()), + TokenizerIdPtr}, + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + TokenizerId = *MemInst.getPointer<uint32_t *>(TokenizerIdPtr); + EXPECT_EQ(TokenizerId, 0); + } + + { + + EXPECT_TRUE(HostFuncModelTrain.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + ModelId, TrainDataLoaderId, ValDataLoaderId, TokenizerId, + /*B*/ 4, + /*T*/ 64, + /*Lr*/ 1e-4f, + /*Epoch*/ 20}, + Errno)); + } +} + +GTEST_API_ int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/plugins/wasmedge_opencvmini/CMakeLists.txt b/test/plugins/wasmedge_opencvmini/CMakeLists.txt index 33fc142509f7..9f0946f2a962 100644 --- a/test/plugins/wasmedge_opencvmini/CMakeLists.txt +++ b/test/plugins/wasmedge_opencvmini/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2023 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeOpencvminiTests wasmedge_opencvmini.cpp diff --git a/test/plugins/wasmedge_opencvmini/wasmedge_opencvmini.cpp b/test/plugins/wasmedge_opencvmini/wasmedge_opencvmini.cpp index 926e1330f2b6..d2905c806cc1 100644 --- a/test/plugins/wasmedge_opencvmini/wasmedge_opencvmini.cpp +++ b/test/plugins/wasmedge_opencvmini/wasmedge_opencvmini.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #include "opencvmini_func.h" @@ -14,34 +14,45 @@ #include <vector> namespace { -WasmEdge::Runtime::Instance::ModuleInstance *createModule() { + +template <typename T, typename U> +inline std::unique_ptr<T> dynamicPointerCast(std::unique_ptr<U> &&R) noexcept { + static_assert(std::has_virtual_destructor_v<T>); + T *P = dynamic_cast<T *>(R.get()); + if (P) { + R.release(); + } + return std::unique_ptr<T>(P); +} + +std::unique_ptr<WasmEdge::Host::WasmEdgeOpenCVMiniModule> createModule() { using namespace std::literals::string_view_literals; WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "../../../plugins/wasmedge_opencvmini/" - "libwasmedgePluginWasmEdgeOpenCVMini" WASMEDGE_LIB_EXTENSION)); + "../../../plugins/wasmedge_opencvmini/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasmEdgeOpenCVMini" WASMEDGE_LIB_EXTENSION)); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasmedge_opencvmini"sv)) { if (const auto *Module = Plugin->findModule("wasmedge_opencvmini"sv)) { - return Module->create().release(); + return dynamicPointerCast<WasmEdge::Host::WasmEdgeOpenCVMiniModule>( + Module->create()); } } - return nullptr; + return {}; } + } // namespace // TODO: unit tests for every functions. TEST(WasmEdgeOpecvminiTest, Module) { // Create the wasmedge_opencvmini module instance. - auto *ImgMod = - dynamic_cast<WasmEdge::Host::WasmEdgeOpenCVMiniModule *>(createModule()); - EXPECT_FALSE(ImgMod == nullptr); + auto ImgMod = createModule(); + ASSERT_TRUE(ImgMod); EXPECT_EQ(ImgMod->getFuncExportNum(), 19U); EXPECT_NE(ImgMod->findFuncExports("wasmedge_opencvmini_imdecode"), nullptr); EXPECT_NE(ImgMod->findFuncExports("wasmedge_opencvmini_imencode"), nullptr); EXPECT_NE(ImgMod->findFuncExports("wasmedge_opencvmini_rectangle"), nullptr); EXPECT_NE(ImgMod->findFuncExports("wasmedge_opencvmini_cvt_color"), nullptr); - delete ImgMod; } GTEST_API_ int main(int argc, char **argv) { diff --git a/test/plugins/wasmedge_process/CMakeLists.txt b/test/plugins/wasmedge_process/CMakeLists.txt index ee34f5c1f9e9..fc389115d70c 100644 --- a/test/plugins/wasmedge_process/CMakeLists.txt +++ b/test/plugins/wasmedge_process/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeProcessTests wasmedge_process.cpp diff --git a/test/plugins/wasmedge_process/wasmedge_process.cpp b/test/plugins/wasmedge_process/wasmedge_process.cpp index 9c25f41233ed..d74e245f6588 100644 --- a/test/plugins/wasmedge_process/wasmedge_process.cpp +++ b/test/plugins/wasmedge_process/wasmedge_process.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #include "processfunc.h" @@ -10,24 +10,38 @@ #include <array> #include <cstdint> #include <gtest/gtest.h> +#include <memory> #include <string> +#include <string_view> #include <vector> namespace { + WasmEdge::Runtime::CallingFrame DummyCallFrame(nullptr, nullptr); -WasmEdge::Runtime::Instance::ModuleInstance *createModule() { +template <typename T, typename U> +inline std::unique_ptr<T> dynamicPointerCast(std::unique_ptr<U> &&R) noexcept { + static_assert(std::has_virtual_destructor_v<T>); + T *P = dynamic_cast<T *>(R.get()); + if (P) { + R.release(); + } + return std::unique_ptr<T>(P); +} + +std::unique_ptr<WasmEdge::Host::WasmEdgeProcessModule> createModule() { using namespace std::literals::string_view_literals; WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "../../../plugins/wasmedge_process/" - "libwasmedgePluginWasmEdgeProcess" WASMEDGE_LIB_EXTENSION)); + "../../../plugins/wasmedge_process/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasmEdgeProcess" WASMEDGE_LIB_EXTENSION)); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasmedge_process"sv)) { if (const auto *Module = Plugin->findModule("wasmedge_process"sv)) { - return Module->create().release(); + return dynamicPointerCast<WasmEdge::Host::WasmEdgeProcessModule>( + Module->create()); } } - return nullptr; + return {}; } void fillMemContent(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, @@ -36,17 +50,18 @@ void fillMemContent(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, } void fillMemContent(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, - uint32_t Offset, const std::string &Str) noexcept { + uint32_t Offset, std::string_view Str) noexcept { char *Buf = MemInst.getPointer<char *>(Offset); - std::copy_n(Str.c_str(), Str.length(), Buf); + std::copy_n(Str.data(), Str.length(), Buf); } } // namespace +using namespace std::literals::string_view_literals; + TEST(WasmEdgeProcessTest, SetProgName) { // Create the wasmedge_process module instance. - auto *ProcMod = - dynamic_cast<WasmEdge::Host::WasmEdgeProcessModule *>(createModule()); - ASSERT_TRUE(ProcMod != nullptr); + auto ProcMod = createModule(); + ASSERT_TRUE(ProcMod); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -61,7 +76,7 @@ TEST(WasmEdgeProcessTest, SetProgName) { // Clear the memory[0, 64]. fillMemContent(MemInst, 0, 64); // Set the memory[0, 4] as string "echo". - fillMemContent(MemInst, 0, std::string("echo")); + fillMemContent(MemInst, 0, "echo"sv); // Get the function "wasmedge_process_set_prog_name". auto *FuncInst = ProcMod->findFuncExports("wasmedge_process_set_prog_name"); @@ -83,15 +98,12 @@ TEST(WasmEdgeProcessTest, SetProgName) { DummyCallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(0), UINT32_C(4)}, {})); - - delete ProcMod; } TEST(WasmEdgeProcessTest, AddArg) { // Create the wasmedge_process module instance. - auto *ProcMod = - dynamic_cast<WasmEdge::Host::WasmEdgeProcessModule *>(createModule()); - ASSERT_TRUE(ProcMod != nullptr); + auto ProcMod = createModule(); + ASSERT_TRUE(ProcMod); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -106,11 +118,11 @@ TEST(WasmEdgeProcessTest, AddArg) { // Clear the memory[0, 64]. fillMemContent(MemInst, 0, 64); // Set the memory[0, 4] as string "echo". - fillMemContent(MemInst, 0, std::string("arg1")); + fillMemContent(MemInst, 0, "arg1"sv); // Set the memory[4, 8] as string "arg2". - fillMemContent(MemInst, 4, std::string("arg2")); + fillMemContent(MemInst, 4, "arg2"sv); // Set the memory[30, 41] as string "--final-arg". - fillMemContent(MemInst, 30, std::string("--final-arg")); + fillMemContent(MemInst, 30, "--final-arg"sv); // Get the function "wasmedge_process_add_arg". auto *FuncInst = ProcMod->findFuncExports("wasmedge_process_add_arg"); @@ -148,15 +160,12 @@ TEST(WasmEdgeProcessTest, AddArg) { DummyCallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(0), UINT32_C(4)}, {})); - - delete ProcMod; } TEST(WasmEdgeProcessTest, AddEnv) { // Create the wasmedge_process module instance. - auto *ProcMod = - dynamic_cast<WasmEdge::Host::WasmEdgeProcessModule *>(createModule()); - ASSERT_TRUE(ProcMod != nullptr); + auto ProcMod = createModule(); + ASSERT_TRUE(ProcMod); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -171,13 +180,13 @@ TEST(WasmEdgeProcessTest, AddEnv) { // Clear the memory[0, 256]. fillMemContent(MemInst, 0, 256); // Set the memory[0, 4] as string "ENV1". - fillMemContent(MemInst, 0, std::string("ENV1")); + fillMemContent(MemInst, 0, "ENV1"sv); // Set the memory[4, 10] as string "VALUE1". - fillMemContent(MemInst, 4, std::string("VALUE1")); + fillMemContent(MemInst, 4, "VALUE1"sv); // Set the memory[30, 45] as string "LD_LIBRARY_PATH". - fillMemContent(MemInst, 30, std::string("LD_LIBRARY_PATH")); + fillMemContent(MemInst, 30, "LD_LIBRARY_PATH"sv); // Set the memory[50, 64] as string "/usr/local/lib". - fillMemContent(MemInst, 50, std::string("/usr/local/lib")); + fillMemContent(MemInst, 50, "/usr/local/lib"sv); // Get the function "wasmedge_process_add_env". auto *FuncInst = ProcMod->findFuncExports("wasmedge_process_add_env"); @@ -210,15 +219,12 @@ TEST(WasmEdgeProcessTest, AddEnv) { std::initializer_list<WasmEdge::ValVariant>{ UINT32_C(0), UINT32_C(4), UINT32_C(4), UINT32_C(6)}, {})); - - delete ProcMod; } TEST(WasmEdgeProcessTest, AddStdIn) { // Create the wasmedge_process module instance. - auto *ProcMod = - dynamic_cast<WasmEdge::Host::WasmEdgeProcessModule *>(createModule()); - ASSERT_TRUE(ProcMod != nullptr); + auto ProcMod = createModule(); + ASSERT_TRUE(ProcMod); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -233,9 +239,9 @@ TEST(WasmEdgeProcessTest, AddStdIn) { // Clear the memory[0, 64]. fillMemContent(MemInst, 0, 64); // Set the memory[0, 4] as string "\01\02\03\04". - fillMemContent(MemInst, 0, std::string("\01\02\03\04")); + fillMemContent(MemInst, 0, "\01\02\03\04"sv); // Set the memory[30, 46] as string "hello, wasmedge\n". - fillMemContent(MemInst, 30, std::string("hello, wasmedge\n")); + fillMemContent(MemInst, 30, "hello, wasmedge\n"sv); // Get the function "wasmedge_process_add_stdin". auto *FuncInst = ProcMod->findFuncExports("wasmedge_process_add_stdin"); @@ -269,15 +275,12 @@ TEST(WasmEdgeProcessTest, AddStdIn) { DummyCallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(0), UINT32_C(4)}, {})); - - delete ProcMod; } TEST(WasmEdgeProcessTest, SetTimeOut) { // Create the wasmedge_process module instance. - auto *ProcMod = - dynamic_cast<WasmEdge::Host::WasmEdgeProcessModule *>(createModule()); - ASSERT_TRUE(ProcMod != nullptr); + auto ProcMod = createModule(); + ASSERT_TRUE(ProcMod); // Get the function "wasmedge_process_set_timeout". auto *FuncInst = ProcMod->findFuncExports("wasmedge_process_set_timeout"); @@ -292,15 +295,12 @@ TEST(WasmEdgeProcessTest, SetTimeOut) { DummyCallFrame, std::initializer_list<WasmEdge::ValVariant>{UINT32_C(100)}, {})); EXPECT_EQ(ProcMod->getEnv().TimeOut, 100U); - - delete ProcMod; } TEST(WasmEdgeProcessTest, Run) { // Create the wasmedge_process module instance. - auto *ProcMod = - dynamic_cast<WasmEdge::Host::WasmEdgeProcessModule *>(createModule()); - ASSERT_TRUE(ProcMod != nullptr); + auto ProcMod = createModule(); + ASSERT_TRUE(ProcMod); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -315,9 +315,9 @@ TEST(WasmEdgeProcessTest, Run) { // Clear the memory[0, 64]. fillMemContent(MemInst, 0, 64); // Set the memory[0, 4] as string "\01\02\03\04". - fillMemContent(MemInst, 0, std::string("\01\02\03\04")); + fillMemContent(MemInst, 0, "\01\02\03\04"sv); // Set the memory[30, 46] as string "hello, wasmedge\n". - fillMemContent(MemInst, 30, std::string("hello, wasmedge\n")); + fillMemContent(MemInst, 30, "hello, wasmedge\n"sv); // Get the function "wasmedge_process_run". auto *FuncInst = ProcMod->findFuncExports("wasmedge_process_run"); @@ -374,15 +374,12 @@ TEST(WasmEdgeProcessTest, Run) { std::string OutStr = "123456 test\n"; EXPECT_TRUE(std::equal(ProcMod->getEnv().StdOut.begin(), ProcMod->getEnv().StdOut.end(), OutStr.begin())); - - delete ProcMod; } TEST(WasmEdgeProcessTest, GetExitCode) { // Create the wasmedge_process module instance. - auto *ProcMod = - dynamic_cast<WasmEdge::Host::WasmEdgeProcessModule *>(createModule()); - ASSERT_TRUE(ProcMod != nullptr); + auto ProcMod = createModule(); + ASSERT_TRUE(ProcMod); // Get the function "wasmedge_process_get_exit_code". auto *FuncInst = ProcMod->findFuncExports("wasmedge_process_get_exit_code"); @@ -396,15 +393,12 @@ TEST(WasmEdgeProcessTest, GetExitCode) { std::array<WasmEdge::ValVariant, 1> RetVal; EXPECT_TRUE(HostFuncInst.run(DummyCallFrame, {}, RetVal)); EXPECT_EQ(RetVal[0].get<int32_t>(), 0); - - delete ProcMod; } TEST(WasmEdgeProcessTest, GetStdOut) { // Create the wasmedge_process module instance. - auto *ProcMod = - dynamic_cast<WasmEdge::Host::WasmEdgeProcessModule *>(createModule()); - ASSERT_TRUE(ProcMod != nullptr); + auto ProcMod = createModule(); + ASSERT_TRUE(ProcMod); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -466,15 +460,12 @@ TEST(WasmEdgeProcessTest, GetStdOut) { EXPECT_TRUE(std::equal(ProcMod->getEnv().StdOut.begin(), ProcMod->getEnv().StdOut.end(), MemInst.getPointer<uint8_t *>(0))); - - delete ProcMod; } TEST(WasmEdgeProcessTest, GetStdErr) { // Create the wasmedge_process module instance. - auto *ProcMod = - dynamic_cast<WasmEdge::Host::WasmEdgeProcessModule *>(createModule()); - ASSERT_TRUE(ProcMod != nullptr); + auto ProcMod = createModule(); + ASSERT_TRUE(ProcMod); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -535,15 +526,13 @@ TEST(WasmEdgeProcessTest, GetStdErr) { EXPECT_TRUE(std::equal(ProcMod->getEnv().StdOut.begin(), ProcMod->getEnv().StdOut.end(), MemInst.getPointer<uint8_t *>(0))); - - delete ProcMod; } TEST(WasmEdgeProcessTest, Module) { // Create the wasmedge_process module instance. - auto *ProcMod = - dynamic_cast<WasmEdge::Host::WasmEdgeProcessModule *>(createModule()); - EXPECT_FALSE(ProcMod == nullptr); + auto ProcMod = createModule(); + ASSERT_TRUE(ProcMod); + EXPECT_EQ(ProcMod->getEnv().ExitCode, 0U); EXPECT_EQ(ProcMod->getFuncExportNum(), 11U); EXPECT_NE(ProcMod->findFuncExports("wasmedge_process_set_prog_name"), @@ -561,7 +550,6 @@ TEST(WasmEdgeProcessTest, Module) { EXPECT_NE(ProcMod->findFuncExports("wasmedge_process_get_stderr_len"), nullptr); EXPECT_NE(ProcMod->findFuncExports("wasmedge_process_get_stderr"), nullptr); - delete ProcMod; } GTEST_API_ int main(int argc, char **argv) { diff --git a/test/plugins/wasmedge_rustls/CMakeLists.txt b/test/plugins/wasmedge_rustls/CMakeLists.txt deleted file mode 100644 index 3cfc874b2d16..000000000000 --- a/test/plugins/wasmedge_rustls/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC - -wasmedge_add_executable(wasmEdgeRUSTLSTests - wasmedge_rustls.cpp -) - -add_dependencies(wasmEdgeRUSTLSTests - wasmedge_rustls -) - -target_include_directories(wasmEdgeRUSTLSTests - PUBLIC - $<TARGET_PROPERTY:wasmedgePlugin,INCLUDE_DIRECTORIES> - $<TARGET_PROPERTY:wasmedge_rustls,INCLUDE_DIRECTORIES> -) - -target_link_libraries(wasmEdgeRUSTLSTests - PRIVATE - ${GTEST_BOTH_LIBRARIES} -) -# Link to the WasmEdge library -if(WASMEDGE_LINK_PLUGINS_STATIC) - target_link_libraries(wasmEdgeRUSTLSTests - PRIVATE - wasmedgeCAPI - ) -else() - target_link_libraries(wasmEdgeRUSTLSTests - PRIVATE - wasmedge_shared - ) -endif() - -add_test(wasmEdgeRUSTLSTests wasmEdgeRUSTLSTests) diff --git a/test/plugins/wasmedge_rustls/wasmedge_rustls.cpp b/test/plugins/wasmedge_rustls/wasmedge_rustls.cpp deleted file mode 100644 index 1e758cf0fdc4..000000000000 --- a/test/plugins/wasmedge_rustls/wasmedge_rustls.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC - -#include "common/defines.h" -#include "plugin/plugin.h" -#include "runtime/instance/module.h" - -#include <algorithm> -#include <array> -#include <cstdint> -#include <gtest/gtest.h> -#include <string> -#include <vector> - -namespace { -WasmEdge::Runtime::Instance::ModuleInstance *createModule() { - using namespace std::literals::string_view_literals; - WasmEdge::Plugin::Plugin::load( - std::filesystem::u8path("../../../plugins/wasmedge_rustls/" - "libwasmedge_rustls" WASMEDGE_LIB_EXTENSION)); - if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("rustls"sv)) { - if (const auto *Module = Plugin->findModule("rustls_client"sv)) { - return Module->create().release(); - } - } - return nullptr; -} -} // namespace - -// TODO: unit tests for every functions. - -TEST(WasmEdgeRUSTLSTest, Module) { - // Create the wasmedge_rustls module instance. - auto *TLSMod = createModule(); - EXPECT_FALSE(TLSMod == nullptr); - EXPECT_EQ(TLSMod->getFuncExportNum(), 11U); - EXPECT_NE(TLSMod->findFuncExports("default_config"), nullptr); - EXPECT_NE(TLSMod->findFuncExports("new_codec"), nullptr); - EXPECT_NE(TLSMod->findFuncExports("codec_is_handshaking"), nullptr); - EXPECT_NE(TLSMod->findFuncExports("codec_wants"), nullptr); - EXPECT_NE(TLSMod->findFuncExports("delete_codec"), nullptr); - EXPECT_NE(TLSMod->findFuncExports("send_close_notify"), nullptr); - EXPECT_NE(TLSMod->findFuncExports("process_new_packets"), nullptr); - EXPECT_NE(TLSMod->findFuncExports("write_raw"), nullptr); - EXPECT_NE(TLSMod->findFuncExports("write_tls"), nullptr); - EXPECT_NE(TLSMod->findFuncExports("read_raw"), nullptr); - EXPECT_NE(TLSMod->findFuncExports("read_tls"), nullptr); - delete TLSMod; -} - -GTEST_API_ int main(int argc, char **argv) { - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/test/plugins/wasmedge_stablediffusion/CMakeLists.txt b/test/plugins/wasmedge_stablediffusion/CMakeLists.txt new file mode 100644 index 000000000000..dac8abd72bb1 --- /dev/null +++ b/test/plugins/wasmedge_stablediffusion/CMakeLists.txt @@ -0,0 +1,47 @@ +wasmedge_add_executable(wasmedgeStableDiffusionTests + wasmedge_stablediffusion.cpp +) + +add_dependencies(wasmedgeStableDiffusionTests + wasmedgePluginWasmEdgeStableDiffusion +) + +target_include_directories(wasmedgeStableDiffusionTests + PUBLIC + $<TARGET_PROPERTY:wasmedgePlugin,INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:wasmedgePluginWasmEdgeStableDiffusion,INCLUDE_DIRECTORIES> +) + +target_link_libraries(wasmedgeStableDiffusionTests + PRIVATE + ${GTEST_BOTH_LIBRARIES} +) + +# Link to the WasmEdge library +if(WASMEDGE_LINK_PLUGINS_STATIC) + target_link_libraries(wasmedgeStableDiffusionTests + PRIVATE + wasmedgeCAPI + ) +else() + target_link_libraries(wasmedgeStableDiffusionTests + PRIVATE + wasmedge_shared + ) +endif() +function(download URL OUTPUT HASH) + file(DOWNLOAD + ${URL} + ${OUTPUT} + SHOW_PROGRESS + EXPECTED_HASH ${HASH} + ) +endfunction() +message(STATUS "Download ML artifacts to ${CMAKE_CURRENT_BINARY_DIR}/sd-v1-4.ckpt") +download( + https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/resolve/main/sd-v1-4.ckpt + ${CMAKE_CURRENT_BINARY_DIR}/stableDiffusion/sd-v1-4.ckpt + MD5=c01059060130b8242849d86e97212c84 +) + +add_test(wasmedgeStableDiffusionTests wasmedgeStableDiffusionTests) diff --git a/test/plugins/wasmedge_stablediffusion/wasmedge_stablediffusion.cpp b/test/plugins/wasmedge_stablediffusion/wasmedge_stablediffusion.cpp new file mode 100644 index 000000000000..a589a9f29e9d --- /dev/null +++ b/test/plugins/wasmedge_stablediffusion/wasmedge_stablediffusion.cpp @@ -0,0 +1,337 @@ +#include "common/defines.h" +#include "runtime/instance/module.h" +#include "sd_func.h" +#include "sd_module.h" + +#include <algorithm> +#include <array> +#include <cstdint> +#include <gtest/gtest.h> +#include <string> +#include <vector> + +using WasmEdge::Host::StableDiffusion::ErrNo; + +namespace { + +template <typename T, typename U> +inline std::unique_ptr<T> dynamicPointerCast(std::unique_ptr<U> &&R) noexcept { + static_assert(std::has_virtual_destructor_v<T>); + T *P = dynamic_cast<T *>(R.get()); + if (P) { + R.release(); + } + return std::unique_ptr<T>(P); +} + +std::unique_ptr<WasmEdge::Host::SDModule> createModule() { + using namespace std::literals::string_view_literals; + WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( + "../../../plugins/wasmedge_stablediffusion/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasmEdgeStableDiffusion" WASMEDGE_LIB_EXTENSION)); + if (const auto *Plugin = + WasmEdge::Plugin::Plugin::find("wasmedge_stablediffusion"sv)) { + if (const auto *Module = Plugin->findModule("wasmedge_stablediffusion"sv)) { + return dynamicPointerCast<WasmEdge::Host::SDModule>(Module->create()); + } + } + return {}; +} +} // namespace + +template <typename T> +void writeBinaries(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, + WasmEdge::Span<const T> Binaries, uint32_t Ptr) noexcept { + std::copy(Binaries.begin(), Binaries.end(), MemInst.getPointer<T *>(Ptr)); +} + +void writeUInt32(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, + uint32_t Value, uint32_t &Ptr) { + uint32_t *BufPtr = MemInst.getPointer<uint32_t *>(Ptr); + *BufPtr = Value; + Ptr += 4; +} + +void writeFatPointer(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, + uint32_t PtrVal, uint32_t PtrSize, uint32_t &Ptr) { + writeUInt32(MemInst, PtrVal, Ptr); + writeUInt32(MemInst, PtrSize, Ptr); +} + +// TODO: unit tests for every functions. + +TEST(WasmEdgeStableDiffusionTest, ModuleFunctions) { + // Create the stable diffusion module instance. + auto SBMod = createModule(); + ASSERT_TRUE(SBMod); + EXPECT_EQ(SBMod->getFuncExportNum(), 4U); + + // Create the calling frame with memory instance. + WasmEdge::Runtime::Instance::ModuleInstance Mod(""); + Mod.addHostMemory( + "memory", std::make_unique<WasmEdge::Runtime::Instance::MemoryInstance>( + WasmEdge::AST::MemoryType(2097024))); + auto *MemInstPtr = Mod.findMemoryExports("memory"); + ASSERT_TRUE(MemInstPtr != nullptr); + auto &MemInst = *MemInstPtr; + WasmEdge::Runtime::CallingFrame CallFrame(nullptr, &Mod); + + // Return value. + std::array<WasmEdge::ValVariant, 1> Errno = {UINT32_C(0)}; + + uint32_t SessionPtr = UINT32_C(0); + uint32_t SessionId = UINT32_C(0); + uint32_t OutputPtr = UINT32_C(0); + // uint32_t OutBoundPtr = UINT32_C(61000) * UINT32_C(65536); + + // Get the function "convert". + auto *FuncInst = SBMod->findFuncExports("convert"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncConvert = + dynamic_cast<WasmEdge::Host::StableDiffusion::SDConvert &>( + FuncInst->getHostFunc()); + // Get the function "create_context". + FuncInst = SBMod->findFuncExports("create_context"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncCreateContext = + dynamic_cast<WasmEdge::Host::StableDiffusion::SDCreateContext &>( + FuncInst->getHostFunc()); + // Get the function "text_to_image". + FuncInst = SBMod->findFuncExports("text_to_image"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncTextToImage = + dynamic_cast<WasmEdge::Host::StableDiffusion::SDTextToImage &>( + FuncInst->getHostFunc()); + // Get the function "image_to_image". + FuncInst = SBMod->findFuncExports("image_to_image"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncImageToImage = + dynamic_cast<WasmEdge::Host::StableDiffusion::SDImageToImage &>( + FuncInst->getHostFunc()); + + std::string Prompt = "a lovely cat"; + std::string Prompt2 = "with blue eyes"; + std::string OutputPathString = "./stableDiffusion/output.png"; + std::vector<char> OutputPath(OutputPathString.begin(), + OutputPathString.end()); + std::string InputPathString = "path:" + OutputPathString; + std::vector<char> InputPath(InputPathString.begin(), InputPathString.end()); + std::string OutputPathString2 = "./stableDiffusion/output2.png"; + std::vector<char> OutputPath2(OutputPathString2.begin(), + OutputPathString2.end()); + std::vector<char> PromptData(Prompt.begin(), Prompt.end()); + std::vector<char> PromptData2(Prompt2.begin(), Prompt2.end()); + std::string ModelPathString = "./stableDiffusion/sd-v1-4.ckpt"; + std::vector<char> ModelPath(ModelPathString.begin(), ModelPathString.end()); + std::string QuantModelPathString = "./stableDiffusion/sd-v1-4-Q8_0.gguf"; + std::vector<char> QuantModelPath(QuantModelPathString.begin(), + QuantModelPathString.end()); + + uint32_t ModelPathPtr = UINT32_C(0); + uint32_t QuantModelPathPtr = ModelPathPtr + ModelPath.size(); + writeBinaries<char>(MemInst, ModelPath, ModelPathPtr); + writeBinaries<char>(MemInst, QuantModelPath, QuantModelPathPtr); + // Test: convert -- convert successfully. + { + EXPECT_TRUE(HostFuncConvert.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + ModelPathPtr, static_cast<uint32_t>(ModelPath.size()), 0, 0, + QuantModelPathPtr, static_cast<uint32_t>(QuantModelPath.size()), + 8}, // SD_TYPE_Q8_0 = 8 + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + EXPECT_TRUE(std::filesystem::exists(QuantModelPathString)); + } + // Test: create_context -- create context for text to image. + { + EXPECT_TRUE(HostFuncCreateContext.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + QuantModelPathPtr, // ModelPathPtr + static_cast<uint32_t>(QuantModelPath.size()), // ModelPathLen + 0, // ClipLPathPtr + 0, // ClipLPathLen + 0, // T5xxlPathPtr + 0, // T5xxlPathLen + 0, // DiffusionModelPathPtr + 0, // DiffusionModelPathLen + 0, // VaePathPtr + 0, // VaePathLen + 0, // TaesdPathPtr + 0, // TaesdPathLen + 0, // ControlNetPathPtr + 0, // ControlNetPathLen + 0, // LoraModelDirPtr + 0, // LoraModelDirLen + 0, // EmbedDirPtr + 0, // EmbedDirLen + 0, // IdEmbedDirPtr + 0, // IdEmbedDirLen + 1, // VaeDecodeOnly + 0, // VaeTiling + -1, // NThreads + 34, // Wtype + 1, // RngType + 0, // Schedule + 0, // ClipOnCpu + 0, // ControlNetCpu + 0, // VaeOnCpu + SessionPtr}, // SessiontIdPtr + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + SessionId = *MemInst.getPointer<uint32_t *>(SessionPtr); + EXPECT_EQ(SessionId, 0); + } + + // Test: text_to_image -- generate image from text. + { + uint32_t PromptPtr = UINT32_C(0); + uint32_t OutputPathPtr = PromptPtr + PromptData.size(); + uint32_t BytesWrittenPtr = OutputPathPtr + OutputPath.size(); + OutputPtr = BytesWrittenPtr + 4; + writeBinaries<char>(MemInst, PromptData, PromptPtr); + writeBinaries<char>(MemInst, OutputPath, OutputPathPtr); + EXPECT_TRUE(HostFuncTextToImage.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + PromptPtr, // PromptPtr + static_cast<uint32_t>(PromptData.size()), // PromptLen + SessionId, // SessionId + 0, // ControlImagePtr + 0, // ControlImageLen + 0, // NegativePromptPtr + 0, // NegativePromptLen + 3.5f, // Guidance + 256, // Width + 256, // Height + -1, // ClipSkip + 7.0f, // CfgScale + 0, // SampleMethod + 20, // SampleSteps + 42, // Seed + 1, // BatchCount + 0.90f, // ControlStrength + 20.0f, // StyleRatio + 0, // NormalizeInput + 0, // InputIdImagesDirPtr + 0, // InputIdImagesDirLen + 0, // CannyPreprocess + 0, // UpscaleModelPathPtr + 0, // UpscaleModelPathLen + 1, // UpscaleRepeats + OutputPathPtr, // OutputPathPtr + static_cast<uint32_t>(OutputPath.size()), // OutputPathLen + OutputPtr, // OutBufferPtr + 1048512, // OutBufferMaxSize + BytesWrittenPtr}, // BytesWrittenPtr + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + auto BytesWritten = *MemInst.getPointer<uint32_t *>(BytesWrittenPtr); + EXPECT_GE(BytesWritten, 50); + EXPECT_TRUE(std::filesystem::exists(OutputPathString)); + } + writeBinaries<char>(MemInst, ModelPath, ModelPathPtr); + writeBinaries<char>(MemInst, QuantModelPath, QuantModelPathPtr); + // Test: create_context -- create context for image to image. + { + EXPECT_TRUE(HostFuncCreateContext.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + QuantModelPathPtr, // ModelPathPtr + static_cast<uint32_t>(QuantModelPath.size()), // ModelPathLen + 0, // ClipLPathPtr + 0, // ClipLPathLen + 0, // T5xxlPathPtr + 0, // T5xxlPathLen + 0, // DiffusionModelPathPtr + 0, // DiffusionModelPathLen + 0, // VaePathPtr + 0, // VaePathLen + 0, // TaesdPathPtr + 0, // TaesdPathLen + 0, // ControlNetPathPtr + 0, // ControlNetPathLen + 0, // LoraModelDirPtr + 0, // LoraModelDirLen + 0, // EmbedDirPtr + 0, // EmbedDirLen + 0, // IdEmbedDirPtr + 0, // IdEmbedDirLen + 0, // VaeDecodeOnly + 0, // VaeTiling + -1, // NThreads + 34, // Wtype + 1, // RngType + 0, // Schedule + 0, // ClipOnCpu + 0, // ControlNetCpu + 0, // VaeOnCpu + SessionPtr}, // SessiontIdPtr + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + SessionId = *MemInst.getPointer<uint32_t *>(SessionPtr); + EXPECT_EQ(SessionId, 1); + } + // Test: image_to_image -- generate image from image. + { + uint32_t PromptPtr = UINT32_C(0); + uint32_t InputPathPtr = PromptPtr + PromptData2.size(); + uint32_t OutputPathPtr = InputPathPtr + InputPath.size(); + uint32_t BytesWrittenPtr = OutputPathPtr + OutputPath2.size(); + OutputPtr = BytesWrittenPtr + 4; + writeBinaries<char>(MemInst, PromptData2, PromptPtr); + writeBinaries<char>(MemInst, InputPath, InputPathPtr); + writeBinaries<char>(MemInst, OutputPath2, OutputPathPtr); + EXPECT_TRUE(HostFuncImageToImage.run( + CallFrame, + std::initializer_list<WasmEdge::ValVariant>{ + InputPathPtr, // ImagePtr + static_cast<uint32_t>(InputPath.size()), // ImageLen + SessionId, // SessionId + 3.5f, // Guidance + 256, // Width + 256, // Height + 0, // ControlImagePtr + 0, // ControlImageLen + PromptPtr, // PromptPtr + static_cast<uint32_t>(PromptData2.size()), // PromptLen + 0, // NegativePromptPtr + 0, // NegativePromptLen + -1, // ClipSkip + 7.0f, // CfgScale + 0, // SampleMethod + 20, // SampleSteps + 0.75f, // Strength + 42, // Seed + 1, // BatchCount + 0.9f, // ControlStrength + 20.0f, // StyleRatio + 0, // NormalizeInput + 0, // InputIdImagesDirPtr + 0, // InputIdImagesDirLen + 0, // CannyPreprocess + 0, // UpscaleModelPathPtr + 0, // UpscaleModelPathLen + 1, // UpscaleRepeats + OutputPathPtr, // OutputPathPtr + static_cast<uint32_t>(OutputPath2.size()), // OutputPathLen + OutputPtr, // OutBufferPtr + 1048512, // OutBufferMaxSize + BytesWrittenPtr}, // BytesWrittenPtr + Errno)); + EXPECT_EQ(Errno[0].get<int32_t>(), static_cast<uint32_t>(ErrNo::Success)); + auto BytesWritten = *MemInst.getPointer<uint32_t *>(BytesWrittenPtr); + EXPECT_GE(BytesWritten, 50); + EXPECT_TRUE(std::filesystem::exists(OutputPathString2)); + } +} + +GTEST_API_ int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/plugins/wasmedge_tensorflow/CMakeLists.txt b/test/plugins/wasmedge_tensorflow/CMakeLists.txt index aba4ee6ee058..9c0f68234322 100644 --- a/test/plugins/wasmedge_tensorflow/CMakeLists.txt +++ b/test/plugins/wasmedge_tensorflow/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeTensorflowTests wasmedge_tensorflow.cpp diff --git a/test/plugins/wasmedge_tensorflow/wasmedge_tensorflow.cpp b/test/plugins/wasmedge_tensorflow/wasmedge_tensorflow.cpp index 253ab8281741..8ce35675ee85 100644 --- a/test/plugins/wasmedge_tensorflow/wasmedge_tensorflow.cpp +++ b/test/plugins/wasmedge_tensorflow/wasmedge_tensorflow.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #include "runtime/instance/module.h" @@ -10,22 +10,35 @@ #include <array> #include <cstdint> #include <gtest/gtest.h> +#include <memory> #include <string> #include <vector> namespace { -WasmEdge::Runtime::Instance::ModuleInstance *createModule() { + +template <typename T, typename U> +inline std::unique_ptr<T> dynamicPointerCast(std::unique_ptr<U> &&R) noexcept { + static_assert(std::has_virtual_destructor_v<T>); + T *P = dynamic_cast<T *>(R.get()); + if (P) { + R.release(); + } + return std::unique_ptr<T>(P); +} + +std::unique_ptr<WasmEdge::Host::WasmEdgeTensorflowModule> createModule() { using namespace std::literals::string_view_literals; WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "../../../plugins/wasmedge_tensorflow/" - "libwasmedgePluginWasmEdgeTensorflow" WASMEDGE_LIB_EXTENSION)); + "../../../plugins/wasmedge_tensorflow/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasmEdgeTensorflow" WASMEDGE_LIB_EXTENSION)); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasmedge_tensorflow"sv)) { if (const auto *Module = Plugin->findModule("wasmedge_tensorflow"sv)) { - return Module->create().release(); + return dynamicPointerCast<WasmEdge::Host::WasmEdgeTensorflowModule>( + Module->create()); } } - return nullptr; + return {}; } } // namespace @@ -33,9 +46,9 @@ WasmEdge::Runtime::Instance::ModuleInstance *createModule() { TEST(WasmEdgeTensorflowTest, Module) { // Create the wasmedge_tensorflow module instance. - auto *TFMod = - dynamic_cast<WasmEdge::Host::WasmEdgeTensorflowModule *>(createModule()); - EXPECT_FALSE(TFMod == nullptr); + auto TFMod = createModule(); + ASSERT_TRUE(TFMod); + EXPECT_EQ(TFMod->getFuncExportNum(), 11U); EXPECT_NE(TFMod->findFuncExports("create_session"), nullptr); EXPECT_NE(TFMod->findFuncExports("create_session_saved_model"), nullptr); @@ -48,7 +61,6 @@ TEST(WasmEdgeTensorflowTest, Module) { EXPECT_NE(TFMod->findFuncExports("append_output"), nullptr); EXPECT_NE(TFMod->findFuncExports("clear_input"), nullptr); EXPECT_NE(TFMod->findFuncExports("clear_output"), nullptr); - delete TFMod; } GTEST_API_ int main(int argc, char **argv) { diff --git a/test/plugins/wasmedge_tensorflowlite/CMakeLists.txt b/test/plugins/wasmedge_tensorflowlite/CMakeLists.txt index 04eee39a955f..bbf2ff609b6b 100644 --- a/test/plugins/wasmedge_tensorflowlite/CMakeLists.txt +++ b/test/plugins/wasmedge_tensorflowlite/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeTensorflowLiteTests wasmedge_tensorflowlite.cpp diff --git a/test/plugins/wasmedge_tensorflowlite/wasmedge_tensorflowlite.cpp b/test/plugins/wasmedge_tensorflowlite/wasmedge_tensorflowlite.cpp index b0cfa5c3b1c9..843e5fc5e3d3 100644 --- a/test/plugins/wasmedge_tensorflowlite/wasmedge_tensorflowlite.cpp +++ b/test/plugins/wasmedge_tensorflowlite/wasmedge_tensorflowlite.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #include "runtime/instance/module.h" @@ -10,33 +10,45 @@ #include <array> #include <cstdint> #include <gtest/gtest.h> +#include <memory> #include <string> #include <vector> namespace { -WasmEdge::Runtime::Instance::ModuleInstance *createModule() { + +template <typename T, typename U> +inline std::unique_ptr<T> dynamicPointerCast(std::unique_ptr<U> &&R) noexcept { + static_assert(std::has_virtual_destructor_v<T>); + T *P = dynamic_cast<T *>(R.get()); + if (P) { + R.release(); + } + return std::unique_ptr<T>(P); +} + +std::unique_ptr<WasmEdge::Host::WasmEdgeTensorflowLiteModule> createModule() { using namespace std::literals::string_view_literals; WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "../../../plugins/wasmedge_tensorflowlite/" - "libwasmedgePluginWasmEdgeTensorflowLite" WASMEDGE_LIB_EXTENSION)); + "../../../plugins/wasmedge_tensorflowlite/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasmEdgeTensorflowLite" WASMEDGE_LIB_EXTENSION)); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasmedge_tensorflowlite"sv)) { if (const auto *Module = Plugin->findModule("wasmedge_tensorflowlite"sv)) { - return Module->create().release(); + return dynamicPointerCast<WasmEdge::Host::WasmEdgeTensorflowLiteModule>( + Module->create()); } } - return nullptr; + return {}; } + } // namespace // TODO: unit tests for every functions. TEST(WasmEdgeTensorflowLiteTest, Module) { // Create the wasmedge_tensorflowlite module instance. - auto *TFLiteMod = - dynamic_cast<WasmEdge::Host::WasmEdgeTensorflowLiteModule *>( - createModule()); - EXPECT_FALSE(TFLiteMod == nullptr); + auto TFLiteMod = createModule(); + ASSERT_TRUE(TFLiteMod); EXPECT_EQ(TFLiteMod->getFuncExportNum(), 7U); EXPECT_NE(TFLiteMod->findFuncExports("create_session"), nullptr); EXPECT_NE(TFLiteMod->findFuncExports("delete_session"), nullptr); @@ -45,7 +57,6 @@ TEST(WasmEdgeTensorflowLiteTest, Module) { EXPECT_NE(TFLiteMod->findFuncExports("get_tensor_len"), nullptr); EXPECT_NE(TFLiteMod->findFuncExports("get_tensor_data"), nullptr); EXPECT_NE(TFLiteMod->findFuncExports("append_input"), nullptr); - delete TFLiteMod; } GTEST_API_ int main(int argc, char **argv) { diff --git a/test/plugins/wasmedge_zlib/CMakeLists.txt b/test/plugins/wasmedge_zlib/CMakeLists.txt index 7159ab83d922..5b9ad3ecb6aa 100644 --- a/test/plugins/wasmedge_zlib/CMakeLists.txt +++ b/test/plugins/wasmedge_zlib/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeZlibTests wasmedge_zlib.cpp diff --git a/test/plugins/wasmedge_zlib/wasmedge_zlib.cpp b/test/plugins/wasmedge_zlib/wasmedge_zlib.cpp index d526178ab593..46b3cb78f5f8 100644 --- a/test/plugins/wasmedge_zlib/wasmedge_zlib.cpp +++ b/test/plugins/wasmedge_zlib/wasmedge_zlib.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "common/defines.h" #include "runtime/instance/module.h" @@ -11,23 +11,36 @@ #include <cstdint> #include <cstdio> #include <gtest/gtest.h> +#include <memory> #include <string> #include <vector> namespace { + WasmEdge::Runtime::CallingFrame DummyCallFrame(nullptr, nullptr); -WasmEdge::Runtime::Instance::ModuleInstance *createModule() { +template <typename T, typename U> +inline std::unique_ptr<T> dynamicPointerCast(std::unique_ptr<U> &&R) noexcept { + static_assert(std::has_virtual_destructor_v<T>); + T *P = dynamic_cast<T *>(R.get()); + if (P) { + R.release(); + } + return std::unique_ptr<T>(P); +} + +std::unique_ptr<WasmEdge::Host::WasmEdgeZlibModule> createModule() { using namespace std::literals::string_view_literals; WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "../../../plugins/wasmedge_zlib/" - "libwasmedgePluginWasmEdgeZlib" WASMEDGE_LIB_EXTENSION)); + "../../../plugins/wasmedge_zlib/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasmEdgeZlib" WASMEDGE_LIB_EXTENSION)); if (const auto *Plugin = WasmEdge::Plugin::Plugin::find("wasmedge_zlib"sv)) { if (const auto *Module = Plugin->findModule("wasmedge_zlib"sv)) { - return Module->create().release(); + return dynamicPointerCast<WasmEdge::Host::WasmEdgeZlibModule>( + Module->create()); } } - return nullptr; + return {}; } } // namespace @@ -49,9 +62,8 @@ constexpr auto RandChar = []() -> char { }; TEST(WasmEdgeZlibTest, DeflateInflateCycle) { - auto *ZlibMod = - dynamic_cast<WasmEdge::Host::WasmEdgeZlibModule *>(createModule()); - ASSERT_TRUE(ZlibMod != nullptr); + auto ZlibMod = createModule(); + ASSERT_TRUE(ZlibMod); // Create the calling frame with memory instance. WasmEdge::Runtime::Instance::ModuleInstance Mod(""); @@ -250,9 +262,9 @@ TEST(WasmEdgeZlibTest, DeflateInflateCycle) { TEST(WasmEdgeZlibTest, Module) { // Create the wasmedge_zlib module instance. - auto *ZlibMod = - dynamic_cast<WasmEdge::Host::WasmEdgeZlibModule *>(createModule()); - EXPECT_FALSE(ZlibMod == nullptr); + auto ZlibMod = createModule(); + ASSERT_TRUE(ZlibMod); + EXPECT_TRUE(ZlibMod->getEnv().ZStreamMap.empty()); EXPECT_EQ(ZlibMod->getFuncExportNum(), 76U); @@ -332,8 +344,6 @@ TEST(WasmEdgeZlibTest, Module) { EXPECT_NE(ZlibMod->findFuncExports("inflateCodesUsed"), nullptr); EXPECT_NE(ZlibMod->findFuncExports("inflateResetKeep"), nullptr); EXPECT_NE(ZlibMod->findFuncExports("deflateResetKeep"), nullptr); - - delete ZlibMod; } GTEST_API_ int main(int ArgC, char **ArgV) { diff --git a/test/po/CMakeLists.txt b/test/po/CMakeLists.txt index 99dd5b8ada03..dbfa7fdb40da 100644 --- a/test/po/CMakeLists.txt +++ b/test/po/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(poTests gtest.cpp diff --git a/test/po/gtest.cpp b/test/po/gtest.cpp index a3e59e47b055..6e7a099ca2ab 100644 --- a/test/po/gtest.cpp +++ b/test/po/gtest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include <gtest/gtest.h> diff --git a/test/po/help.cpp b/test/po/help.cpp index 13ec7ee11aa1..f43ef8fc0f4a 100644 --- a/test/po/help.cpp +++ b/test/po/help.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "po/argument_parser.h" #include "po/list.h" diff --git a/test/po/po.cpp b/test/po/po.cpp index 7101b1a01616..3cdb60efc9af 100644 --- a/test/po/po.cpp +++ b/test/po/po.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "po/argument_parser.h" #include "po/list.h" diff --git a/test/po/subcommand.cpp b/test/po/subcommand.cpp index a8aa33903b46..1e52a0b23d76 100644 --- a/test/po/subcommand.cpp +++ b/test/po/subcommand.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "po/subcommand.h" #include "po/argument_parser.h" @@ -62,7 +62,8 @@ TEST(SubCommands, Simple4) { .begin_subcommand(S2, "s2"sv) .end_subcommand(); std::array Args = {"test", "s1", "s2"}; - EXPECT_FALSE(Parser.parse(stdout, static_cast<int>(Args.size()), Args.data())); + EXPECT_FALSE( + Parser.parse(stdout, static_cast<int>(Args.size()), Args.data())); } TEST(SubCommands, Nested1) { @@ -102,7 +103,8 @@ TEST(SubCommands, Nested3) { .end_subcommand() .end_subcommand(); std::array Args = {"test", "s2"}; - EXPECT_FALSE(Parser.parse(stdout, static_cast<int>(Args.size()), Args.data())); + EXPECT_FALSE( + Parser.parse(stdout, static_cast<int>(Args.size()), Args.data())); } TEST(SubCommands, NestedOption1) { @@ -142,7 +144,8 @@ TEST(SubCommands, NestedOption2) { .end_subcommand() .end_subcommand(); std::array Args = {"test", "s1", "--t1"}; - EXPECT_FALSE(Parser.parse(stdout, static_cast<int>(Args.size()), Args.data())); + EXPECT_FALSE( + Parser.parse(stdout, static_cast<int>(Args.size()), Args.data())); } TEST(SubCommands, NestedOption3) { diff --git a/test/span/CMakeLists.txt b/test/span/CMakeLists.txt index 79d526c4d5c7..53e3c9dfba31 100644 --- a/test/span/CMakeLists.txt +++ b/test/span/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(spanTests span.cpp diff --git a/test/spec/CMakeLists.txt b/test/spec/CMakeLists.txt index 0e1eabe48bc5..8c6ba6714a2e 100644 --- a/test/spec/CMakeLists.txt +++ b/test/spec/CMakeLists.txt @@ -1,71 +1,19 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC include(FetchContent) +wasmedge_setup_simdjson() + message(STATUS "Downloading the WASM spec test suite") FetchContent_Declare( wasmedge_unit_test GIT_REPOSITORY https://github.com/second-state/WasmEdge-unittest - GIT_TAG wasm-dev-0.14.0 + GIT_TAG wasm-dev ) FetchContent_MakeAvailable(wasmedge_unit_test) message(STATUS "Downloading the WASM spec test suite -- done") -find_package(simdjson QUIET) -if(simdjson_FOUND) - message(STATUS "SIMDJSON found") -else() - message(STATUS "Downloading SIMDJSON source") - include(FetchContent) - FetchContent_Declare( - simdjson - GIT_REPOSITORY https://github.com/simdjson/simdjson.git - GIT_TAG tags/v3.2.1 - GIT_SHALLOW TRUE) - - if(MSVC) - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - get_property( - compile_options - DIRECTORY - PROPERTY COMPILE_OPTIONS - ) - set_property( - DIRECTORY - APPEND - PROPERTY COMPILE_OPTIONS - -Wno-undef - -Wno-suggest-override - -Wno-documentation - -Wno-sign-conversion - -Wno-extra-semi-stmt - -Wno-old-style-cast - -Wno-error=unused-parameter - -Wno-error=unused-template - -Wno-conditional-uninitialized - -Wno-implicit-int-conversion - -Wno-shorten-64-to-32 - -Wno-range-loop-bind-reference - -Wno-format-nonliteral - -Wno-unused-exception-parameter - -Wno-unused-member-function - ) - unset(compile_options) - elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - set_property( - DIRECTORY - APPEND - PROPERTY COMPILE_OPTIONS - /wd4100 # unreferenced formal parameter - ) - endif() - endif() - - FetchContent_MakeAvailable(simdjson) - message(STATUS "Downloading SIMDJSON source -- done") -endif() - function(wasmedge_copy_spec_testsuite proposal) message(STATUS "Copying test suite to ${CMAKE_CURRENT_BINARY_DIR}/testSuites/${proposal}") file(COPY @@ -76,7 +24,7 @@ function(wasmedge_copy_spec_testsuite proposal) message(STATUS "Copying test suite to ${CMAKE_CURRENT_BINARY_DIR}/testSuites/${proposal} -- done") endfunction() -foreach(PROPOSAL core multi-memory tail-call extended-const threads function-references) +foreach(PROPOSAL core multi-memory tail-call extended-const threads function-references gc exception-handling exception-handling-legacy relaxed-simd) wasmedge_copy_spec_testsuite(${PROPOSAL}) endforeach() @@ -86,7 +34,7 @@ wasmedge_add_library(wasmedgeTestSpec target_link_libraries(wasmedgeTestSpec PRIVATE - simdjson + simdjson::simdjson PUBLIC std::filesystem wasmedgeCommon diff --git a/test/spec/hostfunc.h b/test/spec/hostfunc.h index 2d35abfff11d..aaee292be379 100644 --- a/test/spec/hostfunc.h +++ b/test/spec/hostfunc.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/spec/hostfunc.h - Spec test host functions ----------===// // @@ -94,11 +94,11 @@ class SpecTestModule : public Runtime::Instance::ModuleInstance { addHostGlobal( "global_f32", std::make_unique<Runtime::Instance::GlobalInstance>( - AST::GlobalType(TypeCode::F32, ValMut::Const), float(666))); + AST::GlobalType(TypeCode::F32, ValMut::Const), float(666.6))); addHostGlobal( "global_f64", std::make_unique<Runtime::Instance::GlobalInstance>( - AST::GlobalType(TypeCode::F64, ValMut::Const), double(666))); + AST::GlobalType(TypeCode::F64, ValMut::Const), double(666.6))); } ~SpecTestModule() noexcept override = default; }; diff --git a/test/spec/spectest.cpp b/test/spec/spectest.cpp index 07ddf2216718..9c6b29d07a14 100644 --- a/test/spec/spectest.cpp +++ b/test/spec/spectest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/spec/spectest.cpp - Wasm test suites ----------------===// // @@ -15,7 +15,7 @@ //===----------------------------------------------------------------------===// #include "spectest.h" -#include "common/log.h" +#include "common/spdlog.h" #include "simdjson.h" #include <algorithm> @@ -85,6 +85,7 @@ SpecTest::CommandID resolveCommand(std::string_view Name) { {"assert_unlinkable"sv, SpecTest::CommandID::AssertUnlinkable}, {"assert_uninstantiable"sv, SpecTest::CommandID::AssertUninstantiable}, + {"assert_exception"sv, SpecTest::CommandID::AssertException}, }; if (auto Iter = CommandMapping.find(Name); Iter != CommandMapping.end()) { return Iter->second; @@ -159,23 +160,27 @@ parseValueList(const simdjson::dom::array &Args) { ResultTypes.emplace_back(WasmEdge::TypeCode::V128); } else if (Value.type() == simdjson::dom::element_type::STRING) { std::string_view ValueStr = Value; - if (Type == "externref"sv) { + if (Type == "externref"sv || Type == "anyref"sv) { + WasmEdge::TypeCode Code = Type == "externref"sv + ? WasmEdge::TypeCode::ExternRef + : WasmEdge::TypeCode::AnyRef; if (Value == "null"sv) { - Result.emplace_back(WasmEdge::RefVariant()); + Result.emplace_back(WasmEdge::RefVariant(Code)); } else { - // Add 0x1 uint32_t prefix in this externref index case. - Result.emplace_back(WasmEdge::RefVariant(reinterpret_cast<void *>( - std::stoul(std::string(ValueStr)) + 0x100000000ULL))); + // ExternRef and AnyRef are non-opaque references. Add 0x1 uint32_t + // prefix in this case to present non-null. + Result.emplace_back(WasmEdge::RefVariant( + Code, reinterpret_cast<void *>(std::stoul(std::string(ValueStr)) + + 0x100000000ULL))); } - ResultTypes.emplace_back(WasmEdge::TypeCode::ExternRef); + ResultTypes.emplace_back(Code); } else if (Type == "funcref"sv) { if (Value == "null"sv) { - Result.emplace_back(WasmEdge::RefVariant()); + Result.emplace_back( + WasmEdge::RefVariant(WasmEdge::TypeCode::FuncRef)); } else { - // Add 0x1 uint32_t prefix in this funcref index case. - Result.emplace_back(WasmEdge::RefVariant( - reinterpret_cast<WasmEdge::Runtime::Instance::FunctionInstance *>( - std::stoul(std::string(ValueStr)) + 0x100000000ULL))); + // Not support input value of opaque references for testing. + assumingUnreachable(); } ResultTypes.emplace_back(WasmEdge::TypeCode::FuncRef); } else if (Type == "i32"sv) { @@ -240,6 +245,17 @@ parseExpectedList(const simdjson::dom::array &Args) { return Result; } +std::vector<std::vector<std::pair<std::string, std::string>>> +parseEithersList(const simdjson::dom::array &Args) { + std::vector<std::vector<std::pair<std::string, std::string>>> Result; + Result.reserve(Args.size()); + for (auto &Maybe : parseExpectedList(Args)) { + Result.emplace_back( + std::vector<std::pair<std::string, std::string>>{Maybe}); + } + return Result; +} + struct TestsuiteProposal { std::string_view Path; WasmEdge::Configure Conf; @@ -254,6 +270,15 @@ static const TestsuiteProposal TestsuiteProposals[] = { {"threads"sv, {Proposal::Threads}}, {"function-references"sv, {Proposal::FunctionReferences, Proposal::TailCall}}, + {"gc"sv, {Proposal::GC}, WasmEdge::SpecTest::TestMode::Interpreter}, + {"exception-handling"sv, + {Proposal::ExceptionHandling, Proposal::TailCall}, + WasmEdge::SpecTest::TestMode::Interpreter}, + // LEGACY-EH: remove the legacy EH test after deprecating legacy EH. + {"exception-handling-legacy"sv, + {Proposal::ExceptionHandling, Proposal::TailCall}, + WasmEdge::SpecTest::TestMode::Interpreter}, + {"relaxed-simd"sv, {Proposal::RelaxSIMD}}, }; } // namespace @@ -299,6 +324,21 @@ bool SpecTest::compare(const std::pair<std::string, std::string> &Expected, const std::pair<ValVariant, ValType> &Got) const { const auto &TypeStr = Expected.first; const auto &ValStr = Expected.second; + + auto IsRefMatch = [&ValStr](const WasmEdge::RefVariant &R) { + if (ValStr == "null"sv) { + // If explicitly expected a `null`, the reference must be null. + return R.isNull(); + } + if (ValStr == ""sv) { + // Opaque expected reference. Always true. + return true; + } + // Explicitly expected the reference value. + return static_cast<uint32_t>(reinterpret_cast<uintptr_t>( + R.getPtr<void>())) == static_cast<uint32_t>(std::stoul(ValStr)); + }; + bool IsV128 = (std::string_view(TypeStr).substr(0, 4) == "v128"sv); if (!IsV128 && ValStr.substr(0, 4) == "nan:"sv) { // Handle NaN case @@ -314,43 +354,109 @@ bool SpecTest::compare(const std::pair<std::string, std::string> &Expected, } return std::isnan(Got.first.get<double>()); } + } else if (TypeStr == "ref"sv) { + // "ref" fits all reference types. + if (!Got.second.isRefType()) { + return false; + } + return IsRefMatch(Got.first.get<RefVariant>()); + } else if (TypeStr == "anyref"sv) { + // "anyref" fits all internal reference types. + if (!Got.second.isRefType() || Got.second.isExternRefType()) { + return false; + } + return IsRefMatch(Got.first.get<RefVariant>()); + } else if (TypeStr == "eqref"sv) { + // "eqref" fits eqref, structref, arrayref, i31ref, and nullref. + if (!Got.second.isRefType()) { + return false; + } + switch (Got.second.getHeapTypeCode()) { + case TypeCode::EqRef: + case TypeCode::I31Ref: + case TypeCode::StructRef: + case TypeCode::ArrayRef: + case TypeCode::NullRef: + break; + default: + return false; + } + return IsRefMatch(Got.first.get<RefVariant>()); + } else if (TypeStr == "structref"sv) { + // "structref" structref and nullref. + if (!Got.second.isRefType()) { + return false; + } + switch (Got.second.getHeapTypeCode()) { + case TypeCode::StructRef: + case TypeCode::NullRef: + break; + default: + return false; + } + return IsRefMatch(Got.first.get<RefVariant>()); + } else if (TypeStr == "arrayref"sv) { + // "arrayref" arrayref and nullref. + if (!Got.second.isRefType()) { + return false; + } + switch (Got.second.getHeapTypeCode()) { + case TypeCode::ArrayRef: + case TypeCode::NullRef: + break; + default: + return false; + } + return IsRefMatch(Got.first.get<RefVariant>()); + } else if (TypeStr == "i31ref"sv) { + // "i31ref" i31ref and nullref. + if (!Got.second.isRefType()) { + return false; + } + switch (Got.second.getHeapTypeCode()) { + case TypeCode::I31Ref: + case TypeCode::NullRef: + break; + default: + return false; + } + return IsRefMatch(Got.first.get<RefVariant>()); + } else if (TypeStr == "nullref"sv) { + if (!Got.second.isRefType() || + Got.second.getHeapTypeCode() != TypeCode::NullRef) { + return false; + } + return IsRefMatch(Got.first.get<RefVariant>()); } else if (TypeStr == "funcref"sv) { + // "funcref" fits funcref and nullfuncref. if (!Got.second.isFuncRefType()) { return false; } - if (ValStr == "null"sv) { - return Got.first.get<RefVariant>().isNull(); - } else { - // Due to the implementations of the embedders, the value of FuncRef is - // opaque. Therefore not to compare the value here. - return !Got.first.get<RefVariant>().isNull(); + return IsRefMatch(Got.first.get<RefVariant>()); + } else if (TypeStr == "nullfuncref"sv) { + if (!Got.second.isRefType() || + Got.second.getHeapTypeCode() != TypeCode::NullFuncRef) { + return false; } + return IsRefMatch(Got.first.get<RefVariant>()); } else if (TypeStr == "externref"sv) { + // "externref" fits externref and nullexternref. if (!Got.second.isExternRefType()) { return false; } - if (ValStr == "null"sv) { - return Got.first.get<RefVariant>().isNull(); - } else { - if (Got.first.get<RefVariant>().isNull()) { - return false; - } - return static_cast<uint32_t>(reinterpret_cast<uintptr_t>( - &WasmEdge::retrieveExternRef<uint32_t>( - Got.first.get<RefVariant>()))) == - static_cast<uint32_t>(std::stoul(ValStr)); - } - } else if (TypeStr == "ref"sv) { - if (!Got.second.isNullableRefType()) { + return IsRefMatch(Got.first.get<RefVariant>()); + } else if (TypeStr == "nullexternref"sv) { + if (!Got.second.isRefType() || + Got.second.getHeapTypeCode() != TypeCode::NullExternRef) { return false; } - if (ValStr == "null"sv) { - return Got.first.get<RefVariant>().isNull(); - } else { - // Due to the implementations of the embedders, the value of Ref is - // opaque. Therefore not to compare the value here. - return !Got.first.get<RefVariant>().isNull(); + return IsRefMatch(Got.first.get<RefVariant>()); + } else if (TypeStr == "exnref"sv) { + if (!Got.second.isRefType() || + Got.second.getHeapTypeCode() != TypeCode::ExnRef) { + return false; } + return IsRefMatch(Got.first.get<RefVariant>()); } else if (TypeStr == "i32"sv) { if (Got.second.getCode() != TypeCode::I32) { return false; @@ -573,6 +679,32 @@ void SpecTest::run(std::string_view Proposal, std::string_view UnitName) { } }; + auto InvokeEither = [&](const simdjson::dom::object &Action, + const simdjson::dom::array &Eithers, + uint64_t LineNumber) { + const auto ModName = GetModuleName(Action); + const std::string_view Field = Action["field"]; + simdjson::dom::array Args = Action["args"]; + const auto Params = parseValueList(Args); + const auto Returns = parseEithersList(Eithers); + + // Invoke function of named module. Named modules are registered in Store + // Manager. Anonymous modules are instantiated in VM. + if (auto Res = onInvoke(ModName, std::string(Field), Params.first, + Params.second)) { + // Check value. + for (auto &Maybe : Returns) { + if (compares(Maybe, *Res)) { + return; + } + } + EXPECT_TRUE(compares(Returns[0], *Res)) + << "This is One of available returns."; + } else { + EXPECT_NE(LineNumber, LineNumber); + } + }; + // Helper function to get values. auto Get = [&](const simdjson::dom::object &Action, const simdjson::dom::array &Expected, uint64_t LineNumber) { @@ -629,6 +761,20 @@ void SpecTest::run(std::string_view Proposal, std::string_view UnitName) { stringContains(Text, WasmEdge::ErrCodeStr[Res.error().getEnum()])); } }; + auto ExceptionInvoke = [&](const simdjson::dom::object &Action, + uint64_t LineNumber) { + const auto ModName = GetModuleName(Action); + const std::string_view Field = Action["field"]; + simdjson::dom::array Args = Action["args"]; + const auto Params = parseValueList(Args); + + if (auto Res = onInvoke(ModName, std::string(Field), Params.first, + Params.second)) { + EXPECT_NE(LineNumber, LineNumber); + } else { + EXPECT_EQ(Res.error(), WasmEdge::ErrCode::Value::UncaughtException); + } + }; // Command processing. Return true for expected result. auto RunCommand = [&](const simdjson::dom::object &Cmd) { @@ -677,21 +823,30 @@ void SpecTest::run(std::string_view Proposal, std::string_view UnitName) { case CommandID::AssertReturn: { const uint64_t LineNumber = Cmd["line"]; const simdjson::dom::object &Action = Cmd["action"]; - const simdjson::dom::array &Expected = Cmd["expected"]; const std::string_view ActType = Action["type"]; - if (ActType == "invoke"sv) { - Invoke(Action, Expected, LineNumber); - return; - } else if (ActType == "get"sv) { - Get(Action, Expected, LineNumber); - return; + simdjson::dom::array Expected, Either; + + if (Cmd["expected"].get(Expected) == simdjson::error_code::SUCCESS) { + if (ActType == "invoke"sv) { + Invoke(Action, Expected, LineNumber); + return; + } else if (ActType == "get"sv) { + Get(Action, Expected, LineNumber); + return; + } + } else if (Cmd["either"].get(Either) == simdjson::error_code::SUCCESS) { + if (ActType == "invoke"sv) { + InvokeEither(Action, Either, LineNumber); + return; + } } + EXPECT_TRUE(false); return; } case CommandID::AssertTrap: { const simdjson::dom::object &Action = Cmd["action"]; - const std::string_view &Text = Cmd["text"]; + const std::string_view Text = Cmd["text"]; const uint64_t LineNumber = Cmd["line"]; TrapInvoke(Action, std::string(Text), LineNumber); return; @@ -701,35 +856,47 @@ void SpecTest::run(std::string_view Proposal, std::string_view UnitName) { return; } case CommandID::AssertMalformed: { - const std::string_view &ModType = Cmd["module_type"]; + const std::string_view ModType = Cmd["module_type"]; if (ModType != "binary"sv) { // TODO: Wat is not supported in WasmEdge yet. return; } - const std::string_view &Name = Cmd["filename"]; + const std::string_view Name = Cmd["filename"]; const auto Filename = (TestsuiteRoot / Proposal / UnitName / Name).u8string(); - const std::string_view &Text = Cmd["text"]; + const std::string_view Text = Cmd["text"]; TrapLoad(Filename, std::string(Text)); return; } case CommandID::AssertInvalid: { - const std::string_view &Name = Cmd["filename"]; + const std::string_view Name = Cmd["filename"]; const auto Filename = (TestsuiteRoot / Proposal / UnitName / Name).u8string(); - const std::string_view &Text = Cmd["text"]; + const std::string_view Text = Cmd["text"]; TrapValidate(Filename, std::string(Text)); return; } case CommandID::AssertUnlinkable: case CommandID::AssertUninstantiable: { - const std::string_view &Name = Cmd["filename"]; + const std::string_view Name = Cmd["filename"]; const auto Filename = (TestsuiteRoot / Proposal / UnitName / Name).u8string(); - const std::string_view &Text = Cmd["text"]; + const std::string_view Text = Cmd["text"]; TrapInstantiate(Filename, std::string(Text)); return; } + case CommandID::AssertException: { + const simdjson::dom::object &Action = Cmd["action"]; + const std::string_view ActType = Action["type"]; + const uint64_t LineNumber = Cmd["line"]; + // TODO: Check expected exception type + if (ActType == "invoke"sv) { + ExceptionInvoke(Action, LineNumber); + return; + } + EXPECT_TRUE(false); + return; + } default:; } } diff --git a/test/spec/spectest.h b/test/spec/spectest.h index 9d53ae5cd5c2..eb022ef9505c 100644 --- a/test/spec/spectest.h +++ b/test/spec/spectest.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/spec/spectest.h - Wasm test suites ------------------===// // @@ -44,6 +44,7 @@ class SpecTest { AssertInvalid, AssertUnlinkable, AssertUninstantiable, + AssertException, }; enum class TestMode : uint8_t { diff --git a/test/thread/CMakeLists.txt b/test/thread/CMakeLists.txt index 8d458d509b12..864121d72133 100644 --- a/test/thread/CMakeLists.txt +++ b/test/thread/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedgeThreadTests ThreadTest.cpp @@ -14,13 +14,13 @@ target_link_libraries(wasmedgeThreadTests wasmedgeVM ) -if(WASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) target_compile_definitions(wasmedgeThreadTests PRIVATE - -DWASMEDGE_BUILD_AOT_RUNTIME + -DWASMEDGE_USE_LLVM ) target_link_libraries(wasmedgeThreadTests PRIVATE - wasmedgeAOT + wasmedgeLLVM ) endif() diff --git a/test/thread/ThreadTest.cpp b/test/thread/ThreadTest.cpp index 61b9d7969a86..cd580d8b5009 100644 --- a/test/thread/ThreadTest.cpp +++ b/test/thread/ThreadTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/thread/ThreadTest.cpp - Multithread test ------------===// // @@ -12,11 +12,12 @@ /// //===----------------------------------------------------------------------===// -#include "common/log.h" +#include "common/spdlog.h" #include "vm/vm.h" -#ifdef WASMEDGE_BUILD_AOT_RUNTIME -#include "aot/compiler.h" +#ifdef WASMEDGE_USE_LLVM +#include "llvm/codegen.h" +#include "llvm/compiler.h" #endif #include "gtest/gtest.h" @@ -225,7 +226,7 @@ TEST(AsyncExecute, GasThreadTest) { } } -#ifdef WASMEDGE_BUILD_AOT_RUNTIME +#ifdef WASMEDGE_USE_LLVM TEST(AOTAsyncExecute, ThreadTest) { WasmEdge::Configure Conf; @@ -238,10 +239,13 @@ TEST(AOTAsyncExecute, ThreadTest) { { WasmEdge::Loader::Loader Loader(Conf); WasmEdge::Validator::Validator ValidatorEngine(Conf); - WasmEdge::AOT::Compiler Compiler(Conf); + WasmEdge::LLVM::Compiler Compiler(Conf); + WasmEdge::LLVM::CodeGen CodeGen(Conf); auto Module = *Loader.parseModule(MersenneTwister19937); ASSERT_TRUE(ValidatorEngine.validate(*Module)); - ASSERT_TRUE(Compiler.compile(MersenneTwister19937, *Module, Path)); + auto Data = Compiler.compile(*Module); + ASSERT_TRUE(Data); + ASSERT_TRUE(CodeGen.codegen(MersenneTwister19937, std::move(*Data), Path)); } WasmEdge::VM::VM VM(Conf); @@ -287,10 +291,13 @@ TEST(AOTAsyncExecute, GasThreadTest) { { WasmEdge::Loader::Loader Loader(Conf); WasmEdge::Validator::Validator ValidatorEngine(Conf); - WasmEdge::AOT::Compiler Compiler(Conf); + WasmEdge::LLVM::Compiler Compiler(Conf); + WasmEdge::LLVM::CodeGen CodeGen(Conf); auto Module = *Loader.parseModule(MersenneTwister19937); ASSERT_TRUE(ValidatorEngine.validate(*Module)); - ASSERT_TRUE(Compiler.compile(MersenneTwister19937, *Module, Path)); + auto Data = Compiler.compile(*Module); + ASSERT_TRUE(Data); + ASSERT_TRUE(CodeGen.codegen(MersenneTwister19937, std::move(*Data), Path)); } WasmEdge::VM::VM VM(Conf); diff --git a/test/thread/mt19937.c b/test/thread/mt19937.c index 9c9b40e8bff2..dc27aa368cf4 100644 --- a/test/thread/mt19937.c +++ b/test/thread/mt19937.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC //===-- wasmedge/test/thread/mt19937.c - MT19937 prng for testing ---------===// // diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 0d862b2f429b..0e295d6bdca1 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,7 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC -if(WASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) add_subdirectory(blake3) endif() - diff --git a/thirdparty/blake3/CMakeLists.txt b/thirdparty/blake3/CMakeLists.txt index 95008511a838..4eb18e408e41 100644 --- a/thirdparty/blake3/CMakeLists.txt +++ b/thirdparty/blake3/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC enable_language(ASM) @@ -34,7 +34,7 @@ macro(BLAKE3_DISABLE_SIMD) set(BLAKE3_SIMD_X86_INTRINSICS OFF) set(BLAKE3_SIMD_NEON_INTRINSICS OFF) set_source_files_properties(blake3_dispatch.c PROPERTIES - COMPILE_DEFINITIONS BLAKE3_USE_NEON=0;BLAKE3_NO_SSE2;BLAKE3_NO_SSE41;BLAKE3_NO_AVX2;BLAKE3_NO_AVX512 + COMPILE_DEFINITIONS "BLAKE3_USE_NEON=0;BLAKE3_NO_SSE2;BLAKE3_NO_SSE41;BLAKE3_NO_AVX2;BLAKE3_NO_AVX512" ) endmacro() diff --git a/thirdparty/blake3/blake3.c b/thirdparty/blake3/blake3.c index 692f4b021648..4d4d89f56d31 100644 --- a/thirdparty/blake3/blake3.c +++ b/thirdparty/blake3/blake3.c @@ -427,7 +427,7 @@ INLINE void hasher_merge_cv_stack(blake3_hasher *self, uint64_t total_len) { // of the whole tree, and it would need to be ROOT finalized. We can't // compress it until we know. // 2) This 64 KiB input might complete a larger tree, whose root node is -// similarly going to be the the root of the whole tree. For example, maybe +// similarly going to be the root of the whole tree. For example, maybe // we have 196 KiB (that is, 128 + 64) hashed so far. We can't compress the // node at the root of the 256 KiB subtree until we know how to finalize it. // diff --git a/thirdparty/blake3/blake3_avx2_x86-64_unix.S b/thirdparty/blake3/blake3_avx2_x86-64_unix.S index 812bb8568295..9da952bc60c4 100644 --- a/thirdparty/blake3/blake3_avx2_x86-64_unix.S +++ b/thirdparty/blake3/blake3_avx2_x86-64_unix.S @@ -1812,4 +1812,3 @@ CMP_MSB_MASK: .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 BLAKE3_IV: .long 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A - diff --git a/thirdparty/blake3/blake3_avx2_x86-64_windows_gnu.S b/thirdparty/blake3/blake3_avx2_x86-64_windows_gnu.S index 3d4be4a7d7cb..9043637cc53f 100644 --- a/thirdparty/blake3/blake3_avx2_x86-64_windows_gnu.S +++ b/thirdparty/blake3/blake3_avx2_x86-64_windows_gnu.S @@ -1814,4 +1814,3 @@ CMP_MSB_MASK: .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 BLAKE3_IV: .long 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A - diff --git a/thirdparty/blake3/blake3_sse41_x86-64_windows_msvc.asm b/thirdparty/blake3/blake3_sse41_x86-64_windows_msvc.asm index 8966c7b84406..97337cb47ead 100644 --- a/thirdparty/blake3/blake3_sse41_x86-64_windows_msvc.asm +++ b/thirdparty/blake3/blake3_sse41_x86-64_windows_msvc.asm @@ -2086,4 +2086,3 @@ CMP_MSB_MASK: _RDATA ENDS END - diff --git a/thirdparty/ggml/ggml.patch b/thirdparty/ggml/ggml.patch deleted file mode 100644 index dafaff70dbdc..000000000000 --- a/thirdparty/ggml/ggml.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/llama.cpp b/llama.cpp -index 5329bd8..fa2b3d2 100644 ---- a/llama.cpp -+++ b/llama.cpp -@@ -9625,7 +9625,9 @@ static void llama_log_internal(ggml_log_level level, const char * format, ...) { - - static void llama_log_callback_default(ggml_log_level level, const char * text, void * user_data) { - (void) level; -- (void) user_data; -- fputs(text, stderr); -- fflush(stderr); -+ bool * enable_log = static_cast<bool *>(user_data); -+ if (enable_log && *enable_log) { -+ fputs(text, stderr); -+ fflush(stderr); -+ } - } diff --git a/thirdparty/wasi/api.hpp b/thirdparty/wasi/api.hpp index 80a1b453af0e..9292ef91e2cc 100644 --- a/thirdparty/wasi/api.hpp +++ b/thirdparty/wasi/api.hpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC /** * THIS FILE IS AUTO-GENERATED from the following files: diff --git a/thirdparty/wasi_crypto/api.hpp b/thirdparty/wasi_crypto/api.hpp index 8d6f60817d28..71bed3d2288b 100644 --- a/thirdparty/wasi_crypto/api.hpp +++ b/thirdparty/wasi_crypto/api.hpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC /** * THIS FILE IS AUTO-GENERATED from the following files: @@ -400,7 +400,7 @@ static_assert(alignof(__wasi_algorithm_type_e_t) == 2, "witx calculated align"); /** * Version of a managed key. * - * A version can be an arbitrary `u64` integer, with the expection of some reserved values. + * A version can be an arbitrary `u64` integer, with the exception of some reserved values. */ using __wasi_version_t = uint64_t; @@ -544,7 +544,7 @@ static_assert(alignof(__wasi_symmetric_key_t) == 4, "witx calculated align"); * * This object type can't be directly created from raw bytes. They are only returned by functions computing MACs. * - * The host is reponsible for securely wiping them from memory on close. + * The host is responsible for securely wiping them from memory on close. */ using __wasi_symmetric_tag_t = int32_t; @@ -673,4 +673,3 @@ using __wasi_signature_secretkey_t = __wasi_secretkey_t; static_assert(sizeof(__wasi_signature_secretkey_t) == 4, "witx calculated size"); static_assert(alignof(__wasi_signature_secretkey_t) == 4, "witx calculated align"); - diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index daf84c6fe42f..486e76112172 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC if(WASMEDGE_BUILD_TOOLS) add_subdirectory(wasmedge) diff --git a/tools/fuzz/CMakeLists.txt b/tools/fuzz/CMakeLists.txt index 3752b5de426e..e9ea4f4aef1d 100644 --- a/tools/fuzz/CMakeLists.txt +++ b/tools/fuzz/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC wasmedge_add_executable(wasmedge-fuzztool tool.cpp diff --git a/tools/fuzz/po.cpp b/tools/fuzz/po.cpp index 7ba9e43cc30e..e8ec19172238 100644 --- a/tools/fuzz/po.cpp +++ b/tools/fuzz/po.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "wasmedge/wasmedge.h" #include <stddef.h> diff --git a/tools/fuzz/tool.cpp b/tools/fuzz/tool.cpp index c663faaca07e..5fc84bb9ef3a 100644 --- a/tools/fuzz/tool.cpp +++ b/tools/fuzz/tool.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "wasmedge/wasmedge.h" #include <stddef.h> diff --git a/tools/wasmedge/CMakeLists.txt b/tools/wasmedge/CMakeLists.txt index a886510d4cbf..1658fa2a3767 100644 --- a/tools/wasmedge/CMakeLists.txt +++ b/tools/wasmedge/CMakeLists.txt @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC -if(WASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) wasmedge_add_executable(wasmedgec wasmedgec.cpp ) diff --git a/tools/wasmedge/wasi_nn_rpcserver.cpp b/tools/wasmedge/wasi_nn_rpcserver.cpp index f740101eaf9b..27725d7d7bcb 100644 --- a/tools/wasmedge/wasi_nn_rpcserver.cpp +++ b/tools/wasmedge/wasi_nn_rpcserver.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "wasmedge/wasmedge.h" diff --git a/tools/wasmedge/wasmedge.cpp b/tools/wasmedge/wasmedge.cpp index 6eb66de8134d..2c5ac2c45e04 100644 --- a/tools/wasmedge/wasmedge.cpp +++ b/tools/wasmedge/wasmedge.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "wasmedge/wasmedge.h" diff --git a/tools/wasmedge/wasmedgec.cpp b/tools/wasmedge/wasmedgec.cpp index 35915dc614a2..bc9b4453e4a0 100644 --- a/tools/wasmedge/wasmedgec.cpp +++ b/tools/wasmedge/wasmedgec.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "wasmedge/wasmedge.h" diff --git a/utils/android/app/.idea/.name b/utils/android/app/.idea/.name index 47c1cd9314b8..d9069869d4b3 100644 --- a/utils/android/app/.idea/.name +++ b/utils/android/app/.idea/.name @@ -1 +1 @@ -WasmEdgeApp \ No newline at end of file +WasmEdgeApp diff --git a/utils/android/app/.idea/compiler.xml b/utils/android/app/.idea/compiler.xml index fb7f4a8a465d..5421743a9c26 100644 --- a/utils/android/app/.idea/compiler.xml +++ b/utils/android/app/.idea/compiler.xml @@ -3,4 +3,4 @@ <component name="CompilerConfiguration"> <bytecodeTargetLevel target="11" /> </component> -</project> \ No newline at end of file +</project> diff --git a/utils/android/app/.idea/gradle.xml b/utils/android/app/.idea/gradle.xml index 3b22eca12a35..a8286d05fd2b 100644 --- a/utils/android/app/.idea/gradle.xml +++ b/utils/android/app/.idea/gradle.xml @@ -18,4 +18,4 @@ </GradleProjectSettings> </option> </component> -</project> \ No newline at end of file +</project> diff --git a/utils/android/app/.idea/misc.xml b/utils/android/app/.idea/misc.xml index 167f93e8c63a..fb242abb68b4 100644 --- a/utils/android/app/.idea/misc.xml +++ b/utils/android/app/.idea/misc.xml @@ -13,4 +13,4 @@ <component name="ProjectType"> <option name="id" value="Android" /> </component> -</project> \ No newline at end of file +</project> diff --git a/utils/android/app/.idea/vcs.xml b/utils/android/app/.idea/vcs.xml index c2365ab11f9b..fbbc5665e98a 100644 --- a/utils/android/app/.idea/vcs.xml +++ b/utils/android/app/.idea/vcs.xml @@ -3,4 +3,4 @@ <component name="VcsDirectoryMappings"> <mapping directory="$PROJECT_DIR$/../../.." vcs="Git" /> </component> -</project> \ No newline at end of file +</project> diff --git a/utils/android/app/app/.gitignore b/utils/android/app/app/.gitignore index 42afabfd2abe..796b96d1c402 100644 --- a/utils/android/app/app/.gitignore +++ b/utils/android/app/app/.gitignore @@ -1 +1 @@ -/build \ No newline at end of file +/build diff --git a/utils/android/app/app/build.gradle b/utils/android/app/app/build.gradle index 4f9b7f1fc216..9467dbfaa83f 100644 --- a/utils/android/app/app/build.gradle +++ b/utils/android/app/app/build.gradle @@ -35,4 +35,4 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.5.0' implementation project(path: ':lib') -} \ No newline at end of file +} diff --git a/utils/android/app/app/proguard-rules.pro b/utils/android/app/app/proguard-rules.pro index 481bb4348141..f1b424510da5 100644 --- a/utils/android/app/app/proguard-rules.pro +++ b/utils/android/app/app/proguard-rules.pro @@ -18,4 +18,4 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile diff --git a/utils/android/app/app/src/main/AndroidManifest.xml b/utils/android/app/app/src/main/AndroidManifest.xml index 3f591646d1cd..0bf2feaed9ba 100644 --- a/utils/android/app/app/src/main/AndroidManifest.xml +++ b/utils/android/app/app/src/main/AndroidManifest.xml @@ -20,4 +20,4 @@ </activity> </application> -</manifest> \ No newline at end of file +</manifest> diff --git a/utils/android/app/app/src/main/java/org/wasmedge/example_app/MainActivity.kt b/utils/android/app/app/src/main/java/org/wasmedge/example_app/MainActivity.kt index d5fac6b43d7c..7d15d9df8b49 100644 --- a/utils/android/app/app/src/main/java/org/wasmedge/example_app/MainActivity.kt +++ b/utils/android/app/app/src/main/java/org/wasmedge/example_app/MainActivity.kt @@ -37,4 +37,4 @@ class MainActivity : AppCompatActivity() { } }.start() } -} \ No newline at end of file +} diff --git a/utils/android/app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/utils/android/app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml index 2b068d11462a..7706ab9e6d40 100644 --- a/utils/android/app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ b/utils/android/app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -27,4 +27,4 @@ android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z" android:strokeWidth="1" android:strokeColor="#00000000" /> -</vector> \ No newline at end of file +</vector> diff --git a/utils/android/app/app/src/main/res/layout/activity_main.xml b/utils/android/app/app/src/main/res/layout/activity_main.xml index e56f4cdf4427..fbd56bd110a3 100644 --- a/utils/android/app/app/src/main/res/layout/activity_main.xml +++ b/utils/android/app/app/src/main/res/layout/activity_main.xml @@ -16,4 +16,4 @@ app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> -</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/utils/android/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/utils/android/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index eca70cfe52ea..6b78462d615b 100644 --- a/utils/android/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/utils/android/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -2,4 +2,4 @@ <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <background android:drawable="@drawable/ic_launcher_background" /> <foreground android:drawable="@drawable/ic_launcher_foreground" /> -</adaptive-icon> \ No newline at end of file +</adaptive-icon> diff --git a/utils/android/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/utils/android/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index eca70cfe52ea..6b78462d615b 100644 --- a/utils/android/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/utils/android/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -2,4 +2,4 @@ <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <background android:drawable="@drawable/ic_launcher_background" /> <foreground android:drawable="@drawable/ic_launcher_foreground" /> -</adaptive-icon> \ No newline at end of file +</adaptive-icon> diff --git a/utils/android/app/app/src/main/res/values-night/themes.xml b/utils/android/app/app/src/main/res/values-night/themes.xml index f33dbf5ccda0..85edb2422f9b 100644 --- a/utils/android/app/app/src/main/res/values-night/themes.xml +++ b/utils/android/app/app/src/main/res/values-night/themes.xml @@ -13,4 +13,4 @@ <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item> <!-- Customize your theme here. --> </style> -</resources> \ No newline at end of file +</resources> diff --git a/utils/android/app/app/src/main/res/values/colors.xml b/utils/android/app/app/src/main/res/values/colors.xml index f8c6127d3276..ca1931bca99e 100644 --- a/utils/android/app/app/src/main/res/values/colors.xml +++ b/utils/android/app/app/src/main/res/values/colors.xml @@ -7,4 +7,4 @@ <color name="teal_700">#FF018786</color> <color name="black">#FF000000</color> <color name="white">#FFFFFFFF</color> -</resources> \ No newline at end of file +</resources> diff --git a/utils/android/app/app/src/main/res/values/strings.xml b/utils/android/app/app/src/main/res/values/strings.xml index 4112b363107e..40b5f63709ad 100644 --- a/utils/android/app/app/src/main/res/values/strings.xml +++ b/utils/android/app/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ <resources> <string name="app_name">WasmEdgeApp</string> -</resources> \ No newline at end of file +</resources> diff --git a/utils/android/app/app/src/main/res/values/themes.xml b/utils/android/app/app/src/main/res/values/themes.xml index e0eb6d7d6db8..f0ed1d1b8d8b 100644 --- a/utils/android/app/app/src/main/res/values/themes.xml +++ b/utils/android/app/app/src/main/res/values/themes.xml @@ -13,4 +13,4 @@ <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item> <!-- Customize your theme here. --> </style> -</resources> \ No newline at end of file +</resources> diff --git a/utils/android/app/build.gradle b/utils/android/app/build.gradle index 7ab671837f10..7204abadeffb 100644 --- a/utils/android/app/build.gradle +++ b/utils/android/app/build.gradle @@ -15,4 +15,4 @@ buildscript { task clean(type: Delete) { delete rootProject.buildDir -} \ No newline at end of file +} diff --git a/utils/android/app/gradle.properties b/utils/android/app/gradle.properties index 52f5917cb0d0..01b80d70cf54 100644 --- a/utils/android/app/gradle.properties +++ b/utils/android/app/gradle.properties @@ -16,4 +16,4 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX -android.enableJetifier=true \ No newline at end of file +android.enableJetifier=true diff --git a/utils/android/app/lib/.gitignore b/utils/android/app/lib/.gitignore index 42afabfd2abe..796b96d1c402 100644 --- a/utils/android/app/lib/.gitignore +++ b/utils/android/app/lib/.gitignore @@ -1 +1 @@ -/build \ No newline at end of file +/build diff --git a/utils/android/app/lib/build.gradle b/utils/android/app/lib/build.gradle index 1711aedade9d..a5722c56844a 100644 --- a/utils/android/app/lib/build.gradle +++ b/utils/android/app/lib/build.gradle @@ -55,4 +55,3 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.5.0' } - diff --git a/utils/android/app/lib/proguard-rules.pro b/utils/android/app/lib/proguard-rules.pro index 481bb4348141..f1b424510da5 100644 --- a/utils/android/app/lib/proguard-rules.pro +++ b/utils/android/app/lib/proguard-rules.pro @@ -18,4 +18,4 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile diff --git a/utils/android/app/lib/src/main/AndroidManifest.xml b/utils/android/app/lib/src/main/AndroidManifest.xml index af7be94ad61f..b2c9f265d071 100644 --- a/utils/android/app/lib/src/main/AndroidManifest.xml +++ b/utils/android/app/lib/src/main/AndroidManifest.xml @@ -2,4 +2,4 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.wasmedge.native_lib"> -</manifest> \ No newline at end of file +</manifest> diff --git a/utils/android/app/lib/src/main/cpp/CMakeLists.txt b/utils/android/app/lib/src/main/cpp/CMakeLists.txt index 5855009e86b0..12635680fc3c 100644 --- a/utils/android/app/lib/src/main/cpp/CMakeLists.txt +++ b/utils/android/app/lib/src/main/cpp/CMakeLists.txt @@ -3,10 +3,10 @@ cmake_minimum_required(VERSION 3.22.1) project("wasmedge_lib") set(WASMEDGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../..) -set(WASMEDGE_BUILD_AOT_RUNTIME OFF CACHE BOOL "" FORCE) set(WASMEDGE_BUILD_PLUGINS OFF CACHE BOOL "" FORCE) set(WASMEDGE_BUILD_TOOLS OFF CACHE BOOL "" FORCE) set(WASMEDGE_BUILD_SHARED_LIB ON CACHE BOOL "" FORCE) +set(WASMEDGE_USE_LLVM OFF CACHE BOOL "" FORCE) set(WASMEDGE_FORCE_DISABLE_LTO ON CACHE BOOL "" FORCE) # fast fixed problem for `-fuse-ld=gold`, we use lld. if (CMAKE_GENERATOR STREQUAL Ninja) set(CMAKE_JOB_POOLS "link=2") diff --git a/utils/android/app/lib/src/main/cpp/wasmedge_lib.cpp b/utils/android/app/lib/src/main/cpp/wasmedge_lib.cpp index ed86207d4f5d..1cd537b8548b 100644 --- a/utils/android/app/lib/src/main/cpp/wasmedge_lib.cpp +++ b/utils/android/app/lib/src/main/cpp/wasmedge_lib.cpp @@ -34,4 +34,3 @@ Java_org_wasmedge_native_1lib_NativeLib_nativeWasmFibonacci(JNIEnv *env, jobject } return WasmEdge_ValueGetI32(ret_val[0]); } - diff --git a/utils/android/app/lib/src/main/java/org/wasmedge/native_lib/NativeLib.kt b/utils/android/app/lib/src/main/java/org/wasmedge/native_lib/NativeLib.kt index 0dcada1824d0..08b7f5482df9 100644 --- a/utils/android/app/lib/src/main/java/org/wasmedge/native_lib/NativeLib.kt +++ b/utils/android/app/lib/src/main/java/org/wasmedge/native_lib/NativeLib.kt @@ -16,4 +16,4 @@ class NativeLib(ctx : Context) { fun wasmFibonacci(idx : Int) : Int{ return nativeWasmFibonacci(fibonacciWasmImageBytes, idx) } -} \ No newline at end of file +} diff --git a/utils/android/standalone/build_for_android.sh b/utils/android/standalone/build_for_android.sh index 6f50107d64f5..920605cf9ebb 100755 --- a/utils/android/standalone/build_for_android.sh +++ b/utils/android/standalone/build_for_android.sh @@ -11,7 +11,7 @@ WASMEDGE_ROOT_PATH=$(dirname $(dirname $(dirname $(dirname $0)))) cd ${WASMEDGE_ROOT_PATH} -if ! cmake -Bbuild -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=23 -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a -DCMAKE_ANDROID_NDK=$ANDROID_NDK_HOME -DCMAKE_ANDROID_STL_TYPE=c++_static; then +if ! cmake -Bbuild -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_USE_LLVM=OFF -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=23 -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a -DCMAKE_ANDROID_NDK=$ANDROID_NDK_HOME -DCMAKE_ANDROID_STL_TYPE=c++_static; then echo === CMakeOutput.log === cat build/CMakeFiles/CMakeOutput.log echo === CMakeError.log === diff --git a/utils/docker/Dockerfile.alpine-static b/utils/docker/Dockerfile.alpine-static index d92dd8da5f77..36e936af9016 100644 --- a/utils/docker/Dockerfile.alpine-static +++ b/utils/docker/Dockerfile.alpine-static @@ -62,7 +62,7 @@ RUN --mount=type=bind,target=/src,source=. \ # For cross compiling -DCMAKE_TOOLCHAIN_FILE="$(xx-toolchain)" \ -DWASMEDGE_BUILD_PACKAGE="TGZ" \ - -DWASMEDGE_BUILD_AOT_RUNTIME=ON \ + -DWASMEDGE_USE_LLVM=ON \ # Build just what we need -DWASMEDGE_BUILD_STATIC_LIB=ON \ -DWASMEDGE_BUILD_TESTS=OFF \ diff --git a/utils/docker/Dockerfile.base b/utils/docker/Dockerfile.base deleted file mode 100644 index db431fb981fc..000000000000 --- a/utils/docker/Dockerfile.base +++ /dev/null @@ -1,19 +0,0 @@ -FROM ubuntu:22.04 - -MAINTAINER hydai hydai@secondstate.io -ENV DEBIAN_FRONTEND=noninteractive - -RUN apt update && apt upgrade -y \ - && apt install -y \ - software-properties-common \ - dpkg-dev \ - wget \ - cmake \ - ninja-build \ - curl \ - git \ - zlib1g-dev \ - llvm-15-dev \ - liblld-15-dev - -RUN rm -rf /var/lib/apt/lists/* diff --git a/utils/docker/Dockerfile.build-clang b/utils/docker/Dockerfile.build-clang deleted file mode 100644 index bed2409b9eb4..000000000000 --- a/utils/docker/Dockerfile.build-clang +++ /dev/null @@ -1,10 +0,0 @@ -ARG BASE=wasmedge/wasmedge:ubuntu-base -FROM ${BASE} - -RUN apt update && apt install -y \ - clang-15 - -RUN rm -rf /var/lib/apt/lists/* - -ENV CC=/usr/bin/clang-15 -ENV CXX=/usr/bin/clang++-15 diff --git a/utils/docker/Dockerfile.build-gcc b/utils/docker/Dockerfile.build-gcc deleted file mode 100644 index 120641145b74..000000000000 --- a/utils/docker/Dockerfile.build-gcc +++ /dev/null @@ -1,11 +0,0 @@ -ARG BASE=wasmedge/wasmedge:ubuntu-base -FROM ${BASE} - -RUN apt update && apt install -y \ - gcc \ - g++ - -RUN rm -rf /var/lib/apt/lists/* - -ENV CC=gcc -ENV CXX=g++ diff --git a/utils/docker/Dockerfile.build-plugins-deps b/utils/docker/Dockerfile.build-plugins-deps deleted file mode 100644 index 21c73d977aaa..000000000000 --- a/utils/docker/Dockerfile.build-plugins-deps +++ /dev/null @@ -1,12 +0,0 @@ -ARG BASE=wasmedge/wasmedge:ubuntu-build-clang -FROM ${BASE} - -RUN apt update && apt install -y \ - wget \ - unzip - -RUN rm -rf /var/lib/apt/lists/* - -COPY install-opencvmini.sh . -ENV OPENCV_VERSION=4.8.0 -RUN [ "/bin/bash", "install-opencvmini.sh" ] diff --git a/utils/docker/Dockerfile.ci-image-base b/utils/docker/Dockerfile.ci-image-base index 4c7fa368fa56..15a854af3803 100644 --- a/utils/docker/Dockerfile.ci-image-base +++ b/utils/docker/Dockerfile.ci-image-base @@ -1,6 +1,5 @@ FROM ubuntu:22.04 -MAINTAINER hydai hydai@secondstate.io ENV DEBIAN_FRONTEND=noninteractive RUN apt update && apt upgrade -y \ @@ -13,7 +12,7 @@ RUN apt update && apt upgrade -y \ RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - RUN add-apt-repository \ - "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ + "deb [arch=$(dpkg --print-architecture)] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" diff --git a/utils/docker/Dockerfile.debian-static b/utils/docker/Dockerfile.debian-static index 7c43fc788193..cea1563b9fed 100644 --- a/utils/docker/Dockerfile.debian-static +++ b/utils/docker/Dockerfile.debian-static @@ -75,14 +75,14 @@ RUN cmake -S /src -B /build -G Ninja \ -DCMAKE_INSTALL_PREFIX=/install \ -DWASMEDGE_BUILD_PACKAGE="TGZ" \ -DWASMEDGE_BUILD_TESTS=OFF \ - -DWASMEDGE_BUILD_AOT_RUNTIME=ON \ -DWASMEDGE_BUILD_SHARED_LIB=OFF \ -DWASMEDGE_BUILD_STATIC_LIB=ON \ -DWASMEDGE_BUILD_TOOLS=OFF \ -DWASMEDGE_BUILD_PLUGINS=OFF \ -DWASMEDGE_BUILD_EXAMPLE=OFF \ -DWASMEDGE_LINK_LLVM_STATIC=ON \ - -DWASMEDGE_LINK_TOOLS_STATIC=ON + -DWASMEDGE_LINK_TOOLS_STATIC=ON \ + -DWASMEDGE_USE_LLVM=ON RUN cmake --build /build -- install RUN cmake --build /build -- package diff --git a/utils/docker/Dockerfile.manylinux2014-build-plugins-deps b/utils/docker/Dockerfile.manylinux2014-build-plugins-deps index 45bcd857cf1a..e2aab3eadcab 100644 --- a/utils/docker/Dockerfile.manylinux2014-build-plugins-deps +++ b/utils/docker/Dockerfile.manylinux2014-build-plugins-deps @@ -6,10 +6,33 @@ ENV MANPATH /opt/rh/devtoolset-11/root/usr/share/man${MANPATH:+:${MANPATH}} ENV INFOPATH /opt/rh/devtoolset-11/root/usr/share/info${INFOPATH:+:${INFOPATH}} ENV PKG_CONFIG_PATH /opt/rh/devtoolset-11/root/usr/lib64/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}} -RUN cd && (yum check-update || true) && yum install -y cmake wget unzip +RUN cd && (yum check-update || true) && \ + yum install -y cmake wget unzip zlib-devel zlib-static +RUN yum-config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo && \ + yum install -y gh -COPY install-opencvmini.sh . -ENV OPENCV_VERSION=4.8.0 +WORKDIR /root + +COPY opencvmini/install-opencvmini.sh . +ENV OPENCV_VERSION "4.8.0" RUN [ "/bin/bash", "install-opencvmini.sh" ] +COPY wasi-nn/install-pytorch.sh . +ENV PYTORCH_VERSION "1.8.2" +ENV PYTORCH_INSTALL_TO "/root" +ENV Torch_DIR "/root/libtorch" +RUN [ "/bin/bash", "install-pytorch.sh", "--disable-cxx11-abi" ] + +COPY wasi-crypto/build-openssl.sh . +ENV OPENSSL_ROOT_DIR "/root/openssl-1.1.1n/openssl" +RUN [ "/bin/bash", "build-openssl.sh" ] + +COPY ffmpeg/install-ffmpeg-v6.0.sh . +RUN [ "/bin/bash", "install-ffmpeg-v6.0.sh" ] +ENV PKG_CONFIG_PATH /root/FFmpeg-n6.0/output/lib/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}} +ENV LD_LIBRARY_PATH /root/FFmpeg-n6.0/output/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}} + +ENV OPENVINO_VERSION "2024.2.0" +ENV OPENVINO_YEAR "2024" + RUN yum clean all diff --git a/utils/docker/Dockerfile.manylinux2014_aarch64 b/utils/docker/Dockerfile.manylinux2014_aarch64 index 59ca239e828a..b666538854f5 100644 --- a/utils/docker/Dockerfile.manylinux2014_aarch64 +++ b/utils/docker/Dockerfile.manylinux2014_aarch64 @@ -1,11 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC FROM quay.io/pypa/manylinux2014_aarch64 MAINTAINER hydai hydai@secondstate.io -ADD SHA256SUM /root/ +ADD SHA256SUM.manylinux2014 /root/ ENV PATH /opt/rh/devtoolset-10/root/usr/bin${PATH:+:${PATH}} ENV MANPATH /opt/rh/devtoolset-10/root/usr/share/man${MANPATH:+:${MANPATH}} @@ -19,38 +19,38 @@ RUN cd && (yum check-update || true) && yum install -y xz openssl-devel rpm-buil export CFGFLAGS="--prefix=/opt/rh/devtoolset-10/root/usr --disable-shared --libdir=/opt/rh/devtoolset-10/root/usr/lib64" && \ curl -s -L -O --remote-name-all \ https://github.com/facebook/zstd/releases/download/v1.5.5/zstd-1.5.5.tar.gz \ - https://github.com/Kitware/CMake/releases/download/v3.26.4/cmake-3.26.4.tar.gz \ + https://github.com/Kitware/CMake/releases/download/v3.29.3/cmake-3.29.3.tar.gz \ https://github.com/ninja-build/ninja/archive/refs/tags/v1.11.1.tar.gz \ - https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.5/llvm-16.0.5.src.tar.xz \ - https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.5/lld-16.0.5.src.tar.xz \ - https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.5/libunwind-16.0.5.src.tar.xz \ - https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.5/cmake-16.0.5.src.tar.xz \ - https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.5/third-party-16.0.5.src.tar.xz \ - https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.5/clang-16.0.5.src.tar.xz && \ - sha256sum -c SHA256SUM && \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/llvm-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/lld-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/libunwind-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/cmake-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/third-party-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/clang-17.0.6.src.tar.xz && \ + sha256sum -c SHA256SUM.manylinux2014 && \ gzip -dc zstd-1.5.5.tar.gz | tar -xf - && \ - gzip -dc cmake-3.26.4.tar.gz | tar -xf - && \ + gzip -dc cmake-3.29.3.tar.gz | tar -xf - && \ gzip -dc v1.11.1.tar.gz | tar -xf - && \ - xz -dc llvm-16.0.5.src.tar.xz | tar -xf - && \ - xz -dc lld-16.0.5.src.tar.xz | tar -xf - && \ - xz -dc libunwind-16.0.5.src.tar.xz | tar -xf - && \ - xz -dc cmake-16.0.5.src.tar.xz | tar -xf - && \ - xz -dc third-party-16.0.5.src.tar.xz | tar -xf - && \ - xz -dc clang-16.0.5.src.tar.xz | tar -xf - && \ + xz -dc llvm-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc lld-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc libunwind-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc cmake-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc third-party-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc clang-17.0.6.src.tar.xz | tar -xf - && \ export ZSTDFLAGS=(PREFIX=/opt/rh/devtoolset-10/root/usr LIBDIR=/opt/rh/devtoolset-10/root/usr/lib64 SED_ERE_OPT=--regexp-extended MOREFLAGS="-std=c17 -O3 -fPIC -fPIE -fvisibility=hidden") && \ cd zstd-1.5.5 && make -s "${ZSTDFLAGS[@]}" -j $CPU && make -s "${ZSTDFLAGS[@]}" install && rm -vf /opt/rh/devtoolset-10/root/usr/lib64/libzstd.so* && cd - && \ mkdir build && cd build && /opt/python/cp311-cp311/bin/python \ ../ninja-1.11.1/configure.py --bootstrap \ --with-python=/opt/python/cp311-cp311/bin/python && \ cp -v ninja /opt/rh/devtoolset-10/root/usr/bin/ninja && cd - && rm -rf build && \ - mkdir build && cd build && ../cmake-3.26.4/configure --prefix=/opt/rh/devtoolset-10/root/usr \ + mkdir build && cd build && ../cmake-3.29.3/configure --prefix=/opt/rh/devtoolset-10/root/usr \ --parallel=$CPU && make -s -j $CPU && make -s install && cd - && rm -rf build && \ - mv -v llvm-16.0.5.src llvm && \ - mv -v lld-16.0.5.src lld && \ - mv -v libunwind-16.0.5.src libunwind && \ - mv -v cmake-16.0.5.src cmake && \ - mv -v third-party-16.0.5.src third-party && \ - mv -v clang-16.0.5.src clang && \ + mv -v llvm-17.0.6.src llvm && \ + mv -v lld-17.0.6.src lld && \ + mv -v libunwind-17.0.6.src libunwind && \ + mv -v cmake-17.0.6.src cmake && \ + mv -v third-party-17.0.6.src third-party && \ + mv -v clang-17.0.6.src clang && \ cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/opt/rh/devtoolset-10/root/usr \ -DPython3_ROOT_DIR=/opt/python/cp311-cp311 -DLLVM_LIBDIR_SUFFIX=64 \ diff --git a/utils/docker/Dockerfile.manylinux2014_x86_64 b/utils/docker/Dockerfile.manylinux2014_x86_64 index cc6a942a3a0f..da67eae9a9ef 100644 --- a/utils/docker/Dockerfile.manylinux2014_x86_64 +++ b/utils/docker/Dockerfile.manylinux2014_x86_64 @@ -1,11 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC FROM quay.io/pypa/manylinux2014_x86_64 MAINTAINER hydai hydai@secondstate.io -ADD SHA256SUM /root/ +ADD SHA256SUM.manylinux2014 /root/ ENV PATH /opt/rh/devtoolset-11/root/usr/bin${PATH:+:${PATH}} ENV MANPATH /opt/rh/devtoolset-11/root/usr/share/man${MANPATH:+:${MANPATH}} @@ -19,38 +19,38 @@ RUN cd && (yum check-update || true) && yum install -y xz openssl-devel rpm-buil export CFGFLAGS="--prefix=/opt/rh/devtoolset-11/root/usr --disable-shared --libdir=/opt/rh/devtoolset-11/root/usr/lib64" && \ curl -s -L -O --remote-name-all \ https://github.com/facebook/zstd/releases/download/v1.5.5/zstd-1.5.5.tar.gz \ - https://github.com/Kitware/CMake/releases/download/v3.26.4/cmake-3.26.4.tar.gz \ + https://github.com/Kitware/CMake/releases/download/v3.29.3/cmake-3.29.3.tar.gz \ https://github.com/ninja-build/ninja/archive/refs/tags/v1.11.1.tar.gz \ - https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.5/llvm-16.0.5.src.tar.xz \ - https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.5/lld-16.0.5.src.tar.xz \ - https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.5/libunwind-16.0.5.src.tar.xz \ - https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.5/cmake-16.0.5.src.tar.xz \ - https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.5/third-party-16.0.5.src.tar.xz \ - https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.5/clang-16.0.5.src.tar.xz && \ - sha256sum -c SHA256SUM && \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/llvm-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/lld-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/libunwind-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/cmake-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/third-party-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/clang-17.0.6.src.tar.xz && \ + sha256sum -c SHA256SUM.manylinux2014 && \ gzip -dc zstd-1.5.5.tar.gz | tar -xf - && \ - gzip -dc cmake-3.26.4.tar.gz | tar -xf - && \ + gzip -dc cmake-3.29.3.tar.gz | tar -xf - && \ gzip -dc v1.11.1.tar.gz | tar -xf - && \ - xz -dc llvm-16.0.5.src.tar.xz | tar -xf - && \ - xz -dc lld-16.0.5.src.tar.xz | tar -xf - && \ - xz -dc libunwind-16.0.5.src.tar.xz | tar -xf - && \ - xz -dc cmake-16.0.5.src.tar.xz | tar -xf - && \ - xz -dc third-party-16.0.5.src.tar.xz | tar -xf - && \ - xz -dc clang-16.0.5.src.tar.xz | tar -xf - && \ + xz -dc llvm-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc lld-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc libunwind-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc cmake-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc third-party-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc clang-17.0.6.src.tar.xz | tar -xf - && \ export ZSTDFLAGS=(PREFIX=/opt/rh/devtoolset-11/root/usr LIBDIR=/opt/rh/devtoolset-11/root/usr/lib64 SED_ERE_OPT=--regexp-extended MOREFLAGS="-std=c17 -O3 -fPIC -fPIE -fvisibility=hidden") && \ cd zstd-1.5.5 && make -s "${ZSTDFLAGS[@]}" -j $CPU && make -s "${ZSTDFLAGS[@]}" install && rm -vf /opt/rh/devtoolset-11/root/usr/lib64/libzstd.so* && cd - && \ mkdir build && cd build && /opt/python/cp311-cp311/bin/python \ ../ninja-1.11.1/configure.py --bootstrap \ --with-python=/opt/python/cp311-cp311/bin/python && \ cp -v ninja /opt/rh/devtoolset-11/root/usr/bin/ninja && cd - && rm -rf build && \ - mkdir build && cd build && ../cmake-3.26.4/configure --prefix=/opt/rh/devtoolset-11/root/usr \ + mkdir build && cd build && ../cmake-3.29.3/configure --prefix=/opt/rh/devtoolset-11/root/usr \ --parallel=$CPU && make -s -j $CPU && make -s install && cd - && rm -rf build && \ - mv -v llvm-16.0.5.src llvm && \ - mv -v lld-16.0.5.src lld && \ - mv -v libunwind-16.0.5.src libunwind && \ - mv -v cmake-16.0.5.src cmake && \ - mv -v third-party-16.0.5.src third-party && \ - mv -v clang-16.0.5.src clang && \ + mv -v llvm-17.0.6.src llvm && \ + mv -v lld-17.0.6.src lld && \ + mv -v libunwind-17.0.6.src libunwind && \ + mv -v cmake-17.0.6.src cmake && \ + mv -v third-party-17.0.6.src third-party && \ + mv -v clang-17.0.6.src clang && \ cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/opt/rh/devtoolset-11/root/usr \ -DPython3_ROOT_DIR=/opt/python/cp311-cp311 -DLLVM_LIBDIR_SUFFIX=64 \ diff --git a/utils/docker/Dockerfile.manylinux_2_28-base b/utils/docker/Dockerfile.manylinux_2_28-base new file mode 100644 index 000000000000..30b64c31d1b3 --- /dev/null +++ b/utils/docker/Dockerfile.manylinux_2_28-base @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# SPDX-FileCopyrightText: 2019-2024 Second State INC +ARG BASE_IMAGE="quay.io/pypa/manylinux_2_28_x86_64" +FROM ${BASE_IMAGE} + +ADD SHA256SUM.manylinux_2_28 /root/ + +# See /opt/rh/gcc-toolset-13/enable +ENV PATH=/opt/rh/gcc-toolset-13/root/usr/bin${PATH:+:${PATH}} +ENV MANPATH=/opt/rh/gcc-toolset-13/root/usr/share/man${MANPATH:+:${MANPATH}} +ENV INFOPATH=/opt/rh/gcc-toolset-13/root/usr/share/info${INFOPATH:+:${INFOPATH}} +ENV LD_LIBRARY_PATH=/opt/rh/gcc-toolset-13/root/usr/lib64:/opt/rh/gcc-toolset-13/root/usr/lib:${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}} +ENV PKG_CONFIG_PATH=/opt/rh/gcc-toolset-13/root/usr/lib64/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}} + +ARG LLVM_TARGETS LLVM_TRIPLE + +RUN cd && (yum check-update || true) && yum install -y openssl-devel rpm-build cmake yum-utils && \ + yum-config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo && \ + yum install -y gcc-toolset-13 && \ + export CPU=$(/opt/python/cp311-cp311/bin/python3 -c \ + 'import multiprocessing; print(multiprocessing.cpu_count())') && \ + export CFGFLAGS="--prefix=/opt/rh/gcc-toolset-13/root/usr --disable-shared --libdir=/opt/rh/gcc-toolset-13/root/usr/lib64" && \ + curl -s -L -O --remote-name-all \ + https://github.com/ninja-build/ninja/archive/refs/tags/v1.11.1.tar.gz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/llvm-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/lld-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/libunwind-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/cmake-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/third-party-17.0.6.src.tar.xz \ + https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/clang-17.0.6.src.tar.xz && \ + sha256sum -c SHA256SUM.manylinux_2_28 && \ + gzip -dc v1.11.1.tar.gz | tar -xf - && \ + xz -dc llvm-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc lld-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc libunwind-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc cmake-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc third-party-17.0.6.src.tar.xz | tar -xf - && \ + xz -dc clang-17.0.6.src.tar.xz | tar -xf - && \ + export ZSTDFLAGS=(PREFIX=/opt/rh/gcc-toolset-13/root/usr LIBDIR=/opt/rh/gcc-toolset-13/root/usr/lib64 SED_ERE_OPT=--regexp-extended MOREFLAGS="-std=c17 -O3 -fPIC -fPIE -fvisibility=hidden") && \ + mkdir build && cd build && /opt/python/cp311-cp311/bin/python \ + ../ninja-1.11.1/configure.py --bootstrap \ + --with-python=/opt/python/cp311-cp311/bin/python && \ + cp -v ninja /opt/rh/gcc-toolset-13/root/usr/bin/ninja && cd - && rm -rf build && \ + mv -v llvm-17.0.6.src llvm && \ + mv -v lld-17.0.6.src lld && \ + mv -v libunwind-17.0.6.src libunwind && \ + mv -v cmake-17.0.6.src cmake && \ + mv -v third-party-17.0.6.src third-party && \ + mv -v clang-17.0.6.src clang && \ + cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/opt/rh/gcc-toolset-13/root/usr \ + -DPython3_ROOT_DIR=/opt/python/cp311-cp311 -DLLVM_LIBDIR_SUFFIX=64 \ + -DLLVM_TARGETS_TO_BUILD="${LLVM_TARGETS}" -DLLVM_ENABLE_PROJECTS="lld;clang" \ + -DLLVM_DEFAULT_TARGET_TRIPLE="${LLVM_TRIPLE}" \ + -DBUILD_SHARED_LIBS=OFF llvm && \ + cmake --build build --target install && \ + rm -rf build && rm -rf * + +RUN yum clean all diff --git a/utils/docker/Dockerfile.manylinux_2_28-plugins-deps b/utils/docker/Dockerfile.manylinux_2_28-plugins-deps new file mode 100644 index 000000000000..ec7be56d3d01 --- /dev/null +++ b/utils/docker/Dockerfile.manylinux_2_28-plugins-deps @@ -0,0 +1,44 @@ +ARG BASE_IMAGE="wasmedge/wasmedge:manylinux_2_28_x86_64" +FROM ${BASE_IMAGE} AS base + +WORKDIR /root + +### deps for x86_64 ### +FROM base AS deps-amd64 +RUN cd && (yum check-update || true) && \ + yum install -y wget unzip zlib-devel zlib-static elfutils-libelf-devel + +COPY wasi-nn/install-pytorch.sh . +ENV PYTORCH_VERSION="1.8.2" +ENV PYTORCH_INSTALL_TO="/root" +ENV Torch_DIR="/root/libtorch" +RUN [ "/bin/bash", "install-pytorch.sh" ] + +### deps for aarch64 ### +FROM base AS deps-arm64 +RUN cd && (yum check-update || true) && \ + yum install -y wget unzip zlib-devel zlib-static + +### deps for all ### +FROM deps-${TARGETARCH} AS final + +COPY opencvmini/install-opencvmini.sh . +ENV OPENCV_VERSION="4.8.0" +RUN [ "/bin/bash", "install-opencvmini.sh" ] + +COPY wasi-crypto/build-openssl.sh . +ENV OpenSSL_DIR="/root/openssl-1.1.1n/openssl" +RUN [ "/bin/bash", "build-openssl.sh" ] + +COPY ffmpeg/install-ffmpeg-v6.0.sh . +RUN [ "/bin/bash", "install-ffmpeg-v6.0.sh" ] +ENV PKG_CONFIG_PATH=/root/FFmpeg-n6.0/output/lib/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}} +ENV LD_LIBRARY_PATH=/root/FFmpeg-n6.0/output/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}} + +ENV OPENVINO_VERSION="2024.2.0" +ENV OPENVINO_YEAR="2024" + +COPY wasi-nn/install-onnxruntime.sh . +RUN [ "/bin/bash", "install-onnxruntime.sh" ] + +RUN yum clean all diff --git a/utils/docker/Dockerfile.ubuntu-base b/utils/docker/Dockerfile.ubuntu-base new file mode 100644 index 000000000000..8dc3f7b397f4 --- /dev/null +++ b/utils/docker/Dockerfile.ubuntu-base @@ -0,0 +1,52 @@ +ARG UBUNTU_VER=22 +FROM ubuntu:${UBUNTU_VER}.04 AS base + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y \ + cmake \ + curl \ + dpkg-dev \ + g++ \ + gcc \ + git \ + ninja-build \ + software-properties-common \ + wget \ + zlib1g-dev + +### deps for ubuntu 20.04 ### +FROM base AS deps-20 + +RUN apt-get install -y \ + llvm-12-dev \ + liblld-12-dev \ + clang-12 + +RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-12 100 && \ + update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-12 100 && \ + update-alternatives --install /usr/bin/llvm-strip llvm-strip /usr/bin/llvm-strip-12 100 + +ENV CC=/usr/bin/clang-12 +ENV CXX=/usr/bin/clang++-12 + +### deps for ubuntu 22.04 ### +FROM base AS deps-22 + +RUN apt-get install -y \ + llvm-15-dev \ + liblld-15-dev \ + clang-15 + +RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-15 100 && \ + update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-15 100 && \ + update-alternatives --install /usr/bin/llvm-strip llvm-strip /usr/bin/llvm-strip-15 100 + +ENV CC=/usr/bin/clang-15 +ENV CXX=/usr/bin/clang++-15 + +### cleanup +FROM deps-${UBUNTU_VER} AS clean-apt + +RUN rm -rf /var/lib/apt/lists/* diff --git a/utils/docker/Dockerfile.ubuntu-gcc b/utils/docker/Dockerfile.ubuntu-gcc new file mode 100644 index 000000000000..1b201ae2027b --- /dev/null +++ b/utils/docker/Dockerfile.ubuntu-gcc @@ -0,0 +1,5 @@ +ARG BASE_IMAGE=wasmedge/wasmedge:latest +FROM ${BASE_IMAGE} AS base + +ENV CC=/usr/bin/gcc +ENV CXX=/usr/bin/g++ diff --git a/utils/docker/Dockerfile.ubuntu-plugins-deps b/utils/docker/Dockerfile.ubuntu-plugins-deps new file mode 100644 index 000000000000..dcff0c53017b --- /dev/null +++ b/utils/docker/Dockerfile.ubuntu-plugins-deps @@ -0,0 +1,28 @@ +ARG BASE_IMAGE=wasmedge/wasmedge:latest +FROM ${BASE_IMAGE} AS base + +WORKDIR /root + +RUN apt-get update && \ + apt-get install -y \ + cargo \ + libelf-dev \ + libomp-dev \ + libssl-dev \ + pkg-config \ + unzip \ + yasm + +COPY opencvmini/install-opencvmini.sh . +ENV OPENCV_VERSION="4.8.0" +RUN [ "/bin/bash", "install-opencvmini.sh" ] + +COPY ffmpeg/install-ffmpeg-v6.0.sh . +RUN [ "/bin/bash", "install-ffmpeg-v6.0.sh" ] +ENV PKG_CONFIG_PATH=/root/FFmpeg-n6.0/output/lib/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}} +ENV LD_LIBRARY_PATH=/root/FFmpeg-n6.0/output/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}} + +### cleanup +FROM base AS clean-apt + +RUN rm -rf /var/lib/apt/lists/* diff --git a/utils/docker/Dockerfile.ubuntu2104_armv7l b/utils/docker/Dockerfile.ubuntu2104_armv7l index 28e7c94cab30..3329e6f223fd 100644 --- a/utils/docker/Dockerfile.ubuntu2104_armv7l +++ b/utils/docker/Dockerfile.ubuntu2104_armv7l @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC FROM arm32v7/ubuntu:hirsute @@ -30,12 +30,12 @@ RUN apt update && apt upgrade -y \ # CMake build from source to avoid compiler_id_detection fails when using QEMU user-mode emulation # See: https://gitlab.kitware.com/cmake/cmake/-/issues/20568 -#RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.1/cmake-3.21.1.tar.gz --no-check-certificate && \ -# tar zxvf cmake-3.21.1.tar.gz && \ -# cd cmake-3.21.1 && \ +#RUN wget https://github.com/Kitware/CMake/releases/download/v3.29.3/cmake-3.29.3.tar.gz --no-check-certificate && \ +# tar zxvf cmake-3.29.3.tar.gz && \ +# cd cmake-3.29.3 && \ # ./configure && \ # make install -j$(nproc) && \ -# cd .. && rm -rf cmake-3.21.1 +# cd .. && rm -rf cmake-3.29.3 RUN rm -rf /var/lib/apt/lists/* diff --git a/utils/docker/SHA256SUM b/utils/docker/SHA256SUM deleted file mode 100644 index 903268becb2e..000000000000 --- a/utils/docker/SHA256SUM +++ /dev/null @@ -1,8 +0,0 @@ -9400d49acd53a4b8f310de60554a891436db5a19f6f227f99f0de13e4afaaaff cmake-16.0.5.src.tar.xz -e7f65970298a60e9608a9fc55ea9af5e9c8e1bc0dc0067f3e9f10eb3fe3e8986 libunwind-16.0.5.src.tar.xz -0c593d1c23f626dc33caa8bf112868f77126e018b58dd1641f5ae6aa1c2a0ce3 lld-16.0.5.src.tar.xz -701b764a182d8ea8fb017b6b5f7f5f1272a29f17c339b838f48de894ffdd4f91 llvm-16.0.5.src.tar.xz -0a4bbb8505e95570e529d6b3d5176e93beb3260f061de9001e320d57b59aed59 third-party-16.0.5.src.tar.xz -31747ae633213f1eda3842686f83c2aa1412e0f5691d1c14dbbcc67fe7400cea v1.11.1.tar.gz -9c4396cc829cfae319a6e2615202e82aad41372073482fce286fac78646d3ee4 zstd-1.5.5.tar.gz -f4bb3456c415f01e929d96983b851c49d02b595bf4f99edbbfc55626437775a7 clang-16.0.5.src.tar.xz diff --git a/utils/docker/SHA256SUM.manylinux2014 b/utils/docker/SHA256SUM.manylinux2014 new file mode 100644 index 000000000000..2e48695e8219 --- /dev/null +++ b/utils/docker/SHA256SUM.manylinux2014 @@ -0,0 +1,9 @@ +a78f668a726ae1d3d9a7179996d97b12b90fb76ab9442a43110b972ff7ad9029 clang-17.0.6.src.tar.xz +807f069c54dc20cb47b21c1f6acafdd9c649f3ae015609040d6182cab01140f4 cmake-17.0.6.src.tar.xz +252aee1448d49caa04954fd5e27d189dd51570557313e7b281636716a238bccb cmake-3.29.3.tar.gz +9e7535a353aa862730b4ba38df42e06f6856b40c4cc51b57f27b5046dc21d70d libunwind-17.0.6.src.tar.xz +4ac13125616dc44905b85820aa403d27ec1226329b7f674daeb5f5584c6f0b22 lld-17.0.6.src.tar.xz +b638167da139126ca11917b6880207cc6e8f9d1cbb1a48d87d017f697ef78188 llvm-17.0.6.src.tar.xz +3054d0a9c9375dab1a4539cc2cc45ab340341c5d71475f9599ba7752e222947b third-party-17.0.6.src.tar.xz +31747ae633213f1eda3842686f83c2aa1412e0f5691d1c14dbbcc67fe7400cea v1.11.1.tar.gz +9c4396cc829cfae319a6e2615202e82aad41372073482fce286fac78646d3ee4 zstd-1.5.5.tar.gz diff --git a/utils/docker/SHA256SUM.manylinux_2_28 b/utils/docker/SHA256SUM.manylinux_2_28 new file mode 100644 index 000000000000..0b732009baad --- /dev/null +++ b/utils/docker/SHA256SUM.manylinux_2_28 @@ -0,0 +1,7 @@ +31747ae633213f1eda3842686f83c2aa1412e0f5691d1c14dbbcc67fe7400cea v1.11.1.tar.gz +a78f668a726ae1d3d9a7179996d97b12b90fb76ab9442a43110b972ff7ad9029 clang-17.0.6.src.tar.xz +807f069c54dc20cb47b21c1f6acafdd9c649f3ae015609040d6182cab01140f4 cmake-17.0.6.src.tar.xz +9e7535a353aa862730b4ba38df42e06f6856b40c4cc51b57f27b5046dc21d70d libunwind-17.0.6.src.tar.xz +4ac13125616dc44905b85820aa403d27ec1226329b7f674daeb5f5584c6f0b22 lld-17.0.6.src.tar.xz +b638167da139126ca11917b6880207cc6e8f9d1cbb1a48d87d017f697ef78188 llvm-17.0.6.src.tar.xz +3054d0a9c9375dab1a4539cc2cc45ab340341c5d71475f9599ba7752e222947b third-party-17.0.6.src.tar.xz diff --git a/utils/docker/build-manylinux.sh b/utils/docker/build-manylinux.sh index 2c4ead7b1d48..5e4affab5505 100755 --- a/utils/docker/build-manylinux.sh +++ b/utils/docker/build-manylinux.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC git config --global --add safe.directory $(pwd) diff --git a/utils/docker/build.sh b/utils/docker/build.sh deleted file mode 100755 index 3d99a86ffc3d..000000000000 --- a/utils/docker/build.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2022 Second State INC - -NAME=${1:+$1/}wasmedge -INTERMEDIATES=() -IMAGES=() - -set -e - -function docker_build -{ - local FILENAME=$1; shift - local TAG=$1; shift - local NAME_TAG=${NAME}:${TAG} - echo "Building docker image \"${NAME_TAG}\" from file \"${FILENAME}\"." - - ( set -x; docker build "$@" -f "${FILENAME}" -t "${NAME_TAG}" . ) - - if [[ "${TAG}" == im-* ]]; then - INTERMEDIATES+=( "${NAME_TAG}" ) - else - IMAGES+=( "${NAME_TAG}" ) - fi -} - -# Build all images. -docker_build Dockerfile.base ubuntu-base -docker_build Dockerfile.ci-image-base ci-image-base -docker_build Dockerfile.build-clang ubuntu-build-clang \ - --build-arg "BASE=${NAME}:ubuntu-base" -docker_build Dockerfile.build-clang latest \ - --build-arg "BASE=${NAME}:ubuntu-base" -docker_build Dockerfile.build-gcc ubuntu-build-gcc \ - --build-arg "BASE=${NAME}:ubuntu-base" -docker_build Dockerfile.build-plugins-deps ubuntu-build-clang-plugins-deps \ - --build-arg "BASE=${NAME}:ubuntu-build-clang" -docker_build Dockerfile.build-plugins-deps ubuntu-build-gcc-plugins-deps \ - --build-arg "BASE=${NAME}:ubuntu-build-gcc" - -# Remove intermediate images. -for NAME_TAG in "${INTERMEDIATES[@]}"; do - ( set -x; docker rmi "${NAME_TAG}" ) -done - -# Push all images. -for NAME_TAG in "${IMAGES[@]}"; do - ( set -x; docker push "${NAME_TAG}" ) -done diff --git a/utils/docker/docker-bake.ci-image-base.hcl b/utils/docker/docker-bake.ci-image-base.hcl new file mode 100644 index 000000000000..b98e75b6e5d6 --- /dev/null +++ b/utils/docker/docker-bake.ci-image-base.hcl @@ -0,0 +1,26 @@ +group "default" { + targets = [ + "x86_64", + "aarch64" + ] +} + +target "base" { + dockerfile = "Dockerfile.ci-image-base" + context = "./utils/docker" +} + +target "x86_64" { + inherits = ["base"] + platforms = ["linux/amd64"] + tags = [ + "wasmedge/wasmedge:ci-image-base", + "wasmedge/wasmedge:ci-image-base_x86_64" + ] +} + +target "aarch64" { + inherits = ["base"] + platforms = ["linux/arm64"] + tags = ["wasmedge/wasmedge:ci-image-base_aarch64"] +} diff --git a/utils/docker/docker-bake.manylinux.hcl b/utils/docker/docker-bake.manylinux.hcl new file mode 100644 index 000000000000..0d122ffc8d74 --- /dev/null +++ b/utils/docker/docker-bake.manylinux.hcl @@ -0,0 +1,51 @@ +target "base" { + dockerfile = "Dockerfile.manylinux_2_28-base" + context = "./utils/docker" +} + +target "plugins-base" { + dockerfile = "./docker/Dockerfile.manylinux_2_28-plugins-deps" + context = "./utils" +} + +target "x86_64" { + inherits = ["base"] + platforms = ["linux/amd64"] + tags = ["wasmedge/wasmedge:manylinux_2_28_x86_64"] + args = { + LLVM_TARGETS = "X86;BPF", + LLVM_TRIPLE = "x86_64-pc-linux-gnu" + } +} + +target "x86_64-plugins" { + inherits = ["plugins-base"] + platforms = ["linux/amd64"] + tags = ["wasmedge/wasmedge:manylinux_2_28_x86_64-plugins-deps"] + contexts = { + "wasmedge/wasmedge:manylinux_2_28_x86_64"= "target:x86_64" + } +} + +target "aarch64" { + inherits = ["base"] + platforms = ["linux/arm64"] + tags = ["wasmedge/wasmedge:manylinux_2_28_aarch64"] + args = { + BASE_IMAGE = "quay.io/pypa/manylinux_2_28_aarch64", + LLVM_TARGETS = "AArch64;BPF", + LLVM_TRIPLE = "aarch64-redhat-linux-gnu" + } +} + +target "aarch64-plugins" { + inherits = ["plugins-base"] + platforms = ["linux/arm64"] + tags = ["wasmedge/wasmedge:manylinux_2_28_aarch64-plugins-deps"] + contexts = { + "wasmedge/wasmedge:manylinux_2_28_aarch64" = "target:aarch64" + } + args = { + BASE_IMAGE = "wasmedge/wasmedge:manylinux_2_28_aarch64" + } +} diff --git a/utils/docker/docker-bake.ubuntu.hcl b/utils/docker/docker-bake.ubuntu.hcl new file mode 100644 index 000000000000..fb9bf95670f6 --- /dev/null +++ b/utils/docker/docker-bake.ubuntu.hcl @@ -0,0 +1,125 @@ +group "default" { + targets = [ + "clang", + "gcc" + ] +} + +function "no-dot" { + params = [ubuntu] + result = replace(ubuntu, ".", "") +} + +function "major" { + params = [ubuntu] + result = regex("^[[:digit:]]+", ubuntu) +} + +function "tags-latest" { + params = [target, ubuntu, toolchain] + result = target == "base" && ubuntu == "22.04" && toolchain == "clang" ? "latest" : "" +} + +function "tags-backports" { + params = [target, ubuntu, toolchain] + result = join("-", compact([ + "ubuntu", + ubuntu != "22.04" ? ubuntu : "", + "build", + toolchain, + target == "plugins" ? "plugins-deps" : "", + ])) +} + +function "tags-simplified" { + params = [target, ubuntu, toolchain] + result = target == "base" && toolchain == "clang" ? "ubuntu-${ubuntu}" : "" +} + +function "tags" { + params = [target, ubuntu, toolchain] + result = [for tag in compact([ + tags-latest(target, ubuntu, toolchain), + tags-backports(target, ubuntu, toolchain), + tags-simplified(target, ubuntu, toolchain), + ]) : "wasmedge/wasmedge:${tag}"] +} + +target "base" { + dockerfile = "Dockerfile.ubuntu-base" + context = "./utils/docker" + + matrix = { + ubuntu = ["20.04", "22.04"] + } + + name = "base-${no-dot(ubuntu)}" + tags = ["local/tmp:base-${ubuntu}"] + args = { + UBUNTU_VER = major(ubuntu) + } +} + +target "plugins" { + dockerfile = "./docker/Dockerfile.ubuntu-plugins-deps" + context = "./utils" + + matrix = { + ubuntu = ["20.04", "22.04"] + } + + inherits = ["base-${no-dot(ubuntu)}"] + name = "plugins-${no-dot(ubuntu)}" + contexts = { + "local/tmp:base-${ubuntu}" = "target:base-${no-dot(ubuntu)}" + } + tags = ["local/tmp:plugins-${ubuntu}"] + args = { + BASE_IMAGE = "local/tmp:base-${ubuntu}" + UBUNTU_VER = major(ubuntu) + } +} + +target "clang" { + matrix = { + parent = ["base", "plugins"] + ubuntu = ["20.04", "22.04"] + } + + inherits = ["${parent}-${no-dot(ubuntu)}"] + name = "${parent}-${no-dot(ubuntu)}-clang" + contexts = { + "local/tmp:${parent}-${ubuntu}" = "target:${parent}-${no-dot(ubuntu)}" + } + tags = tags(parent, ubuntu, "clang") +} + +target "gcc" { + dockerfile = "Dockerfile.ubuntu-gcc" + context = "./utils/docker" + + matrix = { + parent = ["base", "plugins"] + ubuntu = ["20.04", "22.04"] + } + + inherits = ["${parent}-${no-dot(ubuntu)}"] + name = "${parent}-${no-dot(ubuntu)}-gcc" + contexts = { + "local/tmp:${parent}-${ubuntu}" = "target:${parent}-${no-dot(ubuntu)}" + } + tags = tags(parent, ubuntu, "gcc") + args = { + BASE_IMAGE = "local/tmp:${parent}-${ubuntu}" + } +} + +# TODO: Refactor with multi-arch image +target "base-2004-clang-aarch64" { + inherits = ["base-2004"] + contexts = { + "local/tmp:base-2004" = "target:base-2004" + } + tags = [for tag in tags("base", "20.04", "clang") : "${tag}-aarch64"] + platforms = ["linux/arm64"] +} diff --git a/utils/docker/install-opencvmini.sh b/utils/docker/install-opencvmini.sh deleted file mode 100644 index f66ef586b6b0..000000000000 --- a/utils/docker/install-opencvmini.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2023 Second State INC - -wget -O opencv.zip https://github.com/opencv/opencv/archive/refs/tags/${OPENCV_VERSION}.zip - -unzip opencv.zip -mv opencv-${OPENCV_VERSION} opencv - -mkdir -p opencv/build && cd opencv/build -# Configure -cmake -GNinja .. -# Build -cmake --build . -# Install to system -cmake --install . diff --git a/utils/ffmpeg/download-ffmpeg-sample-video.sh b/utils/ffmpeg/download-ffmpeg-sample-video.sh new file mode 100644 index 000000000000..5b05b0801aca --- /dev/null +++ b/utils/ffmpeg/download-ffmpeg-sample-video.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +# The below video used is sourced from an ffmpeg-libav-tutorial repository. +# Source: https://github.com/leandromoreira/ffmpeg-libav-tutorial/blob/master/LICENSE. +TODIR=$1 +SAMPLE_VIDEO=https://raw.githubusercontent.com/Hrushi20/rust-ffmpeg/master/assets/bunny.mp4 +if [[ $# -eq 0 ]]; then + TODIR=. +fi +if [ ! -d $TODIR ]; then + mkdir $TODIR +fi +if [ ! -d $TODIR ]; then + mkdir $TODIR +fi + +if [ ! -f $TODIR/sample_video.mp4 ]; then + curl -sL $SAMPLE_VIDEO -o $TODIR/sample_video.mp4 + cp $TODIR/sample_video.mp4 $TODIR/dummy.mp4 # Dummy file to manipulate and run tests on file. +fi diff --git a/utils/ffmpeg/install-ffmpeg-v6.0.sh b/utils/ffmpeg/install-ffmpeg-v6.0.sh new file mode 100755 index 000000000000..479908ce5bdb --- /dev/null +++ b/utils/ffmpeg/install-ffmpeg-v6.0.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +rm -rf FFmpeg-n6.0 ffmpeg.zip +echo $(pwd) + +curl -sL https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n6.0.zip -o ffmpeg.zip + +unzip ffmpeg.zip + +mkdir -p FFmpeg-n6.0/output +cd FFmpeg-n6.0 +./configure --prefix=$(pwd)/output --enable-gpl --enable-nonfree --enable-shared --disable-static +make && make install +cd .. diff --git a/utils/install.py b/utils/install.py index 921f51676bbe..9df0358a8160 100644 --- a/utils/install.py +++ b/utils/install.py @@ -164,6 +164,9 @@ def extract_archive( for filename in files_extracted: fname = filename.replace(CONST_ipkg, ipath) + if "._" in filename: + remove(join(to_path, filename)) + continue # Skip if it ends with "wasmedge" as it is going to be removed at a later stage if fname.endswith("wasmedge") and not fname.endswith("bin/wasmedge"): continue @@ -175,8 +178,8 @@ def extract_archive( fname = fname[:-5] + "lib" if fname.startswith("/usr") and "lib64" in fname: fname = fname.replace("lib64", "lib", 1) - # ggml-metal.metal is downloaded if we download ggml plugin on macOS - if "Plugin" in fname or fname == "ggml-metal.metal": + + if to_path.endswith("Plugins"): if is_default_path(args): fname = fname.replace( join(ipath, CONST_lib_dir, "wasmedge/"), "" @@ -240,9 +243,13 @@ def _preprocess(self, v, separator, ignorecase): if ignorecase: v = v.lower() return [ - int(x) - if x.isdigit() - else [int(y) if y.isdigit() else y for y in re.findall("\d+|[a-zA-Z]+", x)] + ( + int(x) + if x.isdigit() + else [ + int(y) if y.isdigit() else y for y in re.findall("\d+|[a-zA-Z]+", x) + ] + ) for x in re.split(separator, v) ] @@ -277,14 +284,14 @@ def compare(self, version2, separator=". |-", ignorecase=True): } SUPPORTED_MIN_VERSION = { - "Linux" + "x86_64": VersionString("0.10.0"), - "Linux" + "amd64": VersionString("0.10.0"), - "Linux" + "arm64": VersionString("0.10.0"), - "Linux" + "armv8": VersionString("0.10.0"), - "Linux" + "aarch64": VersionString("0.10.0"), - "Darwin" + "x86_64": VersionString("0.10.0"), - "Darwin" + "arm64": VersionString("0.10.0"), - "Darwin" + "arm": VersionString("0.10.0"), + "Linux" + "x86_64": VersionString("0.13.0"), + "Linux" + "amd64": VersionString("0.13.0"), + "Linux" + "arm64": VersionString("0.13.0"), + "Linux" + "armv8": VersionString("0.13.0"), + "Linux" + "aarch64": VersionString("0.13.0"), + "Darwin" + "x86_64": VersionString("0.13.0"), + "Darwin" + "arm64": VersionString("0.13.0"), + "Darwin" + "arm": VersionString("0.13.0"), } WASMEDGE = "WasmEdge" @@ -294,37 +301,7 @@ def compare(self, version2, separator=". |-", ignorecase=True): TENSORFLOW_LITE_P = "tensorflowlite" TENSORFLOW_DEPS = "tensorflow_deps" TENSORFLOW_LITE_DEPS = "tensorflow_lite_deps" -TENSORFLOW_TOOLS = "tensorflow_tools" IMAGE = "image" -EXTENSIONS = [TENSORFLOW, IMAGE] - -SUPPORTED_EXTENSIONS = { - "Linux" + "x86_64": EXTENSIONS, - "Linux" + "amd64": EXTENSIONS, - "Linux" + "arm64": EXTENSIONS, - "Linux" + "armv8": EXTENSIONS, - "Linux" + "aarch64": EXTENSIONS, - "Darwin" + "x86_64": EXTENSIONS, - "Darwin" + "arm64": EXTENSIONS, - "Darwin" + "arm": EXTENSIONS, -} - -SUPPORTED_EXTENSIONS_VERSION = { - "Linux" + "x86_64" + TENSORFLOW: VersionString("0.10.0"), - "Linux" + "x86_64" + IMAGE: VersionString("0.10.0"), - "Linux" + "amd64" + TENSORFLOW: VersionString("0.10.0"), - "Linux" + "amd64" + IMAGE: VersionString("0.10.0"), - "Linux" + "arm64" + TENSORFLOW: VersionString("0.10.0"), - "Linux" + "arm64" + IMAGE: VersionString("0.10.0"), - "Linux" + "armv8" + TENSORFLOW: VersionString("0.10.0"), - "Linux" + "armv8" + IMAGE: VersionString("0.10.0"), - "Linux" + "aarch64" + TENSORFLOW: VersionString("0.10.0"), - "Linux" + "aarch64" + IMAGE: VersionString("0.10.0"), - "Darwin" + "x86_64" + TENSORFLOW: VersionString("0.10.0"), - "Darwin" + "x86_64" + IMAGE: VersionString("0.10.0"), - "Darwin" + "arm64" + TENSORFLOW: VersionString("0.10.0"), - "Darwin" + "arm" + TENSORFLOW: VersionString("0.10.0"), -} WASI_NN_OPENVINO = "wasi_nn-openvino" WASI_CRYPTO = "wasi_crypto" @@ -332,7 +309,8 @@ def compare(self, version2, separator=". |-", ignorecase=True): WASI_NN_TENSORFLOW_LITE = "wasi_nn-tensorflowlite" WASI_NN_GGML = "wasi_nn-ggml" WASI_NN_GGML_CUDA = "wasi_nn-ggml-cuda" -WASI_NN_GGML_BLAS = "wasi_nn-ggml-blas" +WASI_NN_GGML_NOAVX = "wasi_nn-ggml-noavx" +WASI_LOGGING = "wasi_logging" WASMEDGE_TENSORFLOW_PLUGIN = WASMEDGE.lower() + "_" + TENSORFLOW WASMEDGE_TENSORFLOW_LITE_PLUGIN = WASMEDGE.lower() + "_" + TENSORFLOW_LITE_P WASMEDGE_IMAGE_PLUGIN = WASMEDGE.lower() + "_" + IMAGE @@ -346,7 +324,8 @@ def compare(self, version2, separator=". |-", ignorecase=True): WASI_NN_TENSORFLOW_LITE, WASI_NN_GGML, WASI_NN_GGML_CUDA, - WASI_NN_GGML_BLAS, + WASI_NN_GGML_NOAVX, + WASI_LOGGING, WASMEDGE_TENSORFLOW_PLUGIN, WASMEDGE_TENSORFLOW_LITE_PLUGIN, WASMEDGE_IMAGE_PLUGIN, @@ -355,26 +334,25 @@ def compare(self, version2, separator=". |-", ignorecase=True): ] SUPPORTTED_PLUGINS = { - "ubuntu20.04" + "x86_64" + WASI_CRYPTO: VersionString("0.10.1-rc.1"), - "manylinux2014" + "x86_64" + WASI_CRYPTO: VersionString("0.10.1-rc.1"), - "manylinux2014" + "aarch64" + WASI_CRYPTO: VersionString("0.10.1-rc.1"), - "manylinux2014" + "arm64" + WASI_CRYPTO: VersionString("0.10.1-rc.1"), - "ubuntu20.04" + "x86_64" + WASI_NN_OPENVINO: VersionString("0.10.1-alpha.1"), - "ubuntu20.04" + "x86_64" + WASI_NN_PYTORCH: VersionString("0.11.1-alpha.1"), + "ubuntu20.04" + "x86_64" + WASI_CRYPTO: VersionString("0.13.0"), + "manylinux2014" + "x86_64" + WASI_CRYPTO: VersionString("0.13.0"), + "manylinux2014" + "aarch64" + WASI_CRYPTO: VersionString("0.13.0"), + "manylinux2014" + "arm64" + WASI_CRYPTO: VersionString("0.13.0"), + "ubuntu20.04" + "x86_64" + WASI_NN_OPENVINO: VersionString("0.13.0"), + "ubuntu20.04" + "x86_64" + WASI_NN_PYTORCH: VersionString("0.13.0"), "ubuntu20.04" + "x86_64" + WASI_NN_GGML: VersionString("0.13.4"), "ubuntu20.04" + "aarch64" + WASI_NN_GGML: VersionString("0.13.5"), + "ubuntu20.04" + "x86_64" + WASI_NN_GGML_NOAVX: VersionString("0.13.5"), "ubuntu20.04" + "x86_64" + WASI_NN_GGML_CUDA: VersionString("0.13.4"), "ubuntu20.04" + "aarch64" + WASI_NN_GGML_CUDA: VersionString("0.13.5"), - "ubuntu20.04" + "x86_64" + WASI_NN_GGML_BLAS: VersionString("0.13.5"), - "ubuntu20.04" + "aarch64" + WASI_NN_GGML_BLAS: VersionString("0.13.5"), - "manylinux2014" + "x86_64" + WASI_NN_PYTORCH: VersionString("0.11.2-alpha.1"), - "manylinux2014" + "x86_64" + WASI_NN_TENSORFLOW_LITE: VersionString("0.10.0"), + "manylinux2014" + "x86_64" + WASI_NN_PYTORCH: VersionString("0.13.0"), + "manylinux2014" + "x86_64" + WASI_NN_TENSORFLOW_LITE: VersionString("0.13.0"), "manylinux2014" + "x86_64" + WASI_NN_GGML: VersionString("0.13.4"), - "manylinux2014" + "aarch64" + WASI_NN_TENSORFLOW_LITE: VersionString("0.10.0"), + "manylinux2014" + "aarch64" + WASI_NN_TENSORFLOW_LITE: VersionString("0.13.0"), "manylinux2014" + "aarch64" + WASI_NN_GGML: VersionString("0.13.4"), "darwin" + "x86_64" + WASI_NN_GGML: VersionString("0.13.4"), "darwin" + "arm64" + WASI_NN_GGML: VersionString("0.13.4"), - "ubuntu20.04" + "x86_64" + WASI_NN_TENSORFLOW_LITE: VersionString("0.11.2-rc.1"), + "ubuntu20.04" + "x86_64" + WASI_NN_TENSORFLOW_LITE: VersionString("0.13.0"), "darwin" + "x86_64" + WASMEDGE_TENSORFLOW_PLUGIN: VersionString("0.13.0"), "darwin" + "arm64" + WASMEDGE_TENSORFLOW_PLUGIN: VersionString("0.13.0"), "manylinux2014" + "x86_64" + WASMEDGE_TENSORFLOW_PLUGIN: VersionString("0.13.0"), @@ -394,10 +372,18 @@ def compare(self, version2, separator=". |-", ignorecase=True): "manylinux2014" + "x86_64" + WASMEDGE_IMAGE_PLUGIN: VersionString("0.13.0"), "manylinux2014" + "aarch64" + WASMEDGE_IMAGE_PLUGIN: VersionString("0.13.0"), "ubuntu20.04" + "x86_64" + WASMEDGE_IMAGE_PLUGIN: VersionString("0.13.0"), + "darwin" + "x86_64" + WASI_LOGGING: VersionString("0.14.0"), + "darwin" + "arm64" + WASI_LOGGING: VersionString("0.13.5"), + "manylinux2014" + "aarch64" + WASI_LOGGING: VersionString("0.13.5"), + "manylinux2014" + "x86_64" + WASI_LOGGING: VersionString("0.13.5"), + "ubuntu20.04" + "x86_64" + WASI_LOGGING: VersionString("0.13.5"), + "ubuntu20.04" + "aarch64" + WASI_LOGGING: VersionString("0.14.0"), "darwin" + "x86_64" + WASMEDGE_RUSTLS: VersionString("0.13.4"), "darwin" + "arm64" + WASMEDGE_RUSTLS: VersionString("0.13.4"), + "manylinux2014" + "aarch64" + WASMEDGE_RUSTLS: VersionString("0.13.5"), "manylinux2014" + "x86_64" + WASMEDGE_RUSTLS: VersionString("0.13.4"), "ubuntu20.04" + "x86_64" + WASMEDGE_RUSTLS: VersionString("0.13.4"), + "ubuntu20.04" + "aarch64" + WASMEDGE_RUSTLS: VersionString("0.13.5"), "ubuntu20.04" + "x86_64" + WASM_BPF: VersionString("0.13.2"), "manylinux2014" + "x86_64" + WASM_BPF: VersionString("0.13.2"), } @@ -656,6 +642,19 @@ def check_nvidia_smi(platform): return False +def check_libcudart(platform): + if platform == "Linux": + cmd = "ldconfig -p | grep libcudart.so" + output = run_shell_command(cmd) + logging.debug("%s: %s", cmd, output) + if "libcudart.so" in output: + return True + else: + logging.info("Cannot find libcudart.so") + return False + return False + + def ldconfig(args, compat): if geteuid() == 0: # Only run ldconfig or update_dyld_shared_cache when user is root/sudoer @@ -678,142 +677,23 @@ def is_default_path(args): return args.path == abspath(PATH) or args.path[:4] != "/usr" -def install_image_extension(args, compat): - global CONST_release_pkg, CONST_lib_dir - - if not get_remote_version_availability( - "second-state/WasmEdge-image", args.image_version - ): - logging.error( - "Image extension version incorrect: {0}".format(args.image_version) - ) - return -1 - if compat.prefix() + IMAGE not in SUPPORTED_EXTENSIONS_VERSION: - logging.error("Image extensions not compatible: {0}".format(compat.prefix())) - return -1 - elif ( - SUPPORTED_EXTENSIONS_VERSION[compat.prefix() + IMAGE].compare( - args.image_version - ) - > 0 - ): - logging.error( - "Min image extensions version: {0}".format( - SUPPORTED_EXTENSIONS_VERSION[compat.prefix() + IMAGE], - ) - ) - return -1 - - logging.info("Downloading image extension") - - local_release_package = CONST_release_pkg - - # From WasmEdge 0.11.1, we have the Ubuntu release. - # Installation of ubuntu version extensions when the ubuntu version of WasmEdge selected. - if VersionString(args.image_version).compare("0.11.1") >= 0: - local_release_package = compat.release_package_wasmedge - logging.debug("Downloading dist package: {0}".format(local_release_package)) - - image_pkg = "WasmEdge-image-" + args.image_version + "-" + local_release_package - - download_url(CONST_urls[IMAGE], join(TEMP_PATH, image_pkg), show_progress) - - # Extract archive - extract_archive( - join(TEMP_PATH, image_pkg), - args.path, - join(TEMP_PATH, "WasmEdge-image"), - env_file_path=CONST_env_path, - remove_finished=True, - ) - - wasmedge_image_temp = join(TEMP_PATH, "WasmEdge-image") - for dir in listdir(wasmedge_image_temp): - wasmedge_image_temp_dir = join(wasmedge_image_temp, dir) - for file in listdir(wasmedge_image_temp_dir): - if isdir(join(wasmedge_image_temp_dir, file)) and "wasmedge" == file: - copytree( - join(wasmedge_image_temp_dir, file), - join(args.path, "include", "wasmedge"), - ) - elif CONST_lib_ext in file: - if isdir(join(args.path, CONST_lib_dir)): - shutil.move( - join(wasmedge_image_temp_dir, file), - join(args.path, CONST_lib_dir, file), - ) - else: - logging.error( - "%s directory not found", join(args.path, CONST_lib_dir) - ) - try: - mkdir(join(args.path, CONST_lib_dir)) - shutil.move( - join(wasmedge_image_temp_dir, file), - join(args.path, "lib", file), - ) - except: - pass - elif isdir(join(wasmedge_image_temp_dir, file)): - copytree( - join(wasmedge_image_temp_dir, file), - join(args.path, file), - ) - else: - shutil.move( - join(wasmedge_image_temp_dir, file), - join(args.path, "bin", file), - ) - - fix_gnu_sparse(args) - - return 0 - - def install_tensorflow_extension( args, compat, - download_tf_=False, - download_tf_lite_=False, download_tf_deps_=False, download_tf_lite_deps_=False, - download_tf_tools_=False, ): global CONST_release_pkg, CONST_lib_ext, CONST_lib_dir, CONST_env_path - download_tf = download_tf_ - download_tf_lite = download_tf_lite_ download_tf_deps = download_tf_deps_ download_tf_lite_deps = download_tf_lite_deps_ - download_tf_tools = download_tf_tools_ logging.debug( - "install_tensorflow_extension: %s %s %s %s %s", - download_tf, - download_tf_lite, + "install_tensorflow_extension: %s %s", download_tf_deps, download_tf_lite_deps, - download_tf_tools, ) - if VersionString(args.version).compare("0.13.0") >= 0: - # if greater than 0.13.0 then No WasmEdge-tensorflow and WasmEdge-tensorflow-tools - download_tf = False - download_tf_lite = False - download_tf_tools = False - logging.debug("No WasmEdge-tensorflow and WasmEdge-tensorflow-tools") - - if ( - not get_remote_version_availability( - "second-state/WasmEdge-tensorflow", args.tf_version - ) - and download_tf - ): - logging.debug( - "Tensorflow extension version not found: {0}".format(args.tf_version) - ) - download_tf = False - if ( not get_remote_version_availability( "second-state/WasmEdge-tensorflow-deps", args.tf_deps_version @@ -827,37 +707,7 @@ def install_tensorflow_extension( ) download_tf_deps = False - if ( - not get_remote_version_availability( - "second-state/WasmEdge-tensorflow", args.tf_tools_version - ) - and download_tf_tools - ): - logging.debug( - "Tensorflow Tools version not found: {0}".format(args.tf_tools_version) - ) - download_tf_tools = False - - if compat.prefix() + TENSORFLOW not in SUPPORTED_EXTENSIONS_VERSION: - logging.error( - "Tensorflow extensions not compatible: {0}".format(compat.prefix()) - ) - return -1 - elif ( - SUPPORTED_EXTENSIONS_VERSION[compat.prefix() + TENSORFLOW].compare( - args.tf_version - ) - > 0 - ): - logging.error( - "Min tensorflow extensions version: {0}".format( - SUPPORTED_EXTENSIONS_VERSION[compat.prefix() + TENSORFLOW], - ) - ) - return -1 - if compat.machine == "aarch64": - download_tf = False download_tf_deps = False logging.warning( "Cannot download WasmEdge Tensorflow, Tools & Deps because it is aarch64" @@ -871,20 +721,6 @@ def install_tensorflow_extension( local_release_package = compat.release_package_wasmedge logging.debug("Downloading dist package: {0}".format(local_release_package)) - if download_tf: - tf_pkg = "WasmEdge-tensorflow-" + args.tf_version + "-" + local_release_package - logging.info("Downloading tensorflow extension") - download_url(CONST_urls[TENSORFLOW], join(TEMP_PATH, tf_pkg), show_progress) - # Extract archive - extract_archive( - join(TEMP_PATH, tf_pkg), - args.path, - join(TEMP_PATH, "WasmEdge-tensorflow"), - env_file_path=CONST_env_path, - remove_finished=True, - ) - copytree(join(TEMP_PATH, "WasmEdge-tensorflow"), args.path) - if download_tf_deps: tf_deps_pkg = ( "WasmEdge-tensorflow-deps-TF-" @@ -908,24 +744,6 @@ def install_tensorflow_extension( ) copytree(join(TEMP_PATH, "WasmEdge-tensorflow-deps"), args.path) - if download_tf_lite: - tf_lite_pkg = ( - "WasmEdge-tensorflowlite-" + args.tf_version + "-" + local_release_package - ) - logging.info("Downloading tensorflow-lite extension") - download_url( - CONST_urls[TENSORFLOW_LITE], join(TEMP_PATH, tf_lite_pkg), show_progress - ) - # Extract archive - extract_archive( - join(TEMP_PATH, tf_lite_pkg), - args.path, - join(TEMP_PATH, "WasmEdge-tensorflow-lite"), - env_file_path=CONST_env_path, - remove_finished=True, - ) - copytree(join(TEMP_PATH, "WasmEdge-tensorflow-lite"), args.path) - if download_tf_lite_deps: tf_deps_lite_pkg = ( "WasmEdge-tensorflow-deps-TFLite-" @@ -952,30 +770,6 @@ def install_tensorflow_extension( copytree(join(TEMP_PATH, "WasmEdge-tensorflow-lite-deps"), args.path) - if download_tf_tools: - tf_tools_pkg = ( - "WasmEdge-tensorflow-tools-" - + args.tf_tools_version - + "-" - + CONST_release_pkg - ) - - logging.info("Downloading tensorflow-tools extension") - download_url( - CONST_urls[TENSORFLOW_TOOLS], join(TEMP_PATH, tf_tools_pkg), show_progress - ) - - # Extract archive - extract_archive( - join(TEMP_PATH, tf_tools_pkg), - join(args.path, "bin"), - join(TEMP_PATH, "WasmEdge-tensorflow-tools", "bin"), - env_file_path=CONST_env_path, - remove_finished=True, - ) - - copytree(join(TEMP_PATH, "WasmEdge-tensorflow-tools"), args.path) - fix_gnu_sparse(args) all_files = run_shell_command("ls -R {0}".format(TEMP_PATH)) @@ -1106,36 +900,6 @@ def install_tensorflow_extension( join(args.path, "bin", _file), ) - if download_tf_tools and download_tf: - # Check if wasmedge binary works - wasmedge_tf_output = run_shell_command( - ". {0}/env &&{0}/bin/wasmedge-tensorflow --version".format(args.path) - ) - - if args.tf_version in wasmedge_tf_output: - logging.info("WasmEdge Successfully installed") - else: - logging.critical( - "WasmEdge Tensorflow installation incorrect: {0}".format( - wasmedge_tf_output - ) - ) - - if download_tf_tools and download_tf_lite: - # Check if wasmedge binary works - wasmedge_tf_lite_output = run_shell_command( - ". {0}/env && {0}/bin/wasmedge-tensorflow-lite --version".format(args.path) - ) - - if args.tf_version in wasmedge_tf_lite_output: - logging.info("WasmEdge Tensorflow Lite Successfully installed") - else: - logging.critical( - "WasmEdge Tensorflow installation incorrect: {0}".format( - wasmedge_tf_lite_output - ) - ) - return 0 @@ -1146,11 +910,67 @@ def install_plugins(args, compat): if len(args.plugins) >= 1: for plugin_name in args.plugins: + # Reset the url_root, due to the wasi-nn-ggml plugin with the build number will change the url + url_root = "https://github.com/WasmEdge/WasmEdge/releases/download/" + url_root += ( + "$VERSION$/WasmEdge-plugin-$PLUGIN_NAME$-$VERSION$-$DIST$_$ARCH$.tar.gz" + ) plugin_version_supplied = None + plugin_wasi_nn_ggml_bypass_check = False if plugin_name.find(":") != -1: plugin_name, plugin_version_supplied = plugin_name.split(":") - if plugin_name not in PLUGINS_AVAILABLE: + # Deprecated rustls after 0.14.0 + # Only allow users to install rustls with 0.13.5 + if ( + plugin_name.startswith(WASMEDGE_RUSTLS) + and compat.version.compare("0.13.5") != 0 + ): + logging.warning("WasmEdge Rustls plugin is only available in 0.13.5") + logging.warning("Please use -v 0.13.5 as a workaround") + logging.warning("Skip installing WasmEdge Rustls plugin") + continue + + # Deprecated wasi-logging after 0.14.1-rc.1 + if ( + plugin_name.startswith(WASI_LOGGING) + and compat.version.compare("0.14.1-rc.1") != -1 + ): + logging.warning( + "WASI-Logging plugin is bundled into libwasmedge in 0.14.1-rc.1" + ) + logging.warning("No need to install the WASI-Logging plugin") + continue + + # Split the WASI-NN-GGML plugin and the others + if plugin_name.startswith(WASI_NN_GGML): + # Re-write the plugin name if the build number is supplied + # E.g. wasi_nn-ggml-b2330, wasi_nn-ggml-cuda-b2330, wasi_nn-ggml-cuda-11-b2330 + # "https://github.com/second-state/WASI-NN-GGML-PLUGIN-REGISTRY/raw/main/" + # "$VERSION$/" + # "$BUILD_NUMBER$/" + # "WasmEdge-plugin" + # "-$PLUGIN_NAME$" + # "-$VERSION$" + # "-$DIST$" + # "_$ARCH$" # ".tar.gz" + # If the build number is supplied, bypass the checks + plugin_wasi_nn_ggml_bypass_check = True + if plugin_name.startswith(WASI_NN_GGML) and "-b" in plugin_name: + [plugin_name, plugin_build_number] = plugin_name.split("-b") + url_root = "https://github.com/second-state/WASI-NN-GGML-PLUGIN-REGISTRY/raw/main/" + url_root += "$VERSION$/b$BUILD_NUMBER$/WasmEdge-plugin-$PLUGIN_NAME$-$VERSION$-$DIST$_$ARCH$.tar.gz" + url_root = url_root.replace("$BUILD_NUMBER$", plugin_build_number) + + # Re-write the plugin name if CUDA is available + if plugin_name == WASI_NN_GGML and compat.cuda: + plugin_name = WASI_NN_GGML_CUDA + + # Normal plugin + if ( + plugin_name not in PLUGINS_AVAILABLE + and not plugin_wasi_nn_ggml_bypass_check + ): logging.error( "%s plugin not found, available names - %s", plugin_name, @@ -1158,11 +978,10 @@ def install_plugins(args, compat): ) continue - # Re-write the plugin name if CUDA is available - if plugin_name == WASI_NN_GGML and compat.cuda: - plugin_name = WASI_NN_GGML_CUDA - - if compat.dist + compat.machine + plugin_name not in SUPPORTTED_PLUGINS: + if ( + compat.dist + compat.machine + plugin_name not in SUPPORTTED_PLUGINS + and not plugin_wasi_nn_ggml_bypass_check + ): logging.error( "Plugin not compatible: %s", compat.dist + compat.machine + plugin_name, @@ -1267,14 +1086,6 @@ def set_consts(args, compat): local_release_package_tf = compat.release_package_wasmedge logging.debug("Tensorflow release pkg: {0}".format(local_release_package_tf)) - local_release_package_im = CONST_release_pkg - - # From WasmEdge 0.11.1, we have the Ubuntu release. - # Installation of ubuntu version extensions when the ubuntu version of WasmEdge selected. - if VersionString(args.image_version).compare("0.11.1") >= 0: - local_release_package_im = compat.release_package_wasmedge - logging.debug("Image release pkg: {0}".format(local_release_package_im)) - CONST_urls = { WASMEDGE: "https://github.com/WasmEdge/WasmEdge/releases/download/{0}/WasmEdge-{0}-{1}".format( args.version, compat.release_package_wasmedge @@ -1282,24 +1093,12 @@ def set_consts(args, compat): WASMEDGE_UNINSTALLER: "https://raw.githubusercontent.com/WasmEdge/WasmEdge/{0}/utils/uninstall.sh".format( args.uninstall_script_tag ), - IMAGE: "https://github.com/second-state/WasmEdge-image/releases/download/{0}/WasmEdge-image-{0}-{1}".format( - args.image_version, local_release_package_im - ), TENSORFLOW_DEPS: "https://github.com/second-state/WasmEdge-tensorflow-deps/releases/download/{0}/WasmEdge-tensorflow-deps-TF-{0}-{1}".format( args.tf_deps_version, CONST_release_pkg ), TENSORFLOW_LITE_DEPS: "https://github.com/second-state/WasmEdge-tensorflow-deps/releases/download/{0}/WasmEdge-tensorflow-deps-TFLite-{0}-{1}".format( args.tf_deps_version, CONST_release_pkg ), - TENSORFLOW: "https://github.com/second-state/WasmEdge-tensorflow/releases/download/{0}/WasmEdge-tensorflow-{0}-{1}".format( - args.tf_version, local_release_package_tf - ), - TENSORFLOW_LITE: "https://github.com/second-state/WasmEdge-tensorflow/releases/download/{0}/WasmEdge-tensorflowlite-{0}-{1}".format( - args.tf_version, local_release_package_tf - ), - TENSORFLOW_TOOLS: "https://github.com/second-state/WasmEdge-tensorflow-tools/releases/download/{0}/WasmEdge-tensorflow-tools-{0}-{1}".format( - args.tf_tools_version, CONST_release_pkg - ), } @@ -1310,6 +1109,8 @@ def run_shell_command(cmd): except subprocess.CalledProcessError as e: if "Cannot detect installation path" in str(e.output): logging.warning("Uninstaller did not find previous installation") + elif "ldconfig" in str(e.cmd): + logging.debug("Cannot detect libcudart via ldconfig") elif "nvcc" in str(e.cmd): logging.debug("Cannot detect CUDA via nvcc") else: @@ -1357,19 +1158,19 @@ def __init__( machine=platform.machine(), dist_=None, version=None, - extensions=None, ): self.platform = platform_ # Linux, Darwin self.machine = machine # x86_64, arm self.version = VersionString(version) - self.extensions = extensions self.release_package = None self.install_package_name = None self.lib_extension = None self.ld_library_path = None self.dist = dist_ self.release_package_wasmedge = None - self.cuda = check_nvcc(self.platform) or check_nvidia_smi(self.platform) + self.cuda = check_libcudart(self.platform) and ( + check_nvcc(self.platform) or check_nvidia_smi(self.platform) + ) if self.platform == "Linux": self.install_package_name = "WasmEdge-{0}-Linux".format(self.version) @@ -1447,10 +1248,8 @@ def __init__( self.dist = "darwin" def __str__(self): - return ( - "Platform:{0}\nMachine:{1}\nVersion:{2}\nExtensions:{3}\nDist:{4}\n".format( - self.platform, self.machine, self.version, self.extensions, self.dist - ) + return "Platform:{0}\nMachine:{1}\nVersion:{2}\nDist:{3}\n".format( + self.platform, self.machine, self.version, self.dist ) if sys.version_info[0] == 2: @@ -1468,31 +1267,7 @@ def bool_overload(self): reraise(Exception("Unsupported platform: {0}".format(self.platform))) if self.machine not in SUPPORTED_PLATFORM_MACHINE[self.platform]: reraise(Exception("Unsupported machine: {0}".format(self.machine))) - if self.extensions is not None and len(self.extensions) > 0: - if not ( - set(self.extensions) - <= set(SUPPORTED_EXTENSIONS[self.platform + self.machine]) - ): - logging.error("Supported platforms and corresponding extensions:") - for key in SUPPORTED_EXTENSIONS: - _extensions = None - if len(SUPPORTED_EXTENSIONS[key]) >= 1: - _extensions = ",".join(SUPPORTED_EXTENSIONS[key]) - else: - _extensions = "None" - logging.error( - "Platform: {0} Supported Extensions: {1}".format( - key, _extensions - ) - ) - reraise( - Exception( - "Extensions not supported: {0}. Supported extensions: {1}".format( - self.extensions, - SUPPORTED_EXTENSIONS[self.platform + self.machine], - ) - ) - ) + if ( self.version.compare( version2=SUPPORTED_MIN_VERSION[self.platform + self.machine].version @@ -1529,7 +1304,6 @@ def main(args): compat = Compat( version=args.version, - extensions=args.extensions, platform_=args.platform, machine=args.machine, dist_=args.dist, @@ -1548,18 +1322,13 @@ def main(args): args.plugins = PLUGINS_AVAILABLE[:] logging.debug("Selected all of the available plugins: %s", args.plugins) - if len(args.extensions) >= 1 and compat.version.compare("0.13.0") != -1: - logging.warning( - "Extensions exist only for versions below 0.13.0, use plugins instead" - ) - if compat: logging.info("Compatible with current configuration") set_consts(args, compat) - if compat.version.compare("0.10.0") == -1: - logging.error("Please install the 0.10.0 or above versions.") + if compat.version.compare("0.13.0") == -1: + logging.error("Please install the 0.13.0 or above versions.") exit(1) # Run uninstaller @@ -1614,8 +1383,6 @@ def main(args): logging.info("Installing WasmEdge") # Copy the tree for sub_dir in listdir(join(TEMP_PATH, CONST_ipkg)): - if "._" in sub_dir: - continue if sub_dir == "lib64": copytree(join(TEMP_PATH, CONST_ipkg, sub_dir), join(args.path, "lib")) else: @@ -1647,37 +1414,6 @@ def main(args): "WasmEdge installation incorrect: {0}".format(wasmedge_output) ) - if ( - IMAGE in args.extensions - or "all" in args.extensions - and VersionString(args.version).compare("0.13.0") == -1 - ): - if install_image_extension(args, compat) != 0: - logging.error("Error in installing image extensions") - else: - logging.info("Image extension installed") - - if ( - TENSORFLOW in args.extensions - or "all" in args.extensions - and VersionString(args.version).compare("0.13.0") == -1 - ): - if ( - install_tensorflow_extension( - args, - compat, - download_tf_=True, - download_tf_deps_=True, - download_tf_lite_=True, - download_tf_lite_deps_=True, - download_tf_tools_=True, - ) - != 0 - ): - logging.error("Error in installing tensorflow extensions") - else: - logging.info("Tensorflow extension installed") - install_plugins(args, compat) ldconfig(args, compat) @@ -1703,17 +1439,7 @@ def main(args): if __name__ == "__main__": parser = argparse.ArgumentParser( - description="WasmEdge installation, uninstallation and extensions install" - ) - parser.add_argument( - "-e", - "--extension", - dest="extensions", - choices=EXTENSIONS.append("all"), - required=False, - default=[], - nargs="*", - help="Supported Extensions - {0}".format(EXTENSIONS), + description="WasmEdge installation, uninstallation and plugins install" ) parser.add_argument( "-v", @@ -1784,20 +1510,6 @@ def main(args): default=None, help="Tensorflow and tensorflow lite deps version", ) - parser.add_argument( - "--tf-tools-version", - dest="tf_tools_version", - required=False, - default=None, - help="Tensorflow and tensorflow lite tools version", - ) - parser.add_argument( - "--image-version", - dest="image_version", - required=False, - default=None, - help="Image extension version", - ) parser.add_argument( "--platform", "--os", @@ -1846,11 +1558,5 @@ def main(args): else: reraise("Should not reach here") - if args.tf_tools_version is None: - args.tf_tools_version = args.version - - if args.image_version is None: - args.image_version = args.version - logging.debug("Python Version: %s", sys.version_info) main(args) diff --git a/utils/install_v2.sh b/utils/install_v2.sh new file mode 100755 index 000000000000..2987578c055d --- /dev/null +++ b/utils/install_v2.sh @@ -0,0 +1,630 @@ +#!/usr/bin/env bash + +# This is the bootstrap Unix shell script for installing WasmEdge. +# It will detect the platform and architecture, download the corresponding +# WasmEdge release package, and install it to the specified path. + +set -e + +RED=$'\e[0;31m' +GREEN=$'\e[0;32m' +YELLOW=$'\e[0;33m' +NC=$'\e[0m' # No Color +TMP_DIR="/tmp/wasmedge.$$" + +info() { + command printf '\e[0;32mInfo\e[0m: %s\n\n' "$1" +} + +warn() { + command printf '\e[0;33mWarn\e[0m: %s\n\n' "$1" +} + +error() { + command printf '\e[0;31mError\e[0m: %s\n\n' "$1" 1>&2 +} + +eprintf() { + command printf '%s\n' "$1" 1>&2 +} + +get_cuda_version() { + local cuda="" + cuda=$($1 --version 2>/dev/null | grep "Cuda compilation tools" | cut -f5 -d ' ' | cut -f1 -d ',') + echo ${cuda} +} + +detect_cuda_nvcc() { + local cuda="" + if [[ "${BY_PASS_CUDA_VERSION}" != "0" ]]; then + cuda="${BY_PASS_CUDA_VERSION}" + else + nvcc_paths=("nvcc" "/usr/local/cuda/bin/nvcc" "/opt/cuda/bin/nvcc") + for nvcc_path in "${nvcc_paths[@]}" + do + cuda=$(get_cuda_version ${nvcc_path}) + if [[ "${cuda}" =~ "12" ]]; then + cuda="12" + break + elif [[ "${cuda}" =~ "11" ]]; then + cuda="11" + break + fi + done + fi + + echo ${cuda} +} + +detect_libcudart() { + local cudart="0" + LIBCUDART_PATH="/usr/local/cuda/lib64/libcudart.so" + if [[ "${BY_PASS_CUDA_VERSION}" != "0" ]]; then + cudart="1" + elif [ -f ${LIBCUDART_PATH} ]; then + cudart="1" + fi + + echo ${cudart} +} + +_realpath() { + [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" +} + +_downloader() { + local url=$1 + if ! command -v curl &>/dev/null; then + if ! command -v wget &>/dev/null; then + error "Cannot find wget or curl" + eprintf "Please install wget or curl" + exit 1 + else + wget -c --directory-prefix="$TMP_DIR" "$url" + fi + else + pushd "$TMP_DIR" + curl --progress-bar -L -OC0 "$url" + popd + fi +} + +_extractor() { + local prefix="$IPKG" + if ! command -v tar &>/dev/null; then + error "Cannot find tar" + eprintf "Please install tar" + exit_clean 1 + else + local opt + opt=$(tar "$@" 2>&1) + for var in $opt; do + local filtered=${var//$prefix/} + filtered=${filtered//"lib64"/"lib"} + if [[ "$filtered" =~ "x" ]]; then + continue + fi + if [ ! -d "$IPATH/$filtered" ] ; then + if [[ "$filtered" =~ "Plugin" ]] || [[ "$filtered" =~ "plugin" ]] || [[ "$filtered" =~ "ggml" ]]; then + # Plugins installation is handled in install function + continue + fi + if [[ "$2" =~ "lib" ]] && [[ ! "$IPATH/$filtered" =~ "/lib/" ]]; then + echo "#$IPATH/lib/$filtered" >>"$IPATH/env" + local _re_ + [[ "$OS" == "Linux" ]] && _re_='.[0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2}$' + [[ "$OS" == "Darwin" ]] && _re_='[0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2}.' + if [[ "$filtered" =~ $_re_ ]]; then + local _f_ _f2_ _f3_ _f4_ + _f_=${filtered//$_re_/} + _f2_=${filtered#$_f_} + _f2_=${BASH_REMATCH[*]} + + IFS=. read -r var1 var2 <<<"$(if [[ "$filtered" =~ $_re_ ]]; then + echo "${BASH_REMATCH[*]#.}" + fi)" + + _f3_=${filtered//${_f2_}/} # libsome.so.xx.yy.zz --> libsome.so + [[ "$OS" == "Linux" ]] && _f4_="$_f3_.$var1" # libsome.so.xx.yy.zz --> libsome.so.xx + [[ "$OS" == "Darwin" ]] && _f4_="${filtered//.${_f2_}dylib/}"".$var1.dylib" # libsome.xx.yy.zz.dylib --> libsome.xx.dylib + + ln -sf "$IPATH/lib/$filtered" "$IPATH/lib/$_f3_" + echo "#$IPATH/lib/$_f3_" >>"$IPATH/env" + + ln -sf "$IPATH/lib/$filtered" "$IPATH/lib/$_f4_" + echo "#$IPATH/lib/$_f4_" >>"$IPATH/env" + fi + elif [[ "$2" =~ "bin" ]] && [[ ! "$IPATH/$filtered" =~ "/bin/" ]]; then + echo "#$IPATH/bin/$filtered" >>"$IPATH/env" + else + echo "#$IPATH/$filtered" >>"$IPATH/env" + fi + fi + done + fi +} + +if [ "$__HOME__" = "" ]; then + __HOME__="$HOME" +fi + +get_latest_release() { + echo "0.14.0" +} + +VERSION=$(get_latest_release) + +check_os_arch() { + [ -z "${ARCH}" ] && ARCH=$(uname -m) + [ -z "${OS}" ] && OS=$(uname) + RELEASE_PKG="ubuntu20.04_x86_64.tar.gz" + IPKG="WasmEdge-${VERSION}-${OS}" + _LD_LIBRARY_PATH_="LD_LIBRARY_PATH" + + case ${OS} in + 'Linux') + case ${ARCH} in + 'x86_64') ARCH="x86_64";; + 'arm64' | 'armv8*' | 'aarch64') ARCH="aarch64" ;; + 'amd64') ARCH="x86_64" ;; + *) + error "Detected ${OS}-${ARCH} - currently unsupported" + eprintf "Use --os and --arch to specify the OS and ARCH" + exit 1 + ;; + esac + if [ "${LEGACY}" == 1 ]; then + RELEASE_PKG="manylinux2014_${ARCH}.tar.gz" + else + RELEASE_PKG="ubuntu20.04_${ARCH}.tar.gz" + fi + _LD_LIBRARY_PATH_="LD_LIBRARY_PATH" + + ;; + 'Darwin') + case ${ARCH} in + 'x86_64') ARCH="x86_64" ;; + 'arm64' | 'arm' | 'aarch64') ARCH="arm64" ;; + *) + error "Detected ${OS}-${ARCH} - currently unsupported" + eprintf "Use --os and --arch to specify the OS and ARCH" + exit 1 + ;; + esac + RELEASE_PKG="darwin_${ARCH}.tar.gz" + _LD_LIBRARY_PATH_="DYLD_LIBRARY_PATH" + + ;; + *) + error "Detected ${OS}-${ARCH} - currently unsupported" + eprintf "Use --os and --arch to specify the OS and ARCH" + exit 1 + ;; + esac + + info "Detected ${OS}-${ARCH}" +} + +IPATH="$__HOME__/.wasmedge" +VERBOSE=0 +LEGACY=0 +ENABLE_NOAVX=0 +GGML_BUILD_NUMBER="" +DISABLE_WASI_LOGGING="0" +BY_PASS_CUDA_VERSION="0" +BY_PASS_CUDART="0" + +set_ENV() { + ENV="#!/bin/sh + # wasmedge shell setup + # affix colons on either side of \$PATH to simplify matching + case ":\"\${PATH}\":" in + *:\"$1/bin\":*) + ;; + *) + # Prepending path in case a system-installed wasmedge needs to be overridden + if [ -n \"\${PATH}\" ]; then + export PATH=\"$1/bin\":\$PATH + else + export PATH=\"$1/bin\" + fi + ;; +esac +case ":\"\${"$_LD_LIBRARY_PATH_"}\":" in + *:\"$1/lib\":*) + ;; + *) + # Prepending path in case a system-installed wasmedge libs needs to be overridden + if [ -n \"\${"$_LD_LIBRARY_PATH_"}\" ]; then + export $_LD_LIBRARY_PATH_=\"$1/lib\":\$$_LD_LIBRARY_PATH_ + else + export $_LD_LIBRARY_PATH_=\"$1/lib\" + fi + ;; +esac +case ":\"\${"LIBRARY_PATH"}\":" in + *:\"$1/lib\":*) + ;; + *) + if [ -n \"\${LIBRARY_PATH}\" ]; then + export LIBRARY_PATH=\"$1/lib\":\$LIBRARY_PATH + else + export LIBRARY_PATH=\"$1/lib\" + fi + ;; +esac +case ":\"\${"C_INCLUDE_PATH"}\":" in + *:\"$1/include\":*) + ;; + *) + if [ -n \"\${C_INCLUDE_PATH}\" ]; then + export C_INCLUDE_PATH=\"$1/include\":\$C_INCLUDE_PATH + else + export C_INCLUDE_PATH=\"$1/include\" + fi + ;; +esac +case ":\"\${"CPLUS_INCLUDE_PATH"}\":" in + *:\"$1/include\":*) + ;; + *) + if [ -n \"\${CPLUS_INCLUDE_PATH}\" ]; then + export CPLUS_INCLUDE_PATH=\"$1/include\":\$CPLUS_INCLUDE_PATH + else + export CPLUS_INCLUDE_PATH=\"$1/include\" + fi + ;; +esac" +} + +usage() { + cat <<EOF + Usage: $0 -p </path/to/install> [-V] + WasmEdge installation. + Mandatory arguments to long options are mandatory for short options too. + Long options should be assigned with '=' + + -h, --help Display help + + -l, --legacy Enable legacy OS support. + E.g., CentOS 7. + + -v, --version Install the specific version. + + -V, --verbose Run script in verbose mode. + Will print out each step + of execution. + + -p, --path=[/usr/local] Prefix / Path to install + + --noavx Install the GGML noavx plugin. + Default is disabled. + + -b, --ggmlbn=[b2963] Install the specific GGML plugin. + Default is the latest. + + -c, --ggmlcuda=[11/12] Install the specific CUDA enabled GGML plugin. + Default is the none. + + -o, --os=[Linux/Darwin] Set the OS. + Default is detected OS. + + -a, --arch=[x86_64/aarch64/arm64] Set the ARCH. + Default is detected ARCH. + + -t, --tmpdir=[/tmp] Set the temporary directory. + Default is /tmp. + + Example: + ./$0 -p $IPATH --verbose + + Or + ./$0 --path=/usr/local --verbose + + About: + + - wasmedge is the runtime that executes the wasm program or the AOT compiled + shared library format or universal wasm format programs. + +EOF +} + +on_exit() { + cat <<EOF +${RED} + Please see --help + If issue persists make a trace using -V and submit it to +https://github.com/WasmEdge/WasmEdge/issues/new?assignees=&labels=&template=bug_report.md +${NC} +EOF +} + +exit_clean() { + trap - EXIT + exit "$1" +} + +make_dirs() { + for var in "$@"; do + if [ ! -d "$IPATH/$var" ]; then + mkdir -p "$IPATH/$var" + fi + done +} + +cleanup() { + rm -f "${TMP_DIR}/WasmEdge-${VERSION}-${RELEASE_PKG}" + rm -rf "${TMP_DIR}/WasmEdge-${VERSION}-${OS}" +} + +install() { + local dir=$1 + shift + for var in "$@"; do + if [ "$var" = "lib" ]; then + if [ -d "$TMP_DIR/$dir"/lib64 ]; then + cp -rf "$TMP_DIR/$dir"/lib64/* "$IPATH/$var" + else + cp -rf "$TMP_DIR/$dir"/lib/* "$IPATH/$var" + fi + elif [ "$var" = "plugin" ]; then + if [ -d "$TMP_DIR/$dir"/plugin ]; then + if [[ ! $IPATH =~ ^"/usr" ]]; then + cp -rf "$TMP_DIR/$dir"/plugin/* "$IPATH/plugin" + else + cp -rf "$TMP_DIR/$dir"/plugin/* "$IPATH/lib" + fi + for _file_ in "$IPATH/$dir"/plugin/*; do + if [[ "$_file_" =~ "Plugin" ]] || [[ "$_file_" =~ "plugin" ]] || [[ "$_file_" =~ "ggml" ]]; then + local _plugin_name_=${_file_##*/} + if [[ "$IPATH" =~ ^"/usr" ]]; then + echo "#$_file_" >>"$IPATH/env" + else + echo "#$IPATH/plugin/$_plugin_name_" >>"$IPATH/env" + fi + fi + done + fi + else + cp -rf "$TMP_DIR/$dir/$var"/* "$IPATH/$var" + fi + done +} + +get_wasmedge_release() { + info "Fetching WasmEdge-$VERSION" + _downloader "https://github.com/WasmEdge/WasmEdge/releases/download/$VERSION/WasmEdge-$VERSION-$RELEASE_PKG" + _extractor -C "${TMP_DIR}" -vxzf "$TMP_DIR/WasmEdge-$VERSION-$RELEASE_PKG" +} + +get_wasmedge_ggml_plugin() { + info "Fetching WasmEdge-GGML-Plugin" + local CUDA_EXT="" + local NOAVX_EXT="" + if [ "${ENABLE_NOAVX}" == "1" ]; then + # If noavx is given, it will only use CPU with noavx instructions. + info "NOAVX option is given: Use the noavx CPU version." + NOAVX_EXT="-noavx" + else + cuda=$(detect_cuda_nvcc) + cudart=$(detect_libcudart) + info "Detected CUDA version from nvcc: ${cuda}" + if [ "${cuda}" == "" ]; then + info "CUDA version is not detected from nvcc: Use the CPU version." + info "Or you can use '-c 11' or '-c 12' to install the cuda-11 or cuda-12 version manually." + elif [ "${cudart}" == "0" ]; then + info "libcudart.so is not found in the default installation path of CUDA: Use the CPU version." + info "Or you can use '-c 11' or '-c 12' to install the cuda-11 or cuda-12 version manually." + cuda="" # Reset cuda detection result because of the libcudart.so is not found. + fi + + if [ "${cuda}" == "12" ]; then + info "CUDA version 12 is detected from nvcc: Use the GPU version." + CUDA_EXT="-cuda" + elif [ "${cuda}" == "11" ]; then + info "CUDA version 11 is detected from nvcc: Use the GPU version." + CUDA_EXT="-cuda-11" + else + CUDA_EXT="" + fi + fi + + if [ "$GGML_BUILD_NUMBER" == "" ]; then + info "Use default GGML plugin" + _downloader "https://github.com/WasmEdge/WasmEdge/releases/download/$VERSION/WasmEdge-plugin-wasi_nn-ggml${CUDA_EXT}${NOAVX_EXT}-$VERSION-$RELEASE_PKG" + else + info "Use ${GGML_BUILD_NUMBER} GGML plugin" + _downloader "https://github.com/second-state/WASI-NN-GGML-PLUGIN-REGISTRY/raw/main/${VERSION}/${GGML_BUILD_NUMBER}/WasmEdge-plugin-wasi_nn-ggml${CUDA_EXT}${NOAVX_EXT}-$VERSION-$RELEASE_PKG" + fi + + local TMP_PLUGIN_DIR="${TMP_DIR}/${IPKG}/plugin" + mkdir -p "${TMP_PLUGIN_DIR}" + _extractor -C "${TMP_PLUGIN_DIR}" -vxzf "${TMP_DIR}/WasmEdge-plugin-wasi_nn-ggml${CUDA_EXT}${NOAVX_EXT}-${VERSION}-${RELEASE_PKG}" +} + +get_wasmedge_wasi_logging_plugin() { + info "Fetching WASI-Logging-Plugin" + _downloader "https://github.com/WasmEdge/WasmEdge/releases/download/$VERSION/WasmEdge-plugin-wasi_logging-$VERSION-$RELEASE_PKG" + local TMP_PLUGIN_DIR="${TMP_DIR}/${IPKG}/plugin" + mkdir -p "${TMP_PLUGIN_DIR}" + _extractor -C "${TMP_PLUGIN_DIR}" -vxzf "${TMP_DIR}/WasmEdge-plugin-wasi_logging-${VERSION}-${RELEASE_PKG}" +} + +wasmedge_checks() { + if [ "${ARCH}" == $(uname -m) ] && [ "${OS}" == $(uname) ] ; then + # Check only MAJOR.MINOR.PATCH + local version=$1 + + if [ -f "$IPATH/bin/wasmedge" ]; then + info "Installation of wasmedge-${version} successful" + else + error "WasmEdge-${version} isn't found in the installation folder ${IPATH}" + exit 1 + fi + fi + # Bypass if cross compile +} + +main() { + + trap on_exit EXIT + + # getopt is in the util-linux package, + # it'll probably be fine, but it's of course a good thing to keep in mind. + + local OPTIND + OPTLIST="e:h:l:v:p:b:c:o:a:t:V-:" + while getopts $OPTLIST OPT; do + # support long options: https://stackoverflow.com/a/28466267/519360 + if [ "$OPT" = "-" ]; then # long option: reformulate OPT and OPTARG + OPT="${OPTARG%%=*}" # extract long option name + OPTARG="${OPTARG#$OPT}" # extract long option argument (may be empty) + OPTARG="${OPTARG#=}" # if long option argument, remove assigning `=` + fi + case "$OPT" in + h | help) + usage + trap - EXIT + exit 0 + ;; + l | legacy) + LEGACY=1 + ;; + v | version) + VERSION="${OPTARG}" + ;; + V | verbose) + VERBOSE=1 + ;; + p | path) + IPATH="$(_realpath "${OPTARG}")" + ;; + b | ggmlbn) + GGML_BUILD_NUMBER="${OPTARG}" + ;; + nowasilogging) + DISABLE_WASI_LOGGING="1" + ;; + c | ggmlcuda) + BY_PASS_CUDA_VERSION="${OPTARG}" + BY_PASS_CUDART="1" + ;; + noavx) + ENABLE_NOAVX=1 + ;; + o | os) + OS="${OPTARG^}" + ;; + a | arch) + ARCH="${OPTARG}" + ;; + t | tmpdir) + TMP_DIR="${OPTARG}" + ;; + ?) + exit 2 + ;; + ??*) + error "Illegal option -- ${OPTARG}" + exit 1 + ;; + *) + error "Unknown error" + eprintf "please raise an issue on GitHub with the command you ran." + exit 1 + ;; + esac + done + + shift $((OPTIND - 1)) # remove parsed options and args from $@ list + + if [ ! $VERBOSE == 0 ]; then + echo "Verbose Mode" + set -xv + fi + + check_os_arch + + # Run the uninstaller to remove any previous installations + if [ -f "$IPATH/bin/wasmedge" ]; then + bash <(curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/uninstall.sh) -p "$IPATH" -q + fi + + set_ENV "$IPATH" + mkdir -p "$IPATH" + mkdir -p "$TMP_DIR" + # Setup the plugin folder if the installation path is not in the system path + [[ "$IPATH" =~ ^"/usr" ]] || mkdir -p "$IPATH/plugin" + + echo "$ENV" >"$IPATH/env" + echo "# Please do not edit comments below this for uninstallation purpose" >> "$IPATH/env" + + local _source="source \"$IPATH/env\"" + local _grep=$(cat "$__HOME__/.profile" 2>/dev/null | grep "$IPATH/env") + if [ "$_grep" = "" ]; then + [ -f "$__HOME__/.profile" ] && echo "$_source" >>"$__HOME__/.profile" + fi + + local _shell_ _shell_rc + _shell_="${SHELL#${SHELL%/*}/}" + _shell_rc=".""$_shell_""rc" + + if [[ "$_shell_" =~ "zsh" ]]; then + local _grep=$(cat "$__HOME__/.zprofile" 2>/dev/null | grep "$IPATH/env") + if [ "$_grep" = "" ]; then + [ -f "$__HOME__/.zprofile" ] && echo "$_source" >>"$__HOME__/.zprofile" + fi + elif [[ "$_shell_" =~ "bash" ]]; then + local _grep=$(cat "$__HOME__/.bash_profile" 2>/dev/null | grep "$IPATH/env") + if [ "$_grep" = "" ]; then + # If the .bash_profile is not existing, create a new one + [ ! -f "$__HOME__/.bash_profile" ] && touch "$__HOME__/.bash_profile" + [ -f "$__HOME__/.bash_profile" ] && echo "$_source" >>"$__HOME__/.bash_profile" + fi + fi + + local _grep=$(cat "$__HOME__/$_shell_rc" | grep "$IPATH/env") + if [ "$_grep" = "" ]; then + [ -f "$__HOME__/$_shell_rc" ] && echo "$_source" >>"$__HOME__/$_shell_rc" + fi + + if [ -d "$IPATH" ]; then + info "WasmEdge Installation at $IPATH" + make_dirs "include" "lib" "bin" + + get_wasmedge_release + get_wasmedge_ggml_plugin + if [[ "${VERSION}" =~ ^"0.14.1" ]]; then + # WASI-Logging is bundled into the WasmEdge release package starting from 0.14.1-rc.1 + DISABLE_WASI_LOGGING="1" + fi + + if [[ "${DISABLE_WASI_LOGGING}" == "0" ]]; then + get_wasmedge_wasi_logging_plugin + fi + + install "$IPKG" "include" "lib" "bin" "plugin" + wasmedge_checks "$VERSION" + else + error "Installation path invalid" + eprintf "Please provide a valid path" + exit 1 + fi + + trap - EXIT + cleanup + end_message +} + +end_message() { + case ":${PATH}:" in + *:"${IPATH%"/"}/bin":*) + echo "${GREEN}WasmEdge binaries accessible${NC}" + ;; + *) + echo "${GREEN}source $IPATH/env${NC} to use wasmedge binaries" + ;; + esac +} + +main "$@" diff --git a/utils/ohos/build_for_ohos.sh b/utils/ohos/build_for_ohos.sh index 23aa6dec4ebd..4497b8255e2e 100755 --- a/utils/ohos/build_for_ohos.sh +++ b/utils/ohos/build_for_ohos.sh @@ -1,6 +1,6 @@ #!/bin/bash # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC OHOS_DIR_PATH=$1 WASMEDGE_ROOT_PATH=$(dirname $(dirname $(pwd))) @@ -13,7 +13,7 @@ cd ${WASMEDGE_ROOT_PATH} mkdir build cd build -if ! cmake .. -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_AOT_RUNTIME=OFF -DWASMEDGE_BUILD_ON_OHOS=ON -DOHOS_DIR_PATH=${OHOS_DIR_PATH} -DOHOS_SYSROOT_PATH="${OHOS_DIR_PATH}/out/ohos-arm-release/obj/third_party/musl/"; then +if ! cmake .. -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_ON_OHOS=ON -DOHOS_DIR_PATH=${OHOS_DIR_PATH} -DOHOS_SYSROOT_PATH="${OHOS_DIR_PATH}/out/ohos-arm-release/obj/third_party/musl/"; then echo === CMakeOutput.log === cat build/CMakeFiles/CMakeOutput.log echo === CMakeError.log === diff --git a/utils/ohos/configuration/BUILD.gn b/utils/ohos/configuration/BUILD.gn index 8a0fb2b23d03..a348de33bbcf 100644 --- a/utils/ohos/configuration/BUILD.gn +++ b/utils/ohos/configuration/BUILD.gn @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC import("//build/ohos.gni") diff --git a/utils/ohos/configuration/CMakeLists.txt b/utils/ohos/configuration/CMakeLists.txt index 980a23a2119a..3cb4e0474bae 100644 --- a/utils/ohos/configuration/CMakeLists.txt +++ b/utils/ohos/configuration/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC cmake_minimum_required(VERSION 3.10.2) cmake_policy(SET CMP0091 NEW) @@ -71,10 +71,10 @@ include(Helper) # List of WasmEdge options option(WASMEDGE_BUILD_TESTS "Generate build targets for the wasmedge unit tests." OFF) option(WASMEDGE_BUILD_COVERAGE "Generate coverage report. Require WASMEDGE_BUILD_TESTS." OFF) -option(WASMEDGE_BUILD_AOT_RUNTIME "Enable WasmEdge LLVM-based ahead of time compilation runtime." ON) option(WASMEDGE_BUILD_SHARED_LIB "Generate the WasmEdge shared library." ON) option(WASMEDGE_BUILD_STATIC_LIB "Generate the WasmEdge static library." OFF) option(WASMEDGE_BUILD_TOOLS "Generate wasmedge and wasmedgec tools." ON) +option(WASMEDGE_USE_LLVM "Enable WasmEdge LLVM-based ahead of time compilation runtime." ON) option(WASMEDGE_FORCE_DISABLE_LTO "Forcibly disable link time optimization when linking even in Release/RelWithDeb build." OFF) set(WASMEDGE_BUILD_PACKAGE "DEB;RPM" CACHE STRING "Package generate types") set(CPACK_PROJECT_CONFIG_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cpack_config.cmake) @@ -121,4 +121,3 @@ endif() include(CPack) include(CPackComponent) - diff --git a/utils/ohos/configuration/build_thirdparty.py b/utils/ohos/configuration/build_thirdparty.py index cbd5e045069c..4ae8df7007ab 100755 --- a/utils/ohos/configuration/build_thirdparty.py +++ b/utils/ohos/configuration/build_thirdparty.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC import os import sys diff --git a/utils/opencvmini/install-opencvmini.sh b/utils/opencvmini/install-opencvmini.sh index ac5128efd0cc..799f7382baaa 100644 --- a/utils/opencvmini/install-opencvmini.sh +++ b/utils/opencvmini/install-opencvmini.sh @@ -1,11 +1,12 @@ #!/usr/bin/env bash # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2023 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC +OPENCV_VERSION=${OPENCV_VERSION:-4.8.0} -wget -O opencv.zip https://github.com/opencv/opencv/archive/refs/tags/4.8.0.zip +wget -O opencv.zip https://github.com/opencv/opencv/archive/refs/tags/${OPENCV_VERSION}.zip unzip opencv.zip -mv opencv-4.8.0 opencv +mv opencv-${OPENCV_VERSION} opencv mkdir -p opencv/build && cd opencv/build # Configure diff --git a/utils/openwrt/build_for_openwrt.sh b/utils/openwrt/build_for_openwrt.sh index 0ad5d39a000b..9c25e85eedc1 100755 --- a/utils/openwrt/build_for_openwrt.sh +++ b/utils/openwrt/build_for_openwrt.sh @@ -1,6 +1,6 @@ #!/bin/bash # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC OPENWRT_DIR_PATH=$1 WASMEDGE_FATHER_PATH=$(dirname $(dirname $(dirname $(pwd)))) diff --git a/utils/openwrt/configuration/Makefile b/utils/openwrt/configuration/Makefile index 08995b25b9b5..abb56716478d 100644 --- a/utils/openwrt/configuration/Makefile +++ b/utils/openwrt/configuration/Makefile @@ -1,9 +1,9 @@ include $(TOPDIR)/rules.mk - + PKG_NAME:=WasmEdge -PKG_VERSION:=0.12.1 +PKG_VERSION:=0.14.0 PKG_BUILD_DIR:= $(BUILD_DIR)/$(PKG_NAME) -WASMEDGE_SOVERSION:=0.0.2 +WASMEDGE_SOVERSION:=0.1.0 WASMEDGE_SONAME:=0 include $(INCLUDE_DIR)/package.mk @@ -37,7 +37,6 @@ define Package/$(PKG_NAME)/install endef CMAKE_OPTIONS += \ - -DWASMEDGE_BUILD_AOT_RUNTIME=OFF \ + -DWASMEDGE_USE_LLVM=OFF \ $(eval $(call BuildPackage,$(PKG_NAME))) - diff --git a/utils/wasi-cpp-header/.gitignore b/utils/wasi-cpp-header/.gitignore index 1e0e50f76adb..bc1fb2669dae 100644 --- a/utils/wasi-cpp-header/.gitignore +++ b/utils/wasi-cpp-header/.gitignore @@ -7,4 +7,4 @@ proposal_asymmetric_common.witx proposal_common.witx proposal_signatures.witx proposal_symmetric.witx -proposal_external_secrets.witx \ No newline at end of file +proposal_external_secrets.witx diff --git a/utils/wasi-cpp-header/Cargo.toml b/utils/wasi-cpp-header/Cargo.toml index 056bdd9d37ce..658d1e6f401e 100644 --- a/utils/wasi-cpp-header/Cargo.toml +++ b/utils/wasi-cpp-header/Cargo.toml @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC [package] name = "wasi-cpp-header" diff --git a/utils/wasi-cpp-header/add-addrinfo.patch b/utils/wasi-cpp-header/add-addrinfo.patch index 169f1f9cb7c6..b9080244c527 100644 --- a/utils/wasi-cpp-header/add-addrinfo.patch +++ b/utils/wasi-cpp-header/add-addrinfo.patch @@ -108,4 +108,3 @@ ;;; Flags provided to `sock_recv`. (typename $riflags (flags (@witx repr u16) - diff --git a/utils/wasi-cpp-header/add-wasi_sock.patch b/utils/wasi-cpp-header/add-wasi_sock.patch index ee2149668a1e..b910f5be2acc 100644 --- a/utils/wasi-cpp-header/add-wasi_sock.patch +++ b/utils/wasi-cpp-header/add-wasi_sock.patch @@ -72,4 +72,3 @@ + $sock_stream ) ) - diff --git a/utils/wasi-cpp-header/change-tag-type.patch b/utils/wasi-cpp-header/change-tag-type.patch index aa03bd7ba428..1449a9bebde8 100644 --- a/utils/wasi-cpp-header/change-tag-type.patch +++ b/utils/wasi-cpp-header/change-tag-type.patch @@ -17,4 +17,3 @@ + __wasi_preopentype_t tag; __wasi_prestat_u_t u; }; - diff --git a/utils/wasi-cpp-header/crypto_generate.sh b/utils/wasi-cpp-header/crypto_generate.sh index 1f23a3b594ad..fd871eea3b89 100755 --- a/utils/wasi-cpp-header/crypto_generate.sh +++ b/utils/wasi-cpp-header/crypto_generate.sh @@ -13,4 +13,3 @@ for name in "asymmetric_common" "common" "external_secrets" "kx" "signatures" "s target/release/wasi-cpp-header generate --output $ROOT/thirdparty/wasi_crypto/api.hpp proposal_kx.witx proposal_asymmetric_common.witx proposal_common.witx proposal_signatures.witx proposal_symmetric.witx proposal_external_secrets.witx clang-format-12 -i "$ROOT/thirdparty/wasi_crypto/$api.hpp" patch -p1 -d "$ROOT/thirdparty/wasi_crypto" < crypto-custom.patch - diff --git a/utils/wasi-cpp-header/generate.sh b/utils/wasi-cpp-header/generate.sh index 46e004c1bad0..4449288a5d22 100755 --- a/utils/wasi-cpp-header/generate.sh +++ b/utils/wasi-cpp-header/generate.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC set -x @@ -13,4 +13,4 @@ patch -p1 < add-addrinfo.patch patch -p1 < add-wasi_opt.patch target/release/wasi-cpp-header generate --output "$API_FILE" typenames.witx clang-format-12 -i "$API_FILE" -patch -p1 -d "$ROOT/thirdparty/wasi" < change-tag-type.patch \ No newline at end of file +patch -p1 -d "$ROOT/thirdparty/wasi" < change-tag-type.patch diff --git a/utils/wasi-cpp-header/src/cpp_header.rs b/utils/wasi-cpp-header/src/cpp_header.rs index 24e77f449cb1..2ccd79c7d24a 100644 --- a/utils/wasi-cpp-header/src/cpp_header.rs +++ b/utils/wasi-cpp-header/src/cpp_header.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC use heck::ShoutySnakeCase; use witx::*; @@ -9,7 +9,7 @@ pub fn to_cpp_header(doc: &Document, inputs_str: &str) -> String { ret.push_str(&format!( r#"// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC /** * THIS FILE IS AUTO-GENERATED from the following files: diff --git a/utils/wasi-cpp-header/src/lib.rs b/utils/wasi-cpp-header/src/lib.rs index e9630c0a449c..86962415c979 100644 --- a/utils/wasi-cpp-header/src/lib.rs +++ b/utils/wasi-cpp-header/src/lib.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC mod cpp_header; diff --git a/utils/wasi-cpp-header/src/main.rs b/utils/wasi-cpp-header/src/main.rs index ddfb2787f10b..bbca2ea9e508 100644 --- a/utils/wasi-cpp-header/src/main.rs +++ b/utils/wasi-cpp-header/src/main.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #[macro_use] extern crate clap; diff --git a/utils/wasi-crypto/build-openssl.sh b/utils/wasi-crypto/build-openssl.sh index 547170a3f807..45d628bfa1ff 100755 --- a/utils/wasi-crypto/build-openssl.sh +++ b/utils/wasi-crypto/build-openssl.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC echo "Building OpenSSL for wasi-crypto..." # Get OpenSSL source diff --git a/utils/wasi-nn/build-wasinn-ubuntu-openvino.sh b/utils/wasi-nn/build-wasinn-ubuntu-openvino.sh index 5e3be65805bd..0256ab83ff8e 100755 --- a/utils/wasi-nn/build-wasinn-ubuntu-openvino.sh +++ b/utils/wasi-nn/build-wasinn-ubuntu-openvino.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC if [[ ! -v "${CMAKE_BUILD_TYPE}" ]]; then CMAKE_BUILD_TYPE=Release diff --git a/utils/wasi-nn/download-ggml-fixtures.sh b/utils/wasi-nn/download-ggml-fixtures.sh deleted file mode 100755 index bb635925998f..000000000000 --- a/utils/wasi-nn/download-ggml-fixtures.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2023 Second State INC - -TODIR=$1 -if [[ $# -eq 0 ]]; then - TODIR=. -fi -MODEL=orca_mini.gguf -FIXTURE=https://huggingface.co/TheBloke/orca_mini_v3_7B-GGUF/resolve/main/orca_mini_v3_7b.Q2_K.gguf -if [ ! -d $TODIR ]; then - mkdir $TODIR -fi - -if [ ! -f $TODIR/$MODEL ]; then - curl -sL $FIXTURE -o $TODIR/$MODEL -fi diff --git a/utils/wasi-nn/download-openvino-fixtures.sh b/utils/wasi-nn/download-openvino-fixtures.sh deleted file mode 100755 index 02a243da995d..000000000000 --- a/utils/wasi-nn/download-openvino-fixtures.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2022 Second State INC - -TODIR=$1 -if [[ $# -eq 0 ]]; then - TODIR=. -fi -FIXTURE=https://github.com/intel/openvino-rs/raw/v0.3.3/crates/openvino/tests/fixtures/mobilenet/ -if [ ! -d $TODIR ]; then - mkdir $TODIR -fi -if [ ! -d $TODIR ]; then - mkdir $TODIR -fi - -if [ ! -f $TODIR/mobilenet.bin ]; then - curl -sL $FIXTURE/mobilenet.bin -o $TODIR/mobilenet.bin -fi -if [ ! -f $TODIR/mobilenet.xml ]; then - curl -sL $FIXTURE/mobilenet.xml -o $TODIR/mobilenet.xml -fi -if [ ! -f $TODIR/tensor-1x224x224x3-f32.bgr ]; then - curl -sL $FIXTURE/tensor-1x224x224x3-f32.bgr -o $TODIR/tensor-1x224x224x3-f32.bgr -fi diff --git a/utils/wasi-nn/download-pytorch-fixtures.sh b/utils/wasi-nn/download-pytorch-fixtures.sh deleted file mode 100755 index 6a6aab91b7cb..000000000000 --- a/utils/wasi-nn/download-pytorch-fixtures.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2022 Second State INC - -TODIR=$1 -if [[ $# -eq 0 ]]; then - TODIR=. -fi -FIXTURE=https://github.com/second-state/WasmEdge-WASINN-examples/raw/master/pytorch-mobilenet-image/ -if [ ! -d $TODIR ]; then - mkdir $TODIR -fi - -if [ ! -f $TODIR/mobilenet.pt ]; then - curl -sL $FIXTURE/mobilenet.pt -o $TODIR/mobilenet.pt -fi -if [ ! -f $TODIR/image-1x3x224x224.rgb ]; then - curl -sL $FIXTURE/image-1x3x224x224.rgb -o $TODIR/image-1x3x224x224.rgb -fi diff --git a/utils/wasi-nn/download-tflite-fixtures.sh b/utils/wasi-nn/download-tflite-fixtures.sh deleted file mode 100755 index 959d7fee10af..000000000000 --- a/utils/wasi-nn/download-tflite-fixtures.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2022 Second State INC - -TODIR=$1 -if [[ $# -eq 0 ]]; then - TODIR=. -fi -FIXTURE=https://raw.githubusercontent.com/gusye1234/WasmEdge-WASINN-examples/demo-tflite-image/tflite-birds_v1-image -if [ ! -d $TODIR ]; then - mkdir $TODIR -fi - -if [ ! -f $TODIR/lite-model_aiy_vision_classifier_birds_V1_3.tflite ]; then - curl -sL $FIXTURE/lite-model_aiy_vision_classifier_birds_V1_3.tflite -o $TODIR/lite-model_aiy_vision_classifier_birds_V1_3.tflite -fi -if [ ! -f $TODIR/birdx224x224x3.rgb ]; then - curl -sL $FIXTURE/birdx224x224x3.rgb -o $TODIR/birdx224x224x3.rgb -fi diff --git a/utils/wasi-nn/install-onnxruntime.sh b/utils/wasi-nn/install-onnxruntime.sh new file mode 100644 index 000000000000..dad1fb561821 --- /dev/null +++ b/utils/wasi-nn/install-onnxruntime.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + +set -e + +case "$(uname -m)" in + 'x86_64') ARCH='x64' ;; + 'aarch64') ARCH='aarch64' ;; + *) + echo 'Cannot determine architecture for onnxruntime' >&2 + exit 1 + ;; +esac + +: ${ONNXRUNTIME_VERSION:=1.14.1} + +ONNXRUNTIME_NAME="onnxruntime-linux-${ARCH}-${ONNXRUNTIME_VERSION}" +ONNXRUNTIME_TGZ="${ONNXRUNTIME_NAME}.tgz" + +curl -LO "https://github.com/microsoft/onnxruntime/releases/download/v${ONNXRUNTIME_VERSION}/${ONNXRUNTIME_TGZ}" +tar zxf "${ONNXRUNTIME_TGZ}" +mv "${ONNXRUNTIME_NAME}/include/"* /usr/local/include/ +mv "${ONNXRUNTIME_NAME}/lib/"* /usr/local/lib/ +rm -rf "${ONNXRUNTIME_TGZ}" "${ONNXRUNTIME_NAME}" + +ldconfig diff --git a/utils/wasi-nn/install-openvino.sh b/utils/wasi-nn/install-openvino.sh index 761b6a21d2f8..10a3d089f3c5 100755 --- a/utils/wasi-nn/install-openvino.sh +++ b/utils/wasi-nn/install-openvino.sh @@ -1,12 +1,12 @@ #!/usr/bin/env bash # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC set -e -echo "Installing OpenVINO with version 2023.0.2" +echo "Installing OpenVINO with version 2024.2.0" wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB -echo "deb https://apt.repos.intel.com/openvino/2023 ubuntu20 main" | tee /etc/apt/sources.list.d/intel-openvino-2023.list +echo "deb https://apt.repos.intel.com/openvino/2024 ubuntu20 main" | tee /etc/apt/sources.list.d/intel-openvino-2024.list apt update -apt-get -y install openvino-2023.2.0 +apt-get -y install openvino-2024.2.0 ldconfig diff --git a/utils/wasi-nn/install-pytorch.sh b/utils/wasi-nn/install-pytorch.sh index faec86f2eae4..f3fd070e2c0d 100755 --- a/utils/wasi-nn/install-pytorch.sh +++ b/utils/wasi-nn/install-pytorch.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC if [[ ! -n ${PYTORCH_VERSION} ]]; then PYTORCH_VERSION="1.8.2" diff --git a/utils/wasi-nn/test-wasinn-ubuntu-openvino.sh b/utils/wasi-nn/test-wasinn-ubuntu-openvino.sh index 4919853803a6..39ff9d05cd3d 100755 --- a/utils/wasi-nn/test-wasinn-ubuntu-openvino.sh +++ b/utils/wasi-nn/test-wasinn-ubuntu-openvino.sh @@ -1,3 +1,7 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2024 Second State INC + ldconfig export LD_LIBRARY_PATH="$(pwd)/build/lib/api:$LD_LIBRARY_PATH" diff --git a/utils/wasi-test/0001-PATCH-Disable-other-tests-except-wasmedge.patch b/utils/wasi-test/0001-PATCH-Disable-other-tests-except-wasmedge.patch index e6abfe00b9fa..937bbf0f87ab 100644 --- a/utils/wasi-test/0001-PATCH-Disable-other-tests-except-wasmedge.patch +++ b/utils/wasi-test/0001-PATCH-Disable-other-tests-except-wasmedge.patch @@ -40,4 +40,3 @@ index 9341520..da54714 100755 -- 2.31.1 - diff --git a/utils/wasi-test/run-wasi-test.sh b/utils/wasi-test/run-wasi-test.sh index 0acc1c59243f..478255e4cbe1 100755 --- a/utils/wasi-test/run-wasi-test.sh +++ b/utils/wasi-test/run-wasi-test.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # SPDX-License-Identifier: Apache-2.0 -# SPDX-FileCopyrightText: 2019-2022 Second State INC +# SPDX-FileCopyrightText: 2019-2024 Second State INC # Test WasmEdge WASI layer. # The testcase is from https://github.com/khronosproject/wasi-test From e7e055fda5039eefa15e4cd3cdfd73e2be99677d Mon Sep 17 00:00:00 2001 From: turuslan <turuslan.devbox@gmail.com> Date: Tue, 17 Dec 2024 16:33:48 +0500 Subject: [PATCH 2/2] revert lib/llvm/compiler.cpp Signed-off-by: turuslan <turuslan.devbox@gmail.com> --- lib/llvm/compiler.cpp | 274 ++++++++++++++++++++++++++++++++---------- 1 file changed, 213 insertions(+), 61 deletions(-) diff --git a/lib/llvm/compiler.cpp b/lib/llvm/compiler.cpp index afc19a68555f..e2a8bfd49152 100644 --- a/lib/llvm/compiler.cpp +++ b/lib/llvm/compiler.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2019-2022 Second State INC +// SPDX-FileCopyrightText: 2019-2024 Second State INC #include "llvm/compiler.h" @@ -2039,66 +2039,9 @@ class FunctionCompiler { case OpCode::F64x2__replace_lane: compileReplaceLaneOp(Context.Doublex2Ty, Instr.getMemoryLane()); break; - case OpCode::I8x16__swizzle: { - auto Index = Builder.createBitCast(stackPop(), Context.Int8x16Ty); - auto Vector = Builder.createBitCast(stackPop(), Context.Int8x16Ty); - -#if defined(__x86_64__) - if (Context.SupportSSSE3) { - auto Magic = Builder.createVectorSplat(16, LLContext.getInt8(112)); - auto Added = Builder.createAdd(Index, Magic); - auto NewIndex = Builder.createSelect( - Builder.createICmpUGT(Index, Added), - LLVM::Value::getConstAllOnes(Context.Int8x16Ty), Added); - assuming(LLVM::Core::X86SSSE3PShufB128 != LLVM::Core::NotIntrinsic); - stackPush(Builder.createBitCast( - Builder.createIntrinsic(LLVM::Core::X86SSSE3PShufB128, {}, - {Vector, NewIndex}), - Context.Int64x2Ty)); - break; - } -#endif - -#if defined(__aarch64__) - if (Context.SupportNEON) { - assuming(LLVM::Core::AArch64NeonTbl1 != LLVM::Core::NotIntrinsic); - stackPush(Builder.createBitCast( - Builder.createIntrinsic(LLVM::Core::AArch64NeonTbl1, - {Context.Int8x16Ty}, {Vector, Index}), - Context.Int64x2Ty)); - break; - } -#endif - - // Fallback case. - // If the SSSE3 is not supported on the x86_64 platform or - // the NEON is not supported on the aarch64 platform, - // then fallback to this. - auto Mask = Builder.createVectorSplat(16, LLContext.getInt8(15)); - auto Zero = Builder.createVectorSplat(16, LLContext.getInt8(0)); - auto IsOver = Builder.createICmpUGT(Index, Mask); - auto InboundIndex = Builder.createAnd(Index, Mask); - auto Array = - Builder.createArrayAlloca(Context.Int8Ty, LLContext.getInt64(16)); - for (size_t I = 0; I < 16; ++I) { - Builder.createStore( - Builder.createExtractElement(Vector, LLContext.getInt64(I)), - Builder.createInBoundsGEP1(Context.Int8Ty, Array, - LLContext.getInt64(I))); - } - LLVM::Value Ret = LLVM::Value::getUndef(Context.Int8x16Ty); - for (size_t I = 0; I < 16; ++I) { - auto Idx = - Builder.createExtractElement(InboundIndex, LLContext.getInt64(I)); - auto Value = Builder.createLoad( - Context.Int8Ty, - Builder.createInBoundsGEP1(Context.Int8Ty, Array, Idx)); - Ret = Builder.createInsertElement(Ret, Value, LLContext.getInt64(I)); - } - Ret = Builder.createSelect(IsOver, Zero, Ret); - stackPush(Builder.createBitCast(Ret, Context.Int64x2Ty)); + case OpCode::I8x16__swizzle: + compileVectorSwizzle(); break; - } case OpCode::I8x16__splat: compileSplatOp(Context.Int8x16Ty); break; @@ -2734,6 +2677,65 @@ class FunctionCompiler { case OpCode::F64x2__promote_low_f32x4: compileVectorPromote(); break; + case OpCode::I8x16__relaxed_swizzle: + compileVectorSwizzle(); + break; + case OpCode::I32x4__relaxed_trunc_f32x4_s: + compileVectorTruncSatS32(Context.Floatx4Ty, false); + break; + case OpCode::I32x4__relaxed_trunc_f32x4_u: + compileVectorTruncSatU32(Context.Floatx4Ty, false); + break; + case OpCode::I32x4__relaxed_trunc_f64x2_s_zero: + compileVectorTruncSatS32(Context.Doublex2Ty, true); + break; + case OpCode::I32x4__relaxed_trunc_f64x2_u_zero: + compileVectorTruncSatU32(Context.Doublex2Ty, true); + break; + case OpCode::F32x4__relaxed_madd: + compileVectorVectorMAdd(Context.Floatx4Ty); + break; + case OpCode::F32x4__relaxed_nmadd: + compileVectorVectorNMAdd(Context.Floatx4Ty); + break; + case OpCode::F64x2__relaxed_madd: + compileVectorVectorMAdd(Context.Doublex2Ty); + break; + case OpCode::F64x2__relaxed_nmadd: + compileVectorVectorNMAdd(Context.Doublex2Ty); + break; + case OpCode::I8x16__relaxed_laneselect: + case OpCode::I16x8__relaxed_laneselect: + case OpCode::I32x4__relaxed_laneselect: + case OpCode::I64x2__relaxed_laneselect: { + auto C = stackPop(); + auto V2 = stackPop(); + auto V1 = stackPop(); + stackPush(Builder.createXor( + Builder.createAnd(Builder.createXor(V1, V2), C), V2)); + break; + } + case OpCode::F32x4__relaxed_min: + compileVectorVectorFMin(Context.Floatx4Ty); + break; + case OpCode::F32x4__relaxed_max: + compileVectorVectorFMax(Context.Floatx4Ty); + break; + case OpCode::F64x2__relaxed_min: + compileVectorVectorFMin(Context.Doublex2Ty); + break; + case OpCode::F64x2__relaxed_max: + compileVectorVectorFMax(Context.Doublex2Ty); + break; + case OpCode::I16x8__relaxed_q15mulr_s: + compileVectorVectorQ15MulSat(); + break; + case OpCode::I16x8__relaxed_dot_i8x16_i7x16_s: + compileVectorRelaxedIntegerDotProduct(); + break; + case OpCode::I32x4__relaxed_dot_i8x16_i7x16_add_s: + compileVectorRelaxedIntegerDotProductAdd(); + break; case OpCode::Atomic__fence: return compileMemoryFence(); case OpCode::Memory__atomic__notify: @@ -4293,6 +4295,66 @@ class FunctionCompiler { return Builder.createMul(LHS, RHS); }); } + void compileVectorSwizzle() noexcept { + auto Index = Builder.createBitCast(stackPop(), Context.Int8x16Ty); + auto Vector = Builder.createBitCast(stackPop(), Context.Int8x16Ty); + +#if defined(__x86_64__) + if (Context.SupportSSSE3) { + auto Magic = Builder.createVectorSplat(16, LLContext.getInt8(112)); + auto Added = Builder.createAdd(Index, Magic); + auto NewIndex = Builder.createSelect( + Builder.createICmpUGT(Index, Added), + LLVM::Value::getConstAllOnes(Context.Int8x16Ty), Added); + assuming(LLVM::Core::X86SSSE3PShufB128 != LLVM::Core::NotIntrinsic); + stackPush(Builder.createBitCast( + Builder.createIntrinsic(LLVM::Core::X86SSSE3PShufB128, {}, + {Vector, NewIndex}), + Context.Int64x2Ty)); + return; + } +#endif + +#if defined(__aarch64__) + if (Context.SupportNEON) { + assuming(LLVM::Core::AArch64NeonTbl1 != LLVM::Core::NotIntrinsic); + stackPush(Builder.createBitCast( + Builder.createIntrinsic(LLVM::Core::AArch64NeonTbl1, + {Context.Int8x16Ty}, {Vector, Index}), + Context.Int64x2Ty)); + return; + } +#endif + + // Fallback case. + // If the SSSE3 is not supported on the x86_64 platform or + // the NEON is not supported on the aarch64 platform, + // then fallback to this. + auto Mask = Builder.createVectorSplat(16, LLContext.getInt8(15)); + auto Zero = Builder.createVectorSplat(16, LLContext.getInt8(0)); + auto IsOver = Builder.createICmpUGT(Index, Mask); + auto InboundIndex = Builder.createAnd(Index, Mask); + auto Array = + Builder.createArrayAlloca(Context.Int8Ty, LLContext.getInt64(16)); + for (size_t I = 0; I < 16; ++I) { + Builder.createStore( + Builder.createExtractElement(Vector, LLContext.getInt64(I)), + Builder.createInBoundsGEP1(Context.Int8Ty, Array, + LLContext.getInt64(I))); + } + LLVM::Value Ret = LLVM::Value::getUndef(Context.Int8x16Ty); + for (size_t I = 0; I < 16; ++I) { + auto Idx = + Builder.createExtractElement(InboundIndex, LLContext.getInt64(I)); + auto Value = Builder.createLoad( + Context.Int8Ty, + Builder.createInBoundsGEP1(Context.Int8Ty, Array, Idx)); + Ret = Builder.createInsertElement(Ret, Value, LLContext.getInt64(I)); + } + Ret = Builder.createSelect(IsOver, Zero, Ret); + stackPush(Builder.createBitCast(Ret, Context.Int64x2Ty)); + } + void compileVectorVectorQ15MulSat() noexcept { compileVectorVectorOp( Context.Int16x8Ty, [this](auto LHS, auto RHS) noexcept -> LLVM::Value { @@ -4829,6 +4891,96 @@ class FunctionCompiler { }); } + void compileVectorVectorMAdd(LLVM::Type VectorTy) noexcept { + auto C = Builder.createBitCast(stackPop(), VectorTy); + auto RHS = Builder.createBitCast(stackPop(), VectorTy); + auto LHS = Builder.createBitCast(stackPop(), VectorTy); + stackPush(Builder.createFAdd(Builder.createFMul(LHS, RHS), C)); + } + + void compileVectorVectorNMAdd(LLVM::Type VectorTy) noexcept { + auto C = Builder.createBitCast(stackPop(), VectorTy); + auto RHS = Builder.createBitCast(stackPop(), VectorTy); + auto LHS = Builder.createBitCast(stackPop(), VectorTy); + stackPush(Builder.createFAdd( + Builder.createFMul(Builder.createFNeg(LHS), RHS), C)); + } + + void compileVectorRelaxedIntegerDotProduct() noexcept { + auto OriTy = Context.Int8x16Ty; + auto ExtTy = Context.Int16x8Ty; + auto RHS = Builder.createBitCast(stackPop(), OriTy); + auto LHS = Builder.createBitCast(stackPop(), OriTy); +#if defined(__x86_64__) + if (Context.SupportSSSE3) { + assuming(LLVM::Core::X86SSSE3PMAddUbSw128 != LLVM::Core::NotIntrinsic); + // WebAssembly Relaxed SIMD spec: signed(LHS) * unsigned/signed(RHS) + // But PMAddUbSw128 is unsigned(LHS) * signed(RHS). Therefore swap both + // side to match the WebAssembly spec + return stackPush(Builder.createIntrinsic(LLVM::Core::X86SSSE3PMAddUbSw128, + {}, {RHS, LHS})); + } +#endif + auto Width = LLVM::Value::getConstInt( + ExtTy.getElementType(), OriTy.getElementType().getIntegerBitWidth()); + Width = Builder.createVectorSplat(ExtTy.getVectorSize(), Width); + auto EA = Builder.createBitCast(LHS, ExtTy); + auto EB = Builder.createBitCast(RHS, ExtTy); + + LLVM::Value AL, AR, BL, BR; + AL = Builder.createAShr(EA, Width); + AR = Builder.createAShr(Builder.createShl(EA, Width), Width); + BL = Builder.createAShr(EB, Width); + BR = Builder.createAShr(Builder.createShl(EB, Width), Width); + + return stackPush(Builder.createAdd(Builder.createMul(AL, BL), + Builder.createMul(AR, BR))); + } + + void compileVectorRelaxedIntegerDotProductAdd() noexcept { + auto OriTy = Context.Int8x16Ty; + auto ExtTy = Context.Int16x8Ty; + auto FinTy = Context.Int32x4Ty; + auto VC = Builder.createBitCast(stackPop(), FinTy); + auto RHS = Builder.createBitCast(stackPop(), OriTy); + auto LHS = Builder.createBitCast(stackPop(), OriTy); + LLVM::Value IM; +#if defined(__x86_64__) + if (Context.SupportSSSE3) { + assuming(LLVM::Core::X86SSSE3PMAddUbSw128 != LLVM::Core::NotIntrinsic); + // WebAssembly Relaxed SIMD spec: signed(LHS) * unsigned/signed(RHS) + // But PMAddUbSw128 is unsigned(LHS) * signed(RHS). Therefore swap both + // side to match the WebAssembly spec + IM = Builder.createIntrinsic(LLVM::Core::X86SSSE3PMAddUbSw128, {}, + {RHS, LHS}); + } else +#endif + { + auto Width = LLVM::Value::getConstInt( + ExtTy.getElementType(), OriTy.getElementType().getIntegerBitWidth()); + Width = Builder.createVectorSplat(ExtTy.getVectorSize(), Width); + auto EA = Builder.createBitCast(LHS, ExtTy); + auto EB = Builder.createBitCast(RHS, ExtTy); + + LLVM::Value AL, AR, BL, BR; + AL = Builder.createAShr(EA, Width); + AR = Builder.createAShr(Builder.createShl(EA, Width), Width); + BL = Builder.createAShr(EB, Width); + BR = Builder.createAShr(Builder.createShl(EB, Width), Width); + IM = Builder.createAdd(Builder.createMul(AL, BL), + Builder.createMul(AR, BR)); + } + + auto Width = LLVM::Value::getConstInt( + FinTy.getElementType(), ExtTy.getElementType().getIntegerBitWidth()); + Width = Builder.createVectorSplat(FinTy.getVectorSize(), Width); + auto IME = Builder.createBitCast(IM, FinTy); + auto L = Builder.createAShr(IME, Width); + auto R = Builder.createAShr(Builder.createShl(IME, Width), Width); + + return stackPush(Builder.createAdd(Builder.createAdd(L, R), VC)); + } + void enterBlock(LLVM::BasicBlock JumpBlock, LLVM::BasicBlock NextBlock, LLVM::BasicBlock ElseBlock, std::vector<LLVM::Value> Args, @@ -5482,4 +5634,4 @@ void Compiler::compile(const AST::FunctionSection &FuncSec, } } // namespace LLVM -} // namespace WasmEdge \ No newline at end of file +} // namespace WasmEdge