diff --git a/.CurrentChangelog.md b/.CurrentChangelog.md index a23a94d89dd2..b571a2af6ced 100644 --- a/.CurrentChangelog.md +++ b/.CurrentChangelog.md @@ -1,4 +1,4 @@ -### 0.14.0-alpha.1 (2024-01-05) +### 0.14.0 (2024-05-22) Breaking changes: @@ -29,16 +29,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 +87,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 `` 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 +133,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,6 +157,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 +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. 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/actions/expand-variables/dist/index.js b/.github/actions/expand-variables/dist/index.js index f39cb0b80874..5838734091d6 100644 --- a/.github/actions/expand-variables/dist/index.js +++ b/.github/actions/expand-variables/dist/index.js @@ -1,7 +1,7 @@ /******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ -/***/ 5183: +/***/ 8452: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -28,7 +28,7 @@ var __importStar = (this && this.__importStar) || function (mod) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.issue = exports.issueCommand = void 0; const os = __importStar(__nccwpck_require__(2037)); -const utils_1 = __nccwpck_require__(8091); +const utils_1 = __nccwpck_require__(9842); /** * Commands * @@ -100,7 +100,7 @@ function escapeProperty(s) { /***/ }), -/***/ 2619: +/***/ 5662: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -135,12 +135,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }; 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 command_1 = __nccwpck_require__(8452); +const file_command_1 = __nccwpck_require__(1941); +const utils_1 = __nccwpck_require__(9842); const os = __importStar(__nccwpck_require__(2037)); const path = __importStar(__nccwpck_require__(1017)); -const oidc_utils_1 = __nccwpck_require__(3669); +const oidc_utils_1 = __nccwpck_require__(5904); /** * The code to exit an action */ @@ -425,17 +425,17 @@ exports.getIDToken = getIDToken; /** * Summary exports */ -var summary_1 = __nccwpck_require__(4992); +var summary_1 = __nccwpck_require__(7035); Object.defineProperty(exports, "summary", ({ enumerable: true, get: function () { return summary_1.summary; } })); /** * @deprecated use core.summary */ -var summary_2 = __nccwpck_require__(4992); +var summary_2 = __nccwpck_require__(7035); Object.defineProperty(exports, "markdownSummary", ({ enumerable: true, get: function () { return summary_2.markdownSummary; } })); /** * Path exports */ -var path_utils_1 = __nccwpck_require__(6067); +var path_utils_1 = __nccwpck_require__(4039); 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; } })); @@ -443,7 +443,7 @@ Object.defineProperty(exports, "toPlatformPath", ({ enumerable: true, get: funct /***/ }), -/***/ 5939: +/***/ 1941: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -474,8 +474,8 @@ exports.prepareKeyValueMessage = exports.issueFileCommand = void 0; /* 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); +const uuid_1 = __nccwpck_require__(8689); +const utils_1 = __nccwpck_require__(9842); function issueFileCommand(command, message) { const filePath = process.env[`GITHUB_${command}`]; if (!filePath) { @@ -508,7 +508,7 @@ exports.prepareKeyValueMessage = prepareKeyValueMessage; /***/ }), -/***/ 3669: +/***/ 5904: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -524,9 +524,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }; 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); +const http_client_1 = __nccwpck_require__(4498); +const auth_1 = __nccwpck_require__(1562); +const core_1 = __nccwpck_require__(5662); class OidcClient { static createHttpClient(allowRetry = true, maxRetry = 10) { const requestOptions = { @@ -592,7 +592,7 @@ exports.OidcClient = OidcClient; /***/ }), -/***/ 6067: +/***/ 4039: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -657,7 +657,7 @@ exports.toPlatformPath = toPlatformPath; /***/ }), -/***/ 4992: +/***/ 7035: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -947,7 +947,7 @@ exports.summary = _summary; /***/ }), -/***/ 8091: +/***/ 9842: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -994,7 +994,7 @@ exports.toCommandProperties = toCommandProperties; /***/ }), -/***/ 1535: +/***/ 1562: /***/ (function(__unused_webpack_module, exports) { "use strict"; @@ -1082,7 +1082,7 @@ exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHand /***/ }), -/***/ 429: +/***/ 4498: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -1124,9 +1124,9 @@ 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); +const pm = __importStar(__nccwpck_require__(864)); +const tunnel = __importStar(__nccwpck_require__(2618)); +const undici_1 = __nccwpck_require__(4445); var HttpCodes; (function (HttpCodes) { HttpCodes[HttpCodes["OK"] = 200] = "OK"; @@ -1745,7 +1745,7 @@ const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCa /***/ }), -/***/ 5957: +/***/ 864: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -1834,15 +1834,15 @@ function isLoopbackAddress(host) { /***/ }), -/***/ 6237: +/***/ 2618: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { -module.exports = __nccwpck_require__(2576); +module.exports = __nccwpck_require__(4658); /***/ }), -/***/ 2576: +/***/ 4658: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -2114,31 +2114,32 @@ exports.debug = debug; // for test /***/ }), -/***/ 5116: +/***/ 4445: /***/ ((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 Client = __nccwpck_require__(2914) +const Dispatcher = __nccwpck_require__(2804) +const errors = __nccwpck_require__(6330) +const Pool = __nccwpck_require__(9944) +const BalancedPool = __nccwpck_require__(2503) +const Agent = __nccwpck_require__(9614) +const util = __nccwpck_require__(2423) 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) +const api = __nccwpck_require__(6813) +const buildConnector = __nccwpck_require__(8074) +const MockClient = __nccwpck_require__(4454) +const MockAgent = __nccwpck_require__(580) +const MockPool = __nccwpck_require__(4002) +const mockErrors = __nccwpck_require__(5603) +const ProxyAgent = __nccwpck_require__(4080) +const RetryHandler = __nccwpck_require__(1010) +const { getGlobalDispatcher, setGlobalDispatcher } = __nccwpck_require__(6835) +const DecoratorHandler = __nccwpck_require__(3860) +const RedirectHandler = __nccwpck_require__(9644) +const createRedirectInterceptor = __nccwpck_require__(8573) let hasCrypto try { @@ -2156,6 +2157,7 @@ module.exports.Pool = Pool module.exports.BalancedPool = BalancedPool module.exports.Agent = Agent module.exports.ProxyAgent = ProxyAgent +module.exports.RetryHandler = RetryHandler module.exports.DecoratorHandler = DecoratorHandler module.exports.RedirectHandler = RedirectHandler @@ -2220,7 +2222,7 @@ 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) + fetchImpl = (__nccwpck_require__(7628).fetch) } try { @@ -2233,20 +2235,20 @@ if (util.nodeMajor > 16 || (util.nodeMajor === 16 && util.nodeMinor >= 8)) { 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 + module.exports.Headers = __nccwpck_require__(2836).Headers + module.exports.Response = __nccwpck_require__(786).Response + module.exports.Request = __nccwpck_require__(3437).Request + module.exports.FormData = __nccwpck_require__(9188).FormData + module.exports.File = __nccwpck_require__(3442).File + module.exports.FileReader = __nccwpck_require__(7872).FileReader - const { setGlobalOrigin, getGlobalOrigin } = __nccwpck_require__(4428) + const { setGlobalOrigin, getGlobalOrigin } = __nccwpck_require__(4767) module.exports.setGlobalOrigin = setGlobalOrigin module.exports.getGlobalOrigin = getGlobalOrigin - const { CacheStorage } = __nccwpck_require__(6723) - const { kConstruct } = __nccwpck_require__(4063) + const { CacheStorage } = __nccwpck_require__(1012) + const { kConstruct } = __nccwpck_require__(2182) // 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. @@ -2254,21 +2256,21 @@ if (util.nodeMajor > 16 || (util.nodeMajor === 16 && util.nodeMinor >= 8)) { } if (util.nodeMajor >= 16) { - const { deleteCookie, getCookies, getSetCookies, setCookie } = __nccwpck_require__(30) + const { deleteCookie, getCookies, getSetCookies, setCookie } = __nccwpck_require__(49) module.exports.deleteCookie = deleteCookie module.exports.getCookies = getCookies module.exports.getSetCookies = getSetCookies module.exports.setCookie = setCookie - const { parseMIMEType, serializeAMimeType } = __nccwpck_require__(6822) + const { parseMIMEType, serializeAMimeType } = __nccwpck_require__(6515) module.exports.parseMIMEType = parseMIMEType module.exports.serializeAMimeType = serializeAMimeType } if (util.nodeMajor >= 18 && hasCrypto) { - const { WebSocket } = __nccwpck_require__(6624) + const { WebSocket } = __nccwpck_require__(7183) module.exports.WebSocket = WebSocket } @@ -2287,20 +2289,20 @@ module.exports.mockErrors = mockErrors /***/ }), -/***/ 8162: +/***/ 9614: /***/ ((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 { InvalidArgumentError } = __nccwpck_require__(6330) +const { kClients, kRunning, kClose, kDestroy, kDispatch, kInterceptors } = __nccwpck_require__(5724) +const DispatcherBase = __nccwpck_require__(996) +const Pool = __nccwpck_require__(9944) +const Client = __nccwpck_require__(2914) +const util = __nccwpck_require__(2423) +const createRedirectInterceptor = __nccwpck_require__(8573) +const { WeakRef, FinalizationRegistry } = __nccwpck_require__(4987)() const kOnConnect = Symbol('onConnect') const kOnDisconnect = Symbol('onDisconnect') @@ -2443,11 +2445,11 @@ module.exports = Agent /***/ }), -/***/ 1306: +/***/ 3121: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { -const { addAbortListener } = __nccwpck_require__(6223) -const { RequestAbortedError } = __nccwpck_require__(5767) +const { addAbortListener } = __nccwpck_require__(2423) +const { RequestAbortedError } = __nccwpck_require__(6330) const kListener = Symbol('kListener') const kSignal = Symbol('kSignal') @@ -2504,16 +2506,16 @@ module.exports = { /***/ }), -/***/ 2414: +/***/ 5643: /***/ ((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) +const { InvalidArgumentError, RequestAbortedError, SocketError } = __nccwpck_require__(6330) +const util = __nccwpck_require__(2423) +const { addSignal, removeSignal } = __nccwpck_require__(3121) class ConnectHandler extends AsyncResource { constructor (opts, callback) { @@ -2616,7 +2618,7 @@ module.exports = connect /***/ }), -/***/ 7576: +/***/ 9745: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -2631,10 +2633,10 @@ const { InvalidArgumentError, InvalidReturnValueError, RequestAbortedError -} = __nccwpck_require__(5767) -const util = __nccwpck_require__(6223) +} = __nccwpck_require__(6330) +const util = __nccwpck_require__(2423) const { AsyncResource } = __nccwpck_require__(852) -const { addSignal, removeSignal } = __nccwpck_require__(1306) +const { addSignal, removeSignal } = __nccwpck_require__(3121) const assert = __nccwpck_require__(9491) const kResume = Symbol('resume') @@ -2873,21 +2875,21 @@ module.exports = pipeline /***/ }), -/***/ 233: +/***/ 1567: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const Readable = __nccwpck_require__(425) +const Readable = __nccwpck_require__(1121) const { InvalidArgumentError, RequestAbortedError -} = __nccwpck_require__(5767) -const util = __nccwpck_require__(6223) -const { getResolveErrorBodyCallback } = __nccwpck_require__(4726) +} = __nccwpck_require__(6330) +const util = __nccwpck_require__(2423) +const { getResolveErrorBodyCallback } = __nccwpck_require__(9992) const { AsyncResource } = __nccwpck_require__(852) -const { addSignal, removeSignal } = __nccwpck_require__(1306) +const { addSignal, removeSignal } = __nccwpck_require__(3121) class RequestHandler extends AsyncResource { constructor (opts, callback) { @@ -3056,11 +3058,12 @@ function request (opts, callback) { } module.exports = request +module.exports.RequestHandler = RequestHandler /***/ }), -/***/ 5401: +/***/ 9468: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -3071,11 +3074,11 @@ const { InvalidArgumentError, InvalidReturnValueError, RequestAbortedError -} = __nccwpck_require__(5767) -const util = __nccwpck_require__(6223) -const { getResolveErrorBodyCallback } = __nccwpck_require__(4726) +} = __nccwpck_require__(6330) +const util = __nccwpck_require__(2423) +const { getResolveErrorBodyCallback } = __nccwpck_require__(9992) const { AsyncResource } = __nccwpck_require__(852) -const { addSignal, removeSignal } = __nccwpck_require__(1306) +const { addSignal, removeSignal } = __nccwpck_require__(3121) class StreamHandler extends AsyncResource { constructor (opts, factory, callback) { @@ -3288,16 +3291,16 @@ module.exports = stream /***/ }), -/***/ 1771: +/***/ 6160: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const { InvalidArgumentError, RequestAbortedError, SocketError } = __nccwpck_require__(5767) +const { InvalidArgumentError, RequestAbortedError, SocketError } = __nccwpck_require__(6330) const { AsyncResource } = __nccwpck_require__(852) -const util = __nccwpck_require__(6223) -const { addSignal, removeSignal } = __nccwpck_require__(1306) +const util = __nccwpck_require__(2423) +const { addSignal, removeSignal } = __nccwpck_require__(3121) const assert = __nccwpck_require__(9491) class UpgradeHandler extends AsyncResource { @@ -3401,22 +3404,22 @@ module.exports = upgrade /***/ }), -/***/ 4596: +/***/ 6813: /***/ ((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) +module.exports.request = __nccwpck_require__(1567) +module.exports.stream = __nccwpck_require__(9468) +module.exports.pipeline = __nccwpck_require__(9745) +module.exports.upgrade = __nccwpck_require__(6160) +module.exports.connect = __nccwpck_require__(5643) /***/ }), -/***/ 425: +/***/ 1121: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -3426,9 +3429,9 @@ module.exports.connect = __nccwpck_require__(2414) 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) +const { RequestAbortedError, NotSupportedError, InvalidArgumentError } = __nccwpck_require__(6330) +const util = __nccwpck_require__(2423) +const { ReadableStreamFrom, toUSVString } = __nccwpck_require__(2423) let Blob @@ -3438,6 +3441,8 @@ const kBody = Symbol('kBody') const kAbort = Symbol('abort') const kContentType = Symbol('kContentType') +const noop = () => {} + module.exports = class BodyReadable extends Readable { constructor ({ resume, @@ -3571,37 +3576,50 @@ module.exports = class BodyReadable extends Readable { return this[kBody] } - async dump (opts) { + 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 + try { + if (typeof signal !== 'object' || !('aborted' in signal)) { + throw new InvalidArgumentError('signal must be an AbortSignal') } + util.throwIfAborted(signal) + } catch (err) { + return Promise.reject(err) } - } catch { - util.throwIfAborted(signal) - } finally { - if (typeof signalListenerCleanup === 'function') { - signalListenerCleanup() - } else if (signalListenerCleanup) { - signalListenerCleanup[Symbol.dispose]() - } } + + if (this.closed) { + return Promise.resolve(null) + } + + return new Promise((resolve, reject) => { + const signalListenerCleanup = signal + ? util.addAbortListener(signal, () => { + this.destroy() + }) + : noop + + this + .on('close', function () { + signalListenerCleanup() + if (signal && signal.aborted) { + reject(signal.reason || Object.assign(new Error('The operation was aborted'), { name: 'AbortError' })) + } else { + resolve(null) + } + }) + .on('error', noop) + .on('data', function (chunk) { + limit -= chunk.length + if (limit <= 0) { + this.destroy() + } + }) + .resume() + }) } } @@ -3731,14 +3749,14 @@ function consumeFinish (consume, err) { /***/ }), -/***/ 4726: +/***/ 9992: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const assert = __nccwpck_require__(9491) const { ResponseStatusCodeError -} = __nccwpck_require__(5767) -const { toUSVString } = __nccwpck_require__(6223) +} = __nccwpck_require__(6330) +const { toUSVString } = __nccwpck_require__(2423) async function getResolveErrorBodyCallback ({ callback, body, contentType, statusCode, statusMessage, headers }) { assert(body) @@ -3784,7 +3802,7 @@ module.exports = { getResolveErrorBodyCallback } /***/ }), -/***/ 8580: +/***/ 2503: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -3793,7 +3811,7 @@ module.exports = { getResolveErrorBodyCallback } const { BalancedPoolMissingUpstreamError, InvalidArgumentError -} = __nccwpck_require__(5767) +} = __nccwpck_require__(6330) const { PoolBase, kClients, @@ -3801,10 +3819,10 @@ const { kAddClient, kRemoveClient, kGetDispatcher -} = __nccwpck_require__(1273) -const Pool = __nccwpck_require__(9729) -const { kUrl, kInterceptors } = __nccwpck_require__(1439) -const { parseOrigin } = __nccwpck_require__(6223) +} = __nccwpck_require__(8324) +const Pool = __nccwpck_require__(9944) +const { kUrl, kInterceptors } = __nccwpck_require__(5724) +const { parseOrigin } = __nccwpck_require__(2423) const kFactory = Symbol('factory') const kOptions = Symbol('options') @@ -3982,24 +4000,24 @@ module.exports = BalancedPool /***/ }), -/***/ 7011: +/***/ 5271: /***/ ((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 { kConstruct } = __nccwpck_require__(2182) +const { urlEquals, fieldValues: getFieldValues } = __nccwpck_require__(7290) +const { kEnumerableProperty, isDisturbed } = __nccwpck_require__(2423) +const { kHeadersList } = __nccwpck_require__(5724) +const { webidl } = __nccwpck_require__(194) +const { Response, cloneResponse } = __nccwpck_require__(786) +const { Request } = __nccwpck_require__(3437) +const { kState, kHeaders, kGuard, kRealm } = __nccwpck_require__(8042) +const { fetching } = __nccwpck_require__(7628) +const { urlIsHttpHttpsScheme, createDeferredPromise, readAllBytes } = __nccwpck_require__(6890) const assert = __nccwpck_require__(9491) -const { getGlobalDispatcher } = __nccwpck_require__(398) +const { getGlobalDispatcher } = __nccwpck_require__(6835) /** * @see https://w3c.github.io/ServiceWorker/#dfn-cache-batch-operation @@ -4828,16 +4846,16 @@ module.exports = { /***/ }), -/***/ 6723: +/***/ 1012: /***/ ((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) +const { kConstruct } = __nccwpck_require__(2182) +const { Cache } = __nccwpck_require__(5271) +const { webidl } = __nccwpck_require__(194) +const { kEnumerableProperty } = __nccwpck_require__(2423) class CacheStorage { /** @@ -4980,28 +4998,28 @@ module.exports = { /***/ }), -/***/ 4063: -/***/ ((module) => { +/***/ 2182: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; module.exports = { - kConstruct: Symbol('constructable') + kConstruct: (__nccwpck_require__(5724).kConstruct) } /***/ }), -/***/ 8265: +/***/ 7290: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; const assert = __nccwpck_require__(9491) -const { URLSerializer } = __nccwpck_require__(6822) -const { isValidHeaderName } = __nccwpck_require__(6913) +const { URLSerializer } = __nccwpck_require__(6515) +const { isValidHeaderName } = __nccwpck_require__(6890) /** * @see https://url.spec.whatwg.org/#concept-url-equals @@ -5050,7 +5068,7 @@ module.exports = { /***/ }), -/***/ 8224: +/***/ 2914: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -5064,10 +5082,10 @@ 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 util = __nccwpck_require__(2423) +const timers = __nccwpck_require__(5534) +const Request = __nccwpck_require__(3985) +const DispatcherBase = __nccwpck_require__(996) const { RequestContentLengthMismatchError, ResponseContentLengthMismatchError, @@ -5081,8 +5099,8 @@ const { HTTPParserError, ResponseExceededMaxSizeError, ClientDestroyedError -} = __nccwpck_require__(5767) -const buildConnector = __nccwpck_require__(3311) +} = __nccwpck_require__(6330) +const buildConnector = __nccwpck_require__(8074) const { kUrl, kReset, @@ -5134,7 +5152,7 @@ const { kHTTP2BuildRequest, kHTTP2CopyHeaders, kHTTP1BuildRequest -} = __nccwpck_require__(1439) +} = __nccwpck_require__(5724) /** @type {import('http2')} */ let http2 @@ -5540,16 +5558,16 @@ function onHTTP2GoAway (code) { resume(client) } -const constants = __nccwpck_require__(6744) -const createRedirectInterceptor = __nccwpck_require__(9095) +const constants = __nccwpck_require__(3) +const createRedirectInterceptor = __nccwpck_require__(8573) const EMPTY_BUF = Buffer.alloc(0) async function lazyllhttp () { - const llhttpWasmData = process.env.JEST_WORKER_ID ? __nccwpck_require__(7445) : undefined + const llhttpWasmData = process.env.JEST_WORKER_ID ? __nccwpck_require__(2516) : undefined let mod try { - mod = await WebAssembly.compile(Buffer.from(__nccwpck_require__(6442), 'base64')) + mod = await WebAssembly.compile(Buffer.from(__nccwpck_require__(6390), 'base64')) } catch (e) { /* istanbul ignore next */ @@ -5557,7 +5575,7 @@ async function lazyllhttp () { // 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')) + mod = await WebAssembly.compile(Buffer.from(llhttpWasmData || __nccwpck_require__(2516), 'base64')) } return await WebAssembly.instantiate(mod, { @@ -5973,11 +5991,9 @@ class Parser { socket[kReset] = true } - let pause - try { - pause = request.onHeaders(statusCode, headers, this.resume, statusText) === false - } catch (err) { - util.destroy(socket, err) + const pause = request.onHeaders(statusCode, headers, this.resume, statusText) === false + + if (request.aborted) { return -1 } @@ -6024,13 +6040,8 @@ class Parser { this.bytesRead += buf.length - try { - if (request.onData(buf) === false) { - return constants.ERROR.PAUSED - } - } catch (err) { - util.destroy(socket, err) - return -1 + if (request.onData(buf) === false) { + return constants.ERROR.PAUSED } } @@ -6071,11 +6082,7 @@ class Parser { return -1 } - try { - request.onComplete(headers) - } catch (err) { - errorRequest(client, request, err) - } + request.onComplete(headers) client[kQueue][client[kRunningIdx]++] = null @@ -6239,7 +6246,7 @@ async function connect (client) { const idx = hostname.indexOf(']') assert(idx !== -1) - const ip = hostname.substr(1, idx - 1) + const ip = hostname.substring(1, idx) assert(net.isIP(ip)) hostname = ip @@ -6738,6 +6745,7 @@ function writeH2 (client, session, request) { return false } + /** @type {import('node:http2').ClientHttp2Stream} */ let stream const h2State = client[kHTTP2SessionState] @@ -6833,14 +6841,10 @@ function writeH2 (client, session, request) { 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 @@ -6852,7 +6856,9 @@ function writeH2 (client, session, request) { ++h2State.openStreams stream.once('response', headers => { - if (request.onHeaders(Number(headers[HTTP2_HEADER_STATUS]), headers, stream.resume.bind(stream), '') === false) { + const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers + + if (request.onHeaders(Number(statusCode), realHeaders, stream.resume.bind(stream), '') === false) { stream.pause() } }) @@ -6862,13 +6868,17 @@ function writeH2 (client, session, request) { }) stream.on('data', (chunk) => { - if (request.onData(chunk) === false) stream.pause() + 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() + if (h2State.openStreams === 0) { + session.unref() + } }) stream.once('error', function (err) { @@ -7028,7 +7038,11 @@ function writeStream ({ h2stream, body, client, request, socket, contentLength, } } const onAbort = function () { - onFinished(new RequestAbortedError()) + if (finished) { + return + } + const err = new RequestAbortedError() + queueMicrotask(() => onFinished(err)) } const onFinished = function (err) { if (finished) { @@ -7345,7 +7359,7 @@ module.exports = Client /***/ }), -/***/ 7905: +/***/ 4987: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -7353,7 +7367,7 @@ module.exports = Client /* istanbul ignore file: only for Node 12 */ -const { kConnected, kSize } = __nccwpck_require__(1439) +const { kConnected, kSize } = __nccwpck_require__(5724) class CompatWeakRef { constructor (value) { @@ -7401,7 +7415,7 @@ module.exports = function () { /***/ }), -/***/ 8709: +/***/ 8266: /***/ ((module) => { "use strict"; @@ -7421,16 +7435,16 @@ module.exports = { /***/ }), -/***/ 30: +/***/ 49: /***/ ((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) +const { parseSetCookie } = __nccwpck_require__(5706) +const { stringify, getHeadersList } = __nccwpck_require__(6791) +const { webidl } = __nccwpck_require__(194) +const { Headers } = __nccwpck_require__(2836) /** * @typedef {Object} Cookie @@ -7613,15 +7627,15 @@ module.exports = { /***/ }), -/***/ 1915: +/***/ 5706: /***/ ((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 { maxNameValuePairSize, maxAttributeValueSize } = __nccwpck_require__(8266) +const { isCTLExcludingHtab } = __nccwpck_require__(6791) +const { collectASequenceOfCodePointsFast } = __nccwpck_require__(6515) const assert = __nccwpck_require__(9491) /** @@ -7938,14 +7952,14 @@ module.exports = { /***/ }), -/***/ 7318: +/***/ 6791: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; const assert = __nccwpck_require__(9491) -const { kHeadersList } = __nccwpck_require__(1439) +const { kHeadersList } = __nccwpck_require__(5724) function isCTLExcludingHtab (value) { if (value.length === 0) { @@ -8237,7 +8251,7 @@ module.exports = { /***/ }), -/***/ 3311: +/***/ 8074: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -8245,8 +8259,8 @@ module.exports = { const net = __nccwpck_require__(1808) const assert = __nccwpck_require__(9491) -const util = __nccwpck_require__(6223) -const { InvalidArgumentError, ConnectTimeoutError } = __nccwpck_require__(5767) +const util = __nccwpck_require__(2423) +const { InvalidArgumentError, ConnectTimeoutError } = __nccwpck_require__(6330) let tls // include tls conditionally since it is not always available @@ -8434,7 +8448,7 @@ module.exports = buildConnector /***/ }), -/***/ 5767: +/***/ 6330: /***/ ((module) => { "use strict"; @@ -8633,6 +8647,19 @@ class ResponseExceededMaxSizeError extends UndiciError { } } +class RequestRetryError extends UndiciError { + constructor (message, code, { headers, data }) { + super(message) + Error.captureStackTrace(this, RequestRetryError) + this.name = 'RequestRetryError' + this.message = message || 'Request retry error' + this.code = 'UND_ERR_REQ_RETRY' + this.statusCode = code + this.data = data + this.headers = headers + } +} + module.exports = { HTTPParserError, UndiciError, @@ -8652,13 +8679,14 @@ module.exports = { NotSupportedError, ResponseContentLengthMismatchError, BalancedPoolMissingUpstreamError, - ResponseExceededMaxSizeError + ResponseExceededMaxSizeError, + RequestRetryError } /***/ }), -/***/ 1562: +/***/ 3985: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -8667,10 +8695,10 @@ module.exports = { const { InvalidArgumentError, NotSupportedError -} = __nccwpck_require__(5767) +} = __nccwpck_require__(6330) const assert = __nccwpck_require__(9491) -const { kHTTP2BuildRequest, kHTTP2CopyHeaders, kHTTP1BuildRequest } = __nccwpck_require__(1439) -const util = __nccwpck_require__(6223) +const { kHTTP2BuildRequest, kHTTP2CopyHeaders, kHTTP1BuildRequest } = __nccwpck_require__(5724) +const util = __nccwpck_require__(2423) // tokenRegExp and headerCharRegex have been lifted from // https://github.com/nodejs/node/blob/main/lib/_http_common.js @@ -8865,7 +8893,7 @@ class Request { } if (!extractBody) { - extractBody = (__nccwpck_require__(6770).extractBody) + extractBody = (__nccwpck_require__(3979).extractBody) } const [bodyStream, contentType] = extractBody(body) @@ -8894,9 +8922,9 @@ class Request { onBodySent (chunk) { if (this[kHandler].onBodySent) { try { - this[kHandler].onBodySent(chunk) + return this[kHandler].onBodySent(chunk) } catch (err) { - this.onError(err) + this.abort(err) } } } @@ -8908,9 +8936,9 @@ class Request { if (this[kHandler].onRequestSent) { try { - this[kHandler].onRequestSent() + return this[kHandler].onRequestSent() } catch (err) { - this.onError(err) + this.abort(err) } } } @@ -8935,14 +8963,23 @@ class Request { channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }) } - return this[kHandler].onHeaders(statusCode, headers, resume, statusText) + try { + return this[kHandler].onHeaders(statusCode, headers, resume, statusText) + } catch (err) { + this.abort(err) + } } onData (chunk) { assert(!this.aborted) assert(!this.completed) - return this[kHandler].onData(chunk) + try { + return this[kHandler].onData(chunk) + } catch (err) { + this.abort(err) + return false + } } onUpgrade (statusCode, headers, socket) { @@ -8961,7 +8998,13 @@ class Request { if (channels.trailers.hasSubscribers) { channels.trailers.publish({ request: this, trailers }) } - return this[kHandler].onComplete(trailers) + + try { + return this[kHandler].onComplete(trailers) + } catch (err) { + // TODO (fix): This might be a bad idea? + this.onError(err) + } } onError (error) { @@ -8975,6 +9018,7 @@ class Request { return } this.aborted = true + return this[kHandler].onError(error) } @@ -9149,7 +9193,7 @@ module.exports = Request /***/ }), -/***/ 1439: +/***/ 5724: /***/ ((module) => { module.exports = { @@ -9211,24 +9255,26 @@ module.exports = { kHTTP2BuildRequest: Symbol('http2 build request'), kHTTP1BuildRequest: Symbol('http1 build request'), kHTTP2CopyHeaders: Symbol('http2 copy headers'), - kHTTPConnVersion: Symbol('http connection version') + kHTTPConnVersion: Symbol('http connection version'), + kRetryHandlerDefaultRetry: Symbol('retry agent default retry'), + kConstruct: Symbol('constructable') } /***/ }), -/***/ 6223: +/***/ 2423: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; const assert = __nccwpck_require__(9491) -const { kDestroyed, kBodyUsed } = __nccwpck_require__(1439) +const { kDestroyed, kBodyUsed } = __nccwpck_require__(5724) const { IncomingMessage } = __nccwpck_require__(3685) const stream = __nccwpck_require__(2781) const net = __nccwpck_require__(1808) -const { InvalidArgumentError } = __nccwpck_require__(5767) +const { InvalidArgumentError } = __nccwpck_require__(6330) const { Blob } = __nccwpck_require__(4300) const nodeUtil = __nccwpck_require__(3837) const { stringify } = __nccwpck_require__(3477) @@ -9348,13 +9394,13 @@ function getHostname (host) { const idx = host.indexOf(']') assert(idx !== -1) - return host.substr(1, idx - 1) + return host.substring(1, idx) } const idx = host.indexOf(':') if (idx === -1) return host - return host.substr(0, idx) + return host.substring(0, idx) } // IP addresses are not valid server names per RFC6066 @@ -9451,7 +9497,7 @@ function parseHeaders (headers, obj = {}) { if (!val) { if (Array.isArray(headers[i + 1])) { - obj[key] = headers[i + 1] + obj[key] = headers[i + 1].map(x => x.toString('utf8')) } else { obj[key] = headers[i + 1].toString('utf8') } @@ -9654,16 +9700,7 @@ function throwIfAborted (signal) { } } -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) @@ -9687,6 +9724,21 @@ function toUSVString (val) { return `${val}` } +// Parsed accordingly to RFC 9110 +// https://www.rfc-editor.org/rfc/rfc9110#field.content-range +function parseRangeHeader (range) { + if (range == null || range === '') return { start: 0, end: null, size: null } + + const m = range ? range.match(/^bytes (\d+)-(\d+)\/(\d+)?$/) : null + return m + ? { + start: parseInt(m[1]), + end: m[2] ? parseInt(m[2]) : null, + size: m[3] ? parseInt(m[3]) : null + } + : null +} + const kEnumerableProperty = Object.create(null) kEnumerableProperty.enumerable = true @@ -9720,27 +9772,29 @@ module.exports = { buildURL, throwIfAborted, addAbortListener, + parseRangeHeader, nodeMajor, nodeMinor, - nodeHasAutoSelectFamily: nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 13) + nodeHasAutoSelectFamily: nodeMajor > 18 || (nodeMajor === 18 && nodeMinor >= 13), + safeHTTPMethods: ['GET', 'HEAD', 'OPTIONS', 'TRACE'] } /***/ }), -/***/ 8188: +/***/ 996: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const Dispatcher = __nccwpck_require__(1312) +const Dispatcher = __nccwpck_require__(2804) const { ClientDestroyedError, ClientClosedError, InvalidArgumentError -} = __nccwpck_require__(5767) -const { kDestroy, kClose, kDispatch, kInterceptors } = __nccwpck_require__(1439) +} = __nccwpck_require__(6330) +const { kDestroy, kClose, kDispatch, kInterceptors } = __nccwpck_require__(5724) const kDestroyed = Symbol('destroyed') const kClosed = Symbol('closed') @@ -9928,7 +9982,7 @@ module.exports = DispatcherBase /***/ }), -/***/ 1312: +/***/ 2804: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -9955,14 +10009,14 @@ module.exports = Dispatcher /***/ }), -/***/ 6770: +/***/ 3979: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const Busboy = __nccwpck_require__(1702) -const util = __nccwpck_require__(6223) +const Busboy = __nccwpck_require__(9452) +const util = __nccwpck_require__(2423) const { ReadableStreamFrom, isBlobLike, @@ -9970,18 +10024,18 @@ const { 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) +} = __nccwpck_require__(6890) +const { FormData } = __nccwpck_require__(9188) +const { kState } = __nccwpck_require__(8042) +const { webidl } = __nccwpck_require__(194) +const { DOMException, structuredClone } = __nccwpck_require__(4091) const { Blob, File: NativeFile } = __nccwpck_require__(4300) -const { kBodyUsed } = __nccwpck_require__(1439) +const { kBodyUsed } = __nccwpck_require__(5724) const assert = __nccwpck_require__(9491) -const { isErrored } = __nccwpck_require__(6223) +const { isErrored } = __nccwpck_require__(2423) const { isUint8Array, isArrayBuffer } = __nccwpck_require__(9830) -const { File: UndiciFile } = __nccwpck_require__(9072) -const { parseMIMEType, serializeAMimeType } = __nccwpck_require__(6822) +const { File: UndiciFile } = __nccwpck_require__(3442) +const { parseMIMEType, serializeAMimeType } = __nccwpck_require__(6515) let ReadableStream = globalThis.ReadableStream @@ -10568,7 +10622,7 @@ module.exports = { /***/ }), -/***/ 7213: +/***/ 4091: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -10727,12 +10781,12 @@ module.exports = { /***/ }), -/***/ 6822: +/***/ 6515: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { const assert = __nccwpck_require__(9491) const { atob } = __nccwpck_require__(4300) -const { isomorphicDecode } = __nccwpck_require__(6913) +const { isomorphicDecode } = __nccwpck_require__(6890) const encoder = new TextEncoder() @@ -10851,17 +10905,14 @@ function dataURLProcessor (dataURL) { * @param {boolean} excludeFragment */ function URLSerializer (url, excludeFragment = false) { - const href = url.href - if (!excludeFragment) { - return href + return url.href } - const hash = href.lastIndexOf('#') - if (hash === -1) { - return href - } - return href.slice(0, hash) + const href = url.href + const hashLength = url.hash.length + + return hashLength === 0 ? href : href.substring(0, href.length - hashLength) } // https://infra.spec.whatwg.org/#collect-a-sequence-of-code-points @@ -11364,7 +11415,7 @@ module.exports = { /***/ }), -/***/ 9072: +/***/ 3442: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -11372,11 +11423,11 @@ module.exports = { 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 { kState } = __nccwpck_require__(8042) +const { isBlobLike } = __nccwpck_require__(6890) +const { webidl } = __nccwpck_require__(194) +const { parseMIMEType, serializeAMimeType } = __nccwpck_require__(6515) +const { kEnumerableProperty } = __nccwpck_require__(2423) const encoder = new TextEncoder() class File extends Blob { @@ -11716,16 +11767,16 @@ module.exports = { File, FileLike, isFileLike } /***/ }), -/***/ 4595: +/***/ 9188: /***/ ((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 { isBlobLike, toUSVString, makeIterator } = __nccwpck_require__(6890) +const { kState } = __nccwpck_require__(8042) +const { File: UndiciFile, FileLike, isFileLike } = __nccwpck_require__(3442) +const { webidl } = __nccwpck_require__(194) const { Blob, File: NativeFile } = __nccwpck_require__(4300) /** @type {globalThis['File']} */ @@ -11989,7 +12040,7 @@ module.exports = { FormData } /***/ }), -/***/ 4428: +/***/ 4767: /***/ ((module) => { "use strict"; @@ -12037,7 +12088,7 @@ module.exports = { /***/ }), -/***/ 7967: +/***/ 2836: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -12045,20 +12096,27 @@ module.exports = { -const { kHeadersList } = __nccwpck_require__(1439) -const { kGuard } = __nccwpck_require__(1048) -const { kEnumerableProperty } = __nccwpck_require__(6223) +const { kHeadersList, kConstruct } = __nccwpck_require__(5724) +const { kGuard } = __nccwpck_require__(8042) +const { kEnumerableProperty } = __nccwpck_require__(2423) const { makeIterator, isValidHeaderName, isValidHeaderValue -} = __nccwpck_require__(6913) -const { webidl } = __nccwpck_require__(5337) +} = __nccwpck_require__(6890) +const { webidl } = __nccwpck_require__(194) const assert = __nccwpck_require__(9491) const kHeadersMap = Symbol('headers map') const kHeadersSortedMap = Symbol('headers map sorted') +/** + * @param {number} code + */ +function isHTTPWhiteSpaceCharCode (code) { + return code === 0x00a || code === 0x00d || code === 0x009 || code === 0x020 +} + /** * @see https://fetch.spec.whatwg.org/#concept-header-value-normalize * @param {string} potentialValue @@ -12067,12 +12125,12 @@ function headerValueNormalize (potentialValue) { // To normalize a byte sequence potentialValue, remove // any leading and trailing HTTP whitespace bytes from // potentialValue. + let i = 0; let j = potentialValue.length + + while (j > i && isHTTPWhiteSpaceCharCode(potentialValue.charCodeAt(j - 1))) --j + while (j > i && isHTTPWhiteSpaceCharCode(potentialValue.charCodeAt(i))) ++i - // 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 ]+/, '') + return i === 0 && j === potentialValue.length ? potentialValue : potentialValue.substring(i, j) } function fill (headers, object) { @@ -12081,7 +12139,8 @@ function fill (headers, object) { // 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) { + for (let i = 0; i < object.length; ++i) { + const header = object[i] // 1. If header does not contain exactly two items, then throw a TypeError. if (header.length !== 2) { throw webidl.errors.exception({ @@ -12091,15 +12150,16 @@ function fill (headers, object) { } // 2. Append (header’s first item, header’s second item) to headers. - headers.append(header[0], header[1]) + appendHeader(headers, 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) + const keys = Object.keys(object) + for (let i = 0; i < keys.length; ++i) { + appendHeader(headers, keys[i], object[keys[i]]) } } else { throw webidl.errors.conversionFailed({ @@ -12110,6 +12170,50 @@ function fill (headers, object) { } } +/** + * @see https://fetch.spec.whatwg.org/#concept-headers-append + */ +function appendHeader (headers, name, 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 (headers[kGuard] === 'immutable') { + throw new TypeError('immutable') + } else if (headers[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. + return headers[kHeadersList].append(name, value) + + // 8. If headers’s guard is "request-no-cors", then remove + // privileged no-CORS request headers from headers +} + class HeadersList { /** @type {[string, string][]|null} */ cookies = null @@ -12118,7 +12222,7 @@ class HeadersList { if (init instanceof HeadersList) { this[kHeadersMap] = new Map(init[kHeadersMap]) this[kHeadersSortedMap] = init[kHeadersSortedMap] - this.cookies = init.cookies + this.cookies = init.cookies === null ? null : [...init.cookies] } else { this[kHeadersMap] = new Map(init) this[kHeadersSortedMap] = null @@ -12180,7 +12284,7 @@ class HeadersList { // 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 }) + this[kHeadersMap].set(lowercaseName, { name, value }) } // https://fetch.spec.whatwg.org/#concept-header-list-delete @@ -12193,20 +12297,18 @@ class HeadersList { this.cookies = null } - return this[kHeadersMap].delete(name) + 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 - } + const value = this[kHeadersMap].get(name.toLowerCase()) + // 1. If list does not contain name, then 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 + return value === undefined ? null : value.value } * [Symbol.iterator] () { @@ -12232,6 +12334,9 @@ class HeadersList { // https://fetch.spec.whatwg.org/#headers-class class Headers { constructor (init = undefined) { + if (init === kConstruct) { + return + } this[kHeadersList] = new HeadersList() // The new Headers(init) constructor steps are: @@ -12255,43 +12360,7 @@ class Headers { 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) + return appendHeader(this, name, value) } // https://fetch.spec.whatwg.org/#dom-headers-delete @@ -12336,7 +12405,7 @@ class Headers { // 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) + this[kHeadersList].delete(name) } // https://fetch.spec.whatwg.org/#dom-headers-get @@ -12429,7 +12498,7 @@ class Headers { // 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) + this[kHeadersList].set(name, value) } // https://fetch.spec.whatwg.org/#dom-headers-getsetcookie @@ -12465,7 +12534,8 @@ class Headers { const cookies = this[kHeadersList].cookies // 3. For each name of names: - for (const [name, value] of names) { + for (let i = 0; i < names.length; ++i) { + const [name, value] = names[i] // 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 @@ -12473,8 +12543,8 @@ class Headers { // 2. For each value of values: // 1. Append (name, value) to headers. - for (const value of cookies) { - headers.push([name, value]) + for (let j = 0; j < cookies.length; ++j) { + headers.push([name, cookies[j]]) } } else { // 2. Otherwise: @@ -12498,6 +12568,12 @@ class Headers { keys () { webidl.brandCheck(this, Headers) + if (this[kGuard] === 'immutable') { + const value = this[kHeadersSortedMap] + return makeIterator(() => value, 'Headers', + 'key') + } + return makeIterator( () => [...this[kHeadersSortedMap].values()], 'Headers', @@ -12508,6 +12584,12 @@ class Headers { values () { webidl.brandCheck(this, Headers) + if (this[kGuard] === 'immutable') { + const value = this[kHeadersSortedMap] + return makeIterator(() => value, 'Headers', + 'value') + } + return makeIterator( () => [...this[kHeadersSortedMap].values()], 'Headers', @@ -12518,6 +12600,12 @@ class Headers { entries () { webidl.brandCheck(this, Headers) + if (this[kGuard] === 'immutable') { + const value = this[kHeadersSortedMap] + return makeIterator(() => value, 'Headers', + 'key+value') + } + return makeIterator( () => [...this[kHeadersSortedMap].values()], 'Headers', @@ -12597,7 +12685,7 @@ module.exports = { /***/ }), -/***/ 3360: +/***/ 7628: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -12611,9 +12699,9 @@ const { makeAppropriateNetworkError, filterResponse, makeResponse -} = __nccwpck_require__(1570) -const { Headers } = __nccwpck_require__(7967) -const { Request, makeRequest } = __nccwpck_require__(8619) +} = __nccwpck_require__(786) +const { Headers } = __nccwpck_require__(2836) +const { Request, makeRequest } = __nccwpck_require__(3437) const zlib = __nccwpck_require__(9796) const { bytesMatch, @@ -12644,10 +12732,10 @@ const { urlIsLocal, urlIsHttpHttpsScheme, urlHasHttpsScheme -} = __nccwpck_require__(6913) -const { kState, kHeaders, kGuard, kRealm } = __nccwpck_require__(1048) +} = __nccwpck_require__(6890) +const { kState, kHeaders, kGuard, kRealm } = __nccwpck_require__(8042) const assert = __nccwpck_require__(9491) -const { safelyExtractBody } = __nccwpck_require__(6770) +const { safelyExtractBody } = __nccwpck_require__(3979) const { redirectStatusSet, nullBodyStatus, @@ -12655,15 +12743,15 @@ const { requestBodyHeader, subresourceSet, DOMException -} = __nccwpck_require__(7213) -const { kHeadersList } = __nccwpck_require__(1439) +} = __nccwpck_require__(4091) +const { kHeadersList } = __nccwpck_require__(5724) 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 { addAbortListener, isErrored, isReadable, nodeMajor, nodeMinor } = __nccwpck_require__(2423) +const { dataURLProcessor, serializeAMimeType } = __nccwpck_require__(6515) const { TransformStream } = __nccwpck_require__(5356) -const { getGlobalDispatcher } = __nccwpck_require__(398) -const { webidl } = __nccwpck_require__(5337) +const { getGlobalDispatcher } = __nccwpck_require__(6835) +const { webidl } = __nccwpck_require__(194) const { STATUS_CODES } = __nccwpck_require__(3685) const GET_OR_HEAD = ['GET', 'HEAD'] @@ -12889,7 +12977,7 @@ function finalizeAndReportTiming (response, initiatorType = 'other') { } // 8. If response’s timing allow passed flag is not set, then: - if (!timingInfo.timingAllowPassed) { + if (!response.timingAllowPassed) { // 1. Set timingInfo to a the result of creating an opaque timing info for timingInfo. timingInfo = createOpaqueTimingInfo({ startTime: timingInfo.startTime @@ -13806,6 +13894,9 @@ function httpRedirectFetch (fetchParams, response) { // https://fetch.spec.whatwg.org/#cors-non-wildcard-request-header-name request.headersList.delete('authorization') + // https://fetch.spec.whatwg.org/#authentication-entries + request.headersList.delete('proxy-authorization', true) + // "Cookie" and "Host" are forbidden request-headers, which undici doesn't implement. request.headersList.delete('cookie') request.headersList.delete('host') @@ -14560,7 +14651,7 @@ async function httpNetworkFetch ( path: url.pathname + url.search, origin: url.origin, method: request.method, - body: fetchParams.controller.dispatcher.isMockActive ? request.body && request.body.source : body, + body: fetchParams.controller.dispatcher.isMockActive ? request.body && (request.body.source || request.body.stream) : body, headers: request.headersList.entries, maxRedirections: 0, upgrade: request.mode === 'websocket' ? 'websocket' : undefined @@ -14605,7 +14696,7 @@ async function httpNetworkFetch ( location = val } - headers.append(key, val) + headers[kHeadersList].append(key, val) } } else { const keys = Object.keys(headersList) @@ -14619,7 +14710,7 @@ async function httpNetworkFetch ( location = val } - headers.append(key, val) + headers[kHeadersList].append(key, val) } } @@ -14723,7 +14814,7 @@ async function httpNetworkFetch ( const key = headersList[n + 0].toString('latin1') const val = headersList[n + 1].toString('latin1') - headers.append(key, val) + headers[kHeadersList].append(key, val) } resolve({ @@ -14750,7 +14841,7 @@ module.exports = { /***/ }), -/***/ 8619: +/***/ 3437: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -14758,16 +14849,17 @@ module.exports = { -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 { extractBody, mixinBody, cloneBody } = __nccwpck_require__(3979) +const { Headers, fill: fillHeaders, HeadersList } = __nccwpck_require__(2836) +const { FinalizationRegistry } = __nccwpck_require__(4987)() +const util = __nccwpck_require__(2423) const { isValidHTTPToken, sameOrigin, normalizeMethod, - makePolicyContainer -} = __nccwpck_require__(6913) + makePolicyContainer, + normalizeMethodRecord +} = __nccwpck_require__(6890) const { forbiddenMethodsSet, corsSafeListedMethodsSet, @@ -14777,19 +14869,18 @@ const { requestCredentials, requestCache, requestDuplex -} = __nccwpck_require__(7213) +} = __nccwpck_require__(4091) 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 { kHeaders, kSignal, kState, kGuard, kRealm } = __nccwpck_require__(8042) +const { webidl } = __nccwpck_require__(194) +const { getGlobalOrigin } = __nccwpck_require__(4767) +const { URLSerializer } = __nccwpck_require__(6515) +const { kHeadersList, kConstruct } = __nccwpck_require__(5724) 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 }) => { @@ -14800,7 +14891,7 @@ const requestFinalizer = new FinalizationRegistry(({ signal, abort }) => { class Request { // https://fetch.spec.whatwg.org/#dom-request constructor (input, init = {}) { - if (input === kInit) { + if (input === kConstruct) { return } @@ -14939,8 +15030,10 @@ class Request { urlList: [...request.urlList] }) + const initHasKey = Object.keys(init).length !== 0 + // 13. If init is not empty, then: - if (Object.keys(init).length > 0) { + if (initHasKey) { // 1. If request’s mode is "navigate", then set it to "same-origin". if (request.mode === 'navigate') { request.mode = 'same-origin' @@ -15055,7 +15148,7 @@ class Request { } // 23. If init["integrity"] exists, then set request’s integrity metadata to it. - if (init.integrity !== undefined && init.integrity != null) { + if (init.integrity != null) { request.integrity = String(init.integrity) } @@ -15071,16 +15164,16 @@ class Request { // 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 (!isValidHTTPToken(method)) { + throw new TypeError(`'${method}' is not a valid HTTP method.`) } if (forbiddenMethodsSet.has(method.toUpperCase())) { - throw TypeError(`'${init.method}' HTTP method is unsupported.`) + throw new TypeError(`'${method}' HTTP method is unsupported.`) } // 3. Normalize method. - method = normalizeMethod(init.method) + method = normalizeMethodRecord[method] ?? normalizeMethod(method) // 4. Set request’s method to method. request.method = method @@ -15151,7 +15244,7 @@ class Request { // 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] = new Headers(kConstruct) this[kHeaders][kHeadersList] = request.headersList this[kHeaders][kGuard] = 'request' this[kHeaders][kRealm] = this[kRealm] @@ -15171,25 +15264,25 @@ class Request { } // 32. If init is not empty, then: - if (Object.keys(init).length !== 0) { + if (initHasKey) { + /** @type {HeadersList} */ + const headersList = this[kHeaders][kHeadersList] // 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 - } + const headers = init.headers !== undefined ? init.headers : new HeadersList(headersList) // 3. Empty this’s headers’s header list. - this[kHeaders][kHeadersList].clear() + headersList.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') { + if (headers instanceof HeadersList) { for (const [key, val] of headers) { - this[kHeaders].append(key, val) + headersList.append(key, val) } + // Note: Copy the `set-cookie` meta-data. + headersList.cookies = headers.cookies } else { // 5. Otherwise, fill this’s headers with headers. fillHeaders(this[kHeaders], headers) @@ -15478,10 +15571,10 @@ class Request { // 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) + const clonedRequestObject = new Request(kConstruct) clonedRequestObject[kState] = clonedRequest clonedRequestObject[kRealm] = this[kRealm] - clonedRequestObject[kHeaders] = new Headers() + clonedRequestObject[kHeaders] = new Headers(kConstruct) clonedRequestObject[kHeaders][kHeadersList] = clonedRequest.headersList clonedRequestObject[kHeaders][kGuard] = this[kHeaders][kGuard] clonedRequestObject[kHeaders][kRealm] = this[kHeaders][kRealm] @@ -15702,15 +15795,15 @@ module.exports = { Request, makeRequest } /***/ }), -/***/ 1570: +/***/ 786: /***/ ((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 { Headers, HeadersList, fill } = __nccwpck_require__(2836) +const { extractBody, cloneBody, mixinBody } = __nccwpck_require__(3979) +const util = __nccwpck_require__(2423) const { kEnumerableProperty } = util const { isValidReasonPhrase, @@ -15720,18 +15813,18 @@ const { serializeJavascriptValueToJSONString, isErrorLike, isomorphicEncode -} = __nccwpck_require__(6913) +} = __nccwpck_require__(6890) 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) +} = __nccwpck_require__(4091) +const { kState, kHeaders, kGuard, kRealm } = __nccwpck_require__(8042) +const { webidl } = __nccwpck_require__(194) +const { FormData } = __nccwpck_require__(9188) +const { getGlobalOrigin } = __nccwpck_require__(4767) +const { URLSerializer } = __nccwpck_require__(6515) +const { kHeadersList, kConstruct } = __nccwpck_require__(5724) const assert = __nccwpck_require__(9491) const { types } = __nccwpck_require__(3837) @@ -15852,7 +15945,7 @@ class Response { // 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] = new Headers(kConstruct) this[kHeaders][kGuard] = 'response' this[kHeaders][kHeadersList] = this[kState].headersList this[kHeaders][kRealm] = this[kRealm] @@ -16222,11 +16315,7 @@ webidl.converters.XMLHttpRequestBodyInit = function (V) { return webidl.converters.Blob(V, { strict: false }) } - if ( - types.isAnyArrayBuffer(V) || - types.isTypedArray(V) || - types.isDataView(V) - ) { + if (types.isArrayBuffer(V) || types.isTypedArray(V) || types.isDataView(V)) { return webidl.converters.BufferSource(V) } @@ -16285,7 +16374,7 @@ module.exports = { /***/ }), -/***/ 1048: +/***/ 8042: /***/ ((module) => { "use strict"; @@ -16303,16 +16392,16 @@ module.exports = { /***/ }), -/***/ 6913: +/***/ 6890: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet } = __nccwpck_require__(7213) -const { getGlobalOrigin } = __nccwpck_require__(4428) +const { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet } = __nccwpck_require__(4091) +const { getGlobalOrigin } = __nccwpck_require__(4767) const { performance } = __nccwpck_require__(4074) -const { isBlobLike, toUSVString, ReadableStreamFrom } = __nccwpck_require__(6223) +const { isBlobLike, toUSVString, ReadableStreamFrom } = __nccwpck_require__(2423) const assert = __nccwpck_require__(9491) const { isUint8Array } = __nccwpck_require__(9830) @@ -16412,52 +16501,57 @@ function isValidReasonPhrase (statusText) { 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 https://tools.ietf.org/html/rfc7230#section-3.2.6 + * @param {number} c + */ +function isTokenCharCode (c) { + switch (c) { + case 0x22: + case 0x28: + case 0x29: + case 0x2c: + case 0x2f: + case 0x3a: + case 0x3b: + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + case 0x40: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x7b: + case 0x7d: + // DQUOTE and "(),/:;<=>?@[\]{}" + return false + default: + // VCHAR %x21-7E + return c >= 0x21 && c <= 0x7e + } } -// See RFC 7230, Section 3.2.6. -// https://github.com/chromium/chromium/blob/d7da0240cae77824d1eda25745c4022757499131/third_party/blink/renderer/platform/network/http_parsers.cc#L321 +/** + * @param {string} characters + */ function isValidHTTPToken (characters) { - if (!characters || typeof characters !== 'string') { + if (characters.length === 0) { return false } for (let i = 0; i < characters.length; ++i) { - const c = characters.charCodeAt(i) - if (c > 0x7f || !isTokenChar(c)) { + if (!isTokenCharCode(characters.charCodeAt(i))) { return false } } return true } -// https://fetch.spec.whatwg.org/#header-name -// https://github.com/chromium/chromium/blob/b3d37e6f94f87d59e44662d6078f6a12de845d17/net/http/http_util.cc#L342 +/** + * @see https://fetch.spec.whatwg.org/#header-name + * @param {string} potentialValue + */ function isValidHeaderName (potentialValue) { - if (potentialValue.length === 0) { - return false - } - return isValidHTTPToken(potentialValue) } @@ -17002,11 +17096,30 @@ function isCancelled (fetchParams) { fetchParams.controller.state === 'terminated' } -// https://fetch.spec.whatwg.org/#concept-method-normalize +const normalizeMethodRecord = { + delete: 'DELETE', + DELETE: 'DELETE', + get: 'GET', + GET: 'GET', + head: 'HEAD', + HEAD: 'HEAD', + options: 'OPTIONS', + OPTIONS: 'OPTIONS', + post: 'POST', + POST: 'POST', + put: 'PUT', + PUT: 'PUT' +} + +// Note: object prototypes should not be able to be referenced. e.g. `Object#hasOwnProperty`. +Object.setPrototypeOf(normalizeMethodRecord, null) + +/** + * @see https://fetch.spec.whatwg.org/#concept-method-normalize + * @param {string} method + */ function normalizeMethod (method) { - return /^(DELETE|GET|HEAD|OPTIONS|POST|PUT)$/i.test(method) - ? method.toUpperCase() - : method + return normalizeMethodRecord[method.toLowerCase()] ?? method } // https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string @@ -17351,20 +17464,21 @@ module.exports = { urlIsLocal, urlHasHttpsScheme, urlIsHttpHttpsScheme, - readAllBytes + readAllBytes, + normalizeMethodRecord } /***/ }), -/***/ 5337: +/***/ 194: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; const { types } = __nccwpck_require__(3837) -const { hasOwn, toUSVString } = __nccwpck_require__(6913) +const { hasOwn, toUSVString } = __nccwpck_require__(6890) /** @type {import('../../types/webidl').Webidl} */ const webidl = {} @@ -17790,12 +17904,10 @@ webidl.converters.ByteString = function (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) { + if (x.charCodeAt(index) > 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.` + `index ${index} has a value of ${x.charCodeAt(index)} which is greater than 255.` ) } } @@ -18013,7 +18125,7 @@ module.exports = { /***/ }), -/***/ 7645: +/***/ 7958: /***/ ((module) => { "use strict"; @@ -18311,7 +18423,7 @@ module.exports = { /***/ }), -/***/ 7784: +/***/ 7872: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -18321,16 +18433,16 @@ const { staticPropertyDescriptors, readOperation, fireAProgressEvent -} = __nccwpck_require__(3934) +} = __nccwpck_require__(9326) const { kState, kError, kResult, kEvents, kAborted -} = __nccwpck_require__(8587) -const { webidl } = __nccwpck_require__(5337) -const { kEnumerableProperty } = __nccwpck_require__(6223) +} = __nccwpck_require__(1116) +const { webidl } = __nccwpck_require__(194) +const { kEnumerableProperty } = __nccwpck_require__(2423) class FileReader extends EventTarget { constructor () { @@ -18663,13 +18775,13 @@ module.exports = { /***/ }), -/***/ 1764: +/***/ 8738: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const { webidl } = __nccwpck_require__(5337) +const { webidl } = __nccwpck_require__(194) const kState = Symbol('ProgressEvent state') @@ -18749,7 +18861,7 @@ module.exports = { /***/ }), -/***/ 8587: +/***/ 1116: /***/ ((module) => { "use strict"; @@ -18767,7 +18879,7 @@ module.exports = { /***/ }), -/***/ 3934: +/***/ 9326: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -18779,11 +18891,11 @@ const { 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) +} = __nccwpck_require__(1116) +const { ProgressEvent } = __nccwpck_require__(8738) +const { getEncoding } = __nccwpck_require__(7958) +const { DOMException } = __nccwpck_require__(4091) +const { serializeAMimeType, parseMIMEType } = __nccwpck_require__(6515) const { types } = __nccwpck_require__(3837) const { StringDecoder } = __nccwpck_require__(1576) const { btoa } = __nccwpck_require__(4300) @@ -19167,7 +19279,7 @@ module.exports = { /***/ }), -/***/ 398: +/***/ 6835: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -19176,8 +19288,8 @@ module.exports = { // 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) +const { InvalidArgumentError } = __nccwpck_require__(6330) +const Agent = __nccwpck_require__(9614) if (getGlobalDispatcher() === undefined) { setGlobalDispatcher(new Agent()) @@ -19207,7 +19319,7 @@ module.exports = { /***/ }), -/***/ 3978: +/***/ 3860: /***/ ((module) => { "use strict"; @@ -19250,16 +19362,16 @@ module.exports = class DecoratorHandler { /***/ }), -/***/ 1962: +/***/ 9644: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const util = __nccwpck_require__(6223) -const { kBodyUsed } = __nccwpck_require__(1439) +const util = __nccwpck_require__(2423) +const { kBodyUsed } = __nccwpck_require__(5724) const assert = __nccwpck_require__(9491) -const { InvalidArgumentError } = __nccwpck_require__(5767) +const { InvalidArgumentError } = __nccwpck_require__(6330) const EE = __nccwpck_require__(2361) const redirectableStatusCodes = [300, 301, 302, 303, 307, 308] @@ -19474,13 +19586,356 @@ module.exports = RedirectHandler /***/ }), -/***/ 9095: +/***/ 1010: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const assert = __nccwpck_require__(9491) + +const { kRetryHandlerDefaultRetry } = __nccwpck_require__(5724) +const { RequestRetryError } = __nccwpck_require__(6330) +const { isDisturbed, parseHeaders, parseRangeHeader } = __nccwpck_require__(2423) + +function calculateRetryAfterHeader (retryAfter) { + const current = Date.now() + const diff = new Date(retryAfter).getTime() - current + + return diff +} + +class RetryHandler { + constructor (opts, handlers) { + const { retryOptions, ...dispatchOpts } = opts + const { + // Retry scoped + retry: retryFn, + maxRetries, + maxTimeout, + minTimeout, + timeoutFactor, + // Response scoped + methods, + errorCodes, + retryAfter, + statusCodes + } = retryOptions ?? {} + + this.dispatch = handlers.dispatch + this.handler = handlers.handler + this.opts = dispatchOpts + this.abort = null + this.aborted = false + this.retryOpts = { + retry: retryFn ?? RetryHandler[kRetryHandlerDefaultRetry], + retryAfter: retryAfter ?? true, + maxTimeout: maxTimeout ?? 30 * 1000, // 30s, + timeout: minTimeout ?? 500, // .5s + timeoutFactor: timeoutFactor ?? 2, + maxRetries: maxRetries ?? 5, + // What errors we should retry + methods: methods ?? ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE'], + // Indicates which errors to retry + statusCodes: statusCodes ?? [500, 502, 503, 504, 429], + // List of errors to retry + errorCodes: errorCodes ?? [ + 'ECONNRESET', + 'ECONNREFUSED', + 'ENOTFOUND', + 'ENETDOWN', + 'ENETUNREACH', + 'EHOSTDOWN', + 'EHOSTUNREACH', + 'EPIPE' + ] + } + + this.retryCount = 0 + this.start = 0 + this.end = null + this.etag = null + this.resume = null + + // Handle possible onConnect duplication + this.handler.onConnect(reason => { + this.aborted = true + if (this.abort) { + this.abort(reason) + } else { + this.reason = reason + } + }) + } + + onRequestSent () { + if (this.handler.onRequestSent) { + this.handler.onRequestSent() + } + } + + onUpgrade (statusCode, headers, socket) { + if (this.handler.onUpgrade) { + this.handler.onUpgrade(statusCode, headers, socket) + } + } + + onConnect (abort) { + if (this.aborted) { + abort(this.reason) + } else { + this.abort = abort + } + } + + onBodySent (chunk) { + if (this.handler.onBodySent) return this.handler.onBodySent(chunk) + } + + static [kRetryHandlerDefaultRetry] (err, { state, opts }, cb) { + const { statusCode, code, headers } = err + const { method, retryOptions } = opts + const { + maxRetries, + timeout, + maxTimeout, + timeoutFactor, + statusCodes, + errorCodes, + methods + } = retryOptions + let { counter, currentTimeout } = state + + currentTimeout = + currentTimeout != null && currentTimeout > 0 ? currentTimeout : timeout + + // Any code that is not a Undici's originated and allowed to retry + if ( + code && + code !== 'UND_ERR_REQ_RETRY' && + code !== 'UND_ERR_SOCKET' && + !errorCodes.includes(code) + ) { + cb(err) + return + } + + // If a set of method are provided and the current method is not in the list + if (Array.isArray(methods) && !methods.includes(method)) { + cb(err) + return + } + + // If a set of status code are provided and the current status code is not in the list + if ( + statusCode != null && + Array.isArray(statusCodes) && + !statusCodes.includes(statusCode) + ) { + cb(err) + return + } + + // If we reached the max number of retries + if (counter > maxRetries) { + cb(err) + return + } + + let retryAfterHeader = headers != null && headers['retry-after'] + if (retryAfterHeader) { + retryAfterHeader = Number(retryAfterHeader) + retryAfterHeader = isNaN(retryAfterHeader) + ? calculateRetryAfterHeader(retryAfterHeader) + : retryAfterHeader * 1e3 // Retry-After is in seconds + } + + const retryTimeout = + retryAfterHeader > 0 + ? Math.min(retryAfterHeader, maxTimeout) + : Math.min(currentTimeout * timeoutFactor ** counter, maxTimeout) + + state.currentTimeout = retryTimeout + + setTimeout(() => cb(null), retryTimeout) + } + + onHeaders (statusCode, rawHeaders, resume, statusMessage) { + const headers = parseHeaders(rawHeaders) + + this.retryCount += 1 + + if (statusCode >= 300) { + this.abort( + new RequestRetryError('Request failed', statusCode, { + headers, + count: this.retryCount + }) + ) + return false + } + + // Checkpoint for resume from where we left it + if (this.resume != null) { + this.resume = null + + if (statusCode !== 206) { + return true + } + + const contentRange = parseRangeHeader(headers['content-range']) + // If no content range + if (!contentRange) { + this.abort( + new RequestRetryError('Content-Range mismatch', statusCode, { + headers, + count: this.retryCount + }) + ) + return false + } + + // Let's start with a weak etag check + if (this.etag != null && this.etag !== headers.etag) { + this.abort( + new RequestRetryError('ETag mismatch', statusCode, { + headers, + count: this.retryCount + }) + ) + return false + } + + const { start, size, end = size } = contentRange + + assert(this.start === start, 'content-range mismatch') + assert(this.end == null || this.end === end, 'content-range mismatch') + + this.resume = resume + return true + } + + if (this.end == null) { + if (statusCode === 206) { + // First time we receive 206 + const range = parseRangeHeader(headers['content-range']) + + if (range == null) { + return this.handler.onHeaders( + statusCode, + rawHeaders, + resume, + statusMessage + ) + } + + const { start, size, end = size } = range + + assert( + start != null && Number.isFinite(start) && this.start !== start, + 'content-range mismatch' + ) + assert(Number.isFinite(start)) + assert( + end != null && Number.isFinite(end) && this.end !== end, + 'invalid content-length' + ) + + this.start = start + this.end = end + } + + // We make our best to checkpoint the body for further range headers + if (this.end == null) { + const contentLength = headers['content-length'] + this.end = contentLength != null ? Number(contentLength) : null + } + + assert(Number.isFinite(this.start)) + assert( + this.end == null || Number.isFinite(this.end), + 'invalid content-length' + ) + + this.resume = resume + this.etag = headers.etag != null ? headers.etag : null + + return this.handler.onHeaders( + statusCode, + rawHeaders, + resume, + statusMessage + ) + } + + const err = new RequestRetryError('Request failed', statusCode, { + headers, + count: this.retryCount + }) + + this.abort(err) + + return false + } + + onData (chunk) { + this.start += chunk.length + + return this.handler.onData(chunk) + } + + onComplete (rawTrailers) { + this.retryCount = 0 + return this.handler.onComplete(rawTrailers) + } + + onError (err) { + if (this.aborted || isDisturbed(this.opts.body)) { + return this.handler.onError(err) + } + + this.retryOpts.retry( + err, + { + state: { counter: this.retryCount++, currentTimeout: this.retryAfter }, + opts: { retryOptions: this.retryOpts, ...this.opts } + }, + onRetry.bind(this) + ) + + function onRetry (err) { + if (err != null || this.aborted || isDisturbed(this.opts.body)) { + return this.handler.onError(err) + } + + if (this.start !== 0) { + this.opts = { + ...this.opts, + headers: { + ...this.opts.headers, + range: `bytes=${this.start}-${this.end ?? ''}` + } + } + } + + try { + this.dispatch(this.opts, this) + } catch (err) { + this.handler.onError(err) + } + } + } +} + +module.exports = RetryHandler + + +/***/ }), + +/***/ 8573: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const RedirectHandler = __nccwpck_require__(1962) +const RedirectHandler = __nccwpck_require__(9644) function createRedirectInterceptor ({ maxRedirections: defaultMaxRedirections }) { return (dispatch) => { @@ -19503,14 +19958,14 @@ module.exports = createRedirectInterceptor /***/ }), -/***/ 6744: +/***/ 3: /***/ ((__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); +const utils_1 = __nccwpck_require__(5448); // C headers var ERROR; (function (ERROR) { @@ -19788,7 +20243,7 @@ exports.SPECIAL_HEADERS = { /***/ }), -/***/ 7445: +/***/ 2516: /***/ ((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=' @@ -19796,7 +20251,7 @@ module.exports = 'AGFzbQEAAAABMAhgAX8Bf2ADf39/AX9gBH9/f38Bf2AAAGADf39/AGABfwBgAn /***/ }), -/***/ 6442: +/***/ 6390: /***/ ((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==' @@ -19804,7 +20259,7 @@ module.exports = 'AGFzbQEAAAABMAhgAX8Bf2ADf39/AX9gBH9/f38Bf2AAAGADf39/AGABfwBgAn /***/ }), -/***/ 7728: +/***/ 5448: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -19826,14 +20281,14 @@ exports.enumToMap = enumToMap; /***/ }), -/***/ 8180: +/***/ 580: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const { kClients } = __nccwpck_require__(1439) -const Agent = __nccwpck_require__(8162) +const { kClients } = __nccwpck_require__(5724) +const Agent = __nccwpck_require__(9614) const { kAgent, kMockAgentSet, @@ -19844,14 +20299,14 @@ const { 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) +} = __nccwpck_require__(4932) +const MockClient = __nccwpck_require__(4454) +const MockPool = __nccwpck_require__(4002) +const { matchValue, buildMockOptions } = __nccwpck_require__(7335) +const { InvalidArgumentError, UndiciError } = __nccwpck_require__(6330) +const Dispatcher = __nccwpck_require__(2804) +const Pluralizer = __nccwpck_require__(2326) +const PendingInterceptorsFormatter = __nccwpck_require__(9006) class FakeWeakRef { constructor (value) { @@ -20005,15 +20460,15 @@ module.exports = MockAgent /***/ }), -/***/ 624: +/***/ 4454: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; const { promisify } = __nccwpck_require__(3837) -const Client = __nccwpck_require__(8224) -const { buildMockDispatch } = __nccwpck_require__(2178) +const Client = __nccwpck_require__(2914) +const { buildMockDispatch } = __nccwpck_require__(7335) const { kDispatches, kMockAgent, @@ -20022,10 +20477,10 @@ const { kOrigin, kOriginalDispatch, kConnected -} = __nccwpck_require__(5056) -const { MockInterceptor } = __nccwpck_require__(5666) -const Symbols = __nccwpck_require__(1439) -const { InvalidArgumentError } = __nccwpck_require__(5767) +} = __nccwpck_require__(4932) +const { MockInterceptor } = __nccwpck_require__(1659) +const Symbols = __nccwpck_require__(5724) +const { InvalidArgumentError } = __nccwpck_require__(6330) /** * MockClient provides an API that extends the Client to influence the mockDispatches. @@ -20072,13 +20527,13 @@ module.exports = MockClient /***/ }), -/***/ 463: +/***/ 5603: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const { UndiciError } = __nccwpck_require__(5767) +const { UndiciError } = __nccwpck_require__(6330) class MockNotMatchedError extends UndiciError { constructor (message) { @@ -20097,13 +20552,13 @@ module.exports = { /***/ }), -/***/ 5666: +/***/ 1659: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const { getResponseData, buildKey, addMockDispatch } = __nccwpck_require__(2178) +const { getResponseData, buildKey, addMockDispatch } = __nccwpck_require__(7335) const { kDispatches, kDispatchKey, @@ -20111,9 +20566,9 @@ const { kDefaultTrailers, kContentLength, kMockDispatch -} = __nccwpck_require__(5056) -const { InvalidArgumentError } = __nccwpck_require__(5767) -const { buildURL } = __nccwpck_require__(6223) +} = __nccwpck_require__(4932) +const { InvalidArgumentError } = __nccwpck_require__(6330) +const { buildURL } = __nccwpck_require__(2423) /** * Defines the scope API for an interceptor reply @@ -20311,15 +20766,15 @@ module.exports.MockScope = MockScope /***/ }), -/***/ 3429: +/***/ 4002: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; const { promisify } = __nccwpck_require__(3837) -const Pool = __nccwpck_require__(9729) -const { buildMockDispatch } = __nccwpck_require__(2178) +const Pool = __nccwpck_require__(9944) +const { buildMockDispatch } = __nccwpck_require__(7335) const { kDispatches, kMockAgent, @@ -20328,10 +20783,10 @@ const { kOrigin, kOriginalDispatch, kConnected -} = __nccwpck_require__(5056) -const { MockInterceptor } = __nccwpck_require__(5666) -const Symbols = __nccwpck_require__(1439) -const { InvalidArgumentError } = __nccwpck_require__(5767) +} = __nccwpck_require__(4932) +const { MockInterceptor } = __nccwpck_require__(1659) +const Symbols = __nccwpck_require__(5724) +const { InvalidArgumentError } = __nccwpck_require__(6330) /** * MockPool provides an API that extends the Pool to influence the mockDispatches. @@ -20378,7 +20833,7 @@ module.exports = MockPool /***/ }), -/***/ 5056: +/***/ 4932: /***/ ((module) => { "use strict"; @@ -20409,21 +20864,21 @@ module.exports = { /***/ }), -/***/ 2178: +/***/ 7335: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const { MockNotMatchedError } = __nccwpck_require__(463) +const { MockNotMatchedError } = __nccwpck_require__(5603) const { kDispatches, kMockAgent, kOriginalDispatch, kOrigin, kGetNetConnect -} = __nccwpck_require__(5056) -const { buildURL, nop } = __nccwpck_require__(6223) +} = __nccwpck_require__(4932) +const { buildURL, nop } = __nccwpck_require__(2423) const { STATUS_CODES } = __nccwpck_require__(3685) const { types: { @@ -20768,7 +21223,7 @@ module.exports = { /***/ }), -/***/ 2524: +/***/ 9006: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -20816,7 +21271,7 @@ module.exports = class PendingInterceptorsFormatter { /***/ }), -/***/ 4615: +/***/ 2326: /***/ ((module) => { "use strict"; @@ -20853,7 +21308,7 @@ module.exports = class Pluralizer { /***/ }), -/***/ 3408: +/***/ 6998: /***/ ((module) => { "use strict"; @@ -20978,16 +21433,16 @@ module.exports = class FixedQueue { /***/ }), -/***/ 1273: +/***/ 8324: /***/ ((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 DispatcherBase = __nccwpck_require__(996) +const FixedQueue = __nccwpck_require__(6998) +const { kConnected, kSize, kRunning, kPending, kQueued, kBusy, kFree, kUrl, kClose, kDestroy, kDispatch } = __nccwpck_require__(5724) +const PoolStats = __nccwpck_require__(4822) const kClients = Symbol('clients') const kNeedDrain = Symbol('needDrain') @@ -21180,10 +21635,10 @@ module.exports = { /***/ }), -/***/ 3860: +/***/ 4822: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { -const { kFree, kConnected, kPending, kQueued, kRunning, kSize } = __nccwpck_require__(1439) +const { kFree, kConnected, kPending, kQueued, kRunning, kSize } = __nccwpck_require__(5724) const kPool = Symbol('pool') class PoolStats { @@ -21221,7 +21676,7 @@ module.exports = PoolStats /***/ }), -/***/ 9729: +/***/ 9944: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -21233,14 +21688,14 @@ const { kNeedDrain, kAddClient, kGetDispatcher -} = __nccwpck_require__(1273) -const Client = __nccwpck_require__(8224) +} = __nccwpck_require__(8324) +const Client = __nccwpck_require__(2914) const { InvalidArgumentError -} = __nccwpck_require__(5767) -const util = __nccwpck_require__(6223) -const { kUrl, kInterceptors } = __nccwpck_require__(1439) -const buildConnector = __nccwpck_require__(3311) +} = __nccwpck_require__(6330) +const util = __nccwpck_require__(2423) +const { kUrl, kInterceptors } = __nccwpck_require__(5724) +const buildConnector = __nccwpck_require__(8074) const kOptions = Symbol('options') const kConnections = Symbol('connections') @@ -21323,19 +21778,19 @@ module.exports = Pool /***/ }), -/***/ 2498: +/***/ 4080: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const { kProxy, kClose, kDestroy, kInterceptors } = __nccwpck_require__(1439) +const { kProxy, kClose, kDestroy, kInterceptors } = __nccwpck_require__(5724) 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 Agent = __nccwpck_require__(9614) +const Pool = __nccwpck_require__(9944) +const DispatcherBase = __nccwpck_require__(996) +const { InvalidArgumentError, RequestAbortedError } = __nccwpck_require__(6330) +const buildConnector = __nccwpck_require__(8074) const kAgent = Symbol('proxy agent') const kClient = Symbol('proxy client') @@ -21394,6 +21849,9 @@ class ProxyAgent extends DispatcherBase { this[kProxyTls] = opts.proxyTls this[kProxyHeaders] = opts.headers || {} + const resolvedUrl = new URL(opts.uri) + const { origin, port, host, username, password } = resolvedUrl + if (opts.auth && opts.token) { throw new InvalidArgumentError('opts.auth cannot be used in combination with opts.token') } else if (opts.auth) { @@ -21401,11 +21859,10 @@ class ProxyAgent extends DispatcherBase { this[kProxyHeaders]['proxy-authorization'] = `Basic ${opts.auth}` } else if (opts.token) { this[kProxyHeaders]['proxy-authorization'] = opts.token + } else if (username && password) { + this[kProxyHeaders]['proxy-authorization'] = `Basic ${Buffer.from(`${decodeURIComponent(username)}:${decodeURIComponent(password)}`).toString('base64')}` } - 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 }) @@ -21429,7 +21886,7 @@ class ProxyAgent extends DispatcherBase { }) if (statusCode !== 200) { socket.on('error', () => {}).destroy() - callback(new RequestAbortedError('Proxy response !== 200 when HTTP Tunneling')) + callback(new RequestAbortedError(`Proxy response (${statusCode}) !== 200 when HTTP Tunneling`)) } if (opts.protocol !== 'https:') { callback(null, socket) @@ -21518,7 +21975,7 @@ module.exports = ProxyAgent /***/ }), -/***/ 8581: +/***/ 5534: /***/ ((module) => { "use strict"; @@ -21623,27 +22080,27 @@ module.exports = { /***/ }), -/***/ 7610: +/***/ 9489: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; const diagnosticsChannel = __nccwpck_require__(7643) -const { uid, states } = __nccwpck_require__(4009) +const { uid, states } = __nccwpck_require__(6927) 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) +} = __nccwpck_require__(3555) +const { fireEvent, failWebsocketConnection } = __nccwpck_require__(3542) +const { CloseEvent } = __nccwpck_require__(7973) +const { makeRequest } = __nccwpck_require__(3437) +const { fetching } = __nccwpck_require__(7628) +const { Headers } = __nccwpck_require__(2836) +const { getGlobalDispatcher } = __nccwpck_require__(6835) +const { kHeadersList } = __nccwpck_require__(5724) const channels = {} channels.open = diagnosticsChannel.channel('undici:websocket:open') @@ -21922,7 +22379,7 @@ module.exports = { /***/ }), -/***/ 4009: +/***/ 6927: /***/ ((module) => { "use strict"; @@ -21981,14 +22438,14 @@ module.exports = { /***/ }), -/***/ 3458: +/***/ 7973: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const { webidl } = __nccwpck_require__(5337) -const { kEnumerableProperty } = __nccwpck_require__(6223) +const { webidl } = __nccwpck_require__(194) +const { kEnumerableProperty } = __nccwpck_require__(2423) const { MessagePort } = __nccwpck_require__(1267) /** @@ -22292,13 +22749,13 @@ module.exports = { /***/ }), -/***/ 9262: +/***/ 6772: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const { maxUnsigned16Bit } = __nccwpck_require__(4009) +const { maxUnsigned16Bit } = __nccwpck_require__(6927) /** @type {import('crypto')} */ let crypto @@ -22373,7 +22830,7 @@ module.exports = { /***/ }), -/***/ 1213: +/***/ 1579: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -22381,10 +22838,10 @@ module.exports = { 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) +const { parserStates, opcodes, states, emptyBuffer } = __nccwpck_require__(6927) +const { kReadyState, kSentClose, kResponse, kReceivedClose } = __nccwpck_require__(3555) +const { isValidStatusCode, failWebsocketConnection, websocketMessageReceived } = __nccwpck_require__(3542) +const { WebsocketFrameSend } = __nccwpck_require__(6772) // This code was influenced by ws released under the MIT license. // Copyright (c) 2011 Einar Otto Stangvik @@ -22725,7 +23182,7 @@ module.exports = { /***/ }), -/***/ 4295: +/***/ 3555: /***/ ((module) => { "use strict"; @@ -22745,15 +23202,15 @@ module.exports = { /***/ }), -/***/ 1310: +/***/ 3542: /***/ ((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) +const { kReadyState, kController, kResponse, kBinaryType, kWebSocketURL } = __nccwpck_require__(3555) +const { states, opcodes } = __nccwpck_require__(6927) +const { MessageEvent, ErrorEvent } = __nccwpck_require__(7973) /* globals Blob */ @@ -22953,17 +23410,17 @@ module.exports = { /***/ }), -/***/ 6624: +/***/ 7183: /***/ ((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 { webidl } = __nccwpck_require__(194) +const { DOMException } = __nccwpck_require__(4091) +const { URLSerializer } = __nccwpck_require__(6515) +const { getGlobalOrigin } = __nccwpck_require__(4767) +const { staticPropertyDescriptors, states, opcodes, emptyBuffer } = __nccwpck_require__(6927) const { kWebSocketURL, kReadyState, @@ -22972,13 +23429,13 @@ const { 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) +} = __nccwpck_require__(3555) +const { isEstablished, isClosing, isValidSubprotocol, failWebsocketConnection, fireEvent } = __nccwpck_require__(3542) +const { establishWebSocketConnection } = __nccwpck_require__(9489) +const { WebsocketFrameSend } = __nccwpck_require__(6772) +const { ByteParser } = __nccwpck_require__(1579) +const { kEnumerableProperty, isBlobLike } = __nccwpck_require__(2423) +const { getGlobalDispatcher } = __nccwpck_require__(6835) const { types } = __nccwpck_require__(3837) let experimentalWarned = false @@ -23602,7 +24059,7 @@ module.exports = { /***/ }), -/***/ 8860: +/***/ 8689: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -23666,29 +24123,29 @@ Object.defineProperty(exports, "parse", ({ } })); -var _v = _interopRequireDefault(__nccwpck_require__(2078)); +var _v = _interopRequireDefault(__nccwpck_require__(4333)); -var _v2 = _interopRequireDefault(__nccwpck_require__(7788)); +var _v2 = _interopRequireDefault(__nccwpck_require__(3223)); -var _v3 = _interopRequireDefault(__nccwpck_require__(4205)); +var _v3 = _interopRequireDefault(__nccwpck_require__(3166)); -var _v4 = _interopRequireDefault(__nccwpck_require__(2795)); +var _v4 = _interopRequireDefault(__nccwpck_require__(3828)); -var _nil = _interopRequireDefault(__nccwpck_require__(2162)); +var _nil = _interopRequireDefault(__nccwpck_require__(4956)); -var _version = _interopRequireDefault(__nccwpck_require__(5315)); +var _version = _interopRequireDefault(__nccwpck_require__(1564)); -var _validate = _interopRequireDefault(__nccwpck_require__(6192)); +var _validate = _interopRequireDefault(__nccwpck_require__(7368)); -var _stringify = _interopRequireDefault(__nccwpck_require__(5354)); +var _stringify = _interopRequireDefault(__nccwpck_require__(2157)); -var _parse = _interopRequireDefault(__nccwpck_require__(861)); +var _parse = _interopRequireDefault(__nccwpck_require__(8659)); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /***/ }), -/***/ 1755: +/***/ 4919: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -23718,7 +24175,7 @@ exports["default"] = _default; /***/ }), -/***/ 2162: +/***/ 4956: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -23733,7 +24190,7 @@ exports["default"] = _default; /***/ }), -/***/ 861: +/***/ 8659: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -23744,7 +24201,7 @@ Object.defineProperty(exports, "__esModule", ({ })); exports["default"] = void 0; -var _validate = _interopRequireDefault(__nccwpck_require__(6192)); +var _validate = _interopRequireDefault(__nccwpck_require__(7368)); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -23785,7 +24242,7 @@ exports["default"] = _default; /***/ }), -/***/ 4003: +/***/ 5872: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -23800,7 +24257,7 @@ exports["default"] = _default; /***/ }), -/***/ 8795: +/***/ 7931: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -23831,7 +24288,7 @@ function rng() { /***/ }), -/***/ 3899: +/***/ 3445: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -23861,7 +24318,7 @@ exports["default"] = _default; /***/ }), -/***/ 5354: +/***/ 2157: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -23872,7 +24329,7 @@ Object.defineProperty(exports, "__esModule", ({ })); exports["default"] = void 0; -var _validate = _interopRequireDefault(__nccwpck_require__(6192)); +var _validate = _interopRequireDefault(__nccwpck_require__(7368)); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -23907,7 +24364,7 @@ exports["default"] = _default; /***/ }), -/***/ 2078: +/***/ 4333: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -23918,9 +24375,9 @@ Object.defineProperty(exports, "__esModule", ({ })); exports["default"] = void 0; -var _rng = _interopRequireDefault(__nccwpck_require__(8795)); +var _rng = _interopRequireDefault(__nccwpck_require__(7931)); -var _stringify = _interopRequireDefault(__nccwpck_require__(5354)); +var _stringify = _interopRequireDefault(__nccwpck_require__(2157)); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -24021,7 +24478,7 @@ exports["default"] = _default; /***/ }), -/***/ 7788: +/***/ 3223: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -24032,9 +24489,9 @@ Object.defineProperty(exports, "__esModule", ({ })); exports["default"] = void 0; -var _v = _interopRequireDefault(__nccwpck_require__(9629)); +var _v = _interopRequireDefault(__nccwpck_require__(1892)); -var _md = _interopRequireDefault(__nccwpck_require__(1755)); +var _md = _interopRequireDefault(__nccwpck_require__(4919)); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -24044,7 +24501,7 @@ exports["default"] = _default; /***/ }), -/***/ 9629: +/***/ 1892: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -24056,9 +24513,9 @@ Object.defineProperty(exports, "__esModule", ({ exports["default"] = _default; exports.URL = exports.DNS = void 0; -var _stringify = _interopRequireDefault(__nccwpck_require__(5354)); +var _stringify = _interopRequireDefault(__nccwpck_require__(2157)); -var _parse = _interopRequireDefault(__nccwpck_require__(861)); +var _parse = _interopRequireDefault(__nccwpck_require__(8659)); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -24129,7 +24586,7 @@ function _default(name, version, hashfunc) { /***/ }), -/***/ 4205: +/***/ 3166: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -24140,9 +24597,9 @@ Object.defineProperty(exports, "__esModule", ({ })); exports["default"] = void 0; -var _rng = _interopRequireDefault(__nccwpck_require__(8795)); +var _rng = _interopRequireDefault(__nccwpck_require__(7931)); -var _stringify = _interopRequireDefault(__nccwpck_require__(5354)); +var _stringify = _interopRequireDefault(__nccwpck_require__(2157)); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -24173,7 +24630,7 @@ exports["default"] = _default; /***/ }), -/***/ 2795: +/***/ 3828: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -24184,9 +24641,9 @@ Object.defineProperty(exports, "__esModule", ({ })); exports["default"] = void 0; -var _v = _interopRequireDefault(__nccwpck_require__(9629)); +var _v = _interopRequireDefault(__nccwpck_require__(1892)); -var _sha = _interopRequireDefault(__nccwpck_require__(3899)); +var _sha = _interopRequireDefault(__nccwpck_require__(3445)); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -24196,7 +24653,7 @@ exports["default"] = _default; /***/ }), -/***/ 6192: +/***/ 7368: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -24207,7 +24664,7 @@ Object.defineProperty(exports, "__esModule", ({ })); exports["default"] = void 0; -var _regex = _interopRequireDefault(__nccwpck_require__(4003)); +var _regex = _interopRequireDefault(__nccwpck_require__(5872)); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -24220,7 +24677,7 @@ exports["default"] = _default; /***/ }), -/***/ 5315: +/***/ 1564: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -24231,7 +24688,7 @@ Object.defineProperty(exports, "__esModule", ({ })); exports["default"] = void 0; -var _validate = _interopRequireDefault(__nccwpck_require__(6192)); +var _validate = _interopRequireDefault(__nccwpck_require__(7368)); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -24472,7 +24929,7 @@ module.exports = require("zlib"); /***/ }), -/***/ 3186: +/***/ 7464: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -24481,10 +24938,10 @@ module.exports = require("zlib"); const WritableStream = (__nccwpck_require__(4492).Writable) const inherits = (__nccwpck_require__(7261).inherits) -const StreamSearch = __nccwpck_require__(3331) +const StreamSearch = __nccwpck_require__(9477) -const PartStream = __nccwpck_require__(5785) -const HeaderParser = __nccwpck_require__(8981) +const PartStream = __nccwpck_require__(8258) +const HeaderParser = __nccwpck_require__(4874) const DASH = 45 const B_ONEDASH = Buffer.from('-') @@ -24687,7 +25144,7 @@ module.exports = Dicer /***/ }), -/***/ 8981: +/***/ 4874: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -24695,9 +25152,9 @@ module.exports = Dicer const EventEmitter = (__nccwpck_require__(5673).EventEmitter) const inherits = (__nccwpck_require__(7261).inherits) -const getLimit = __nccwpck_require__(4323) +const getLimit = __nccwpck_require__(9281) -const StreamSearch = __nccwpck_require__(3331) +const StreamSearch = __nccwpck_require__(9477) const B_DCRLF = Buffer.from('\r\n\r\n') const RE_CRLF = /\r\n/g @@ -24795,7 +25252,7 @@ module.exports = HeaderParser /***/ }), -/***/ 5785: +/***/ 8258: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -24816,7 +25273,7 @@ module.exports = PartStream /***/ }), -/***/ 3331: +/***/ 9477: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -25052,7 +25509,7 @@ module.exports = SBMH /***/ }), -/***/ 1702: +/***/ 9452: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -25060,11 +25517,11 @@ module.exports = SBMH const WritableStream = (__nccwpck_require__(4492).Writable) const { inherits } = __nccwpck_require__(7261) -const Dicer = __nccwpck_require__(3186) +const Dicer = __nccwpck_require__(7464) -const MultipartParser = __nccwpck_require__(7435) -const UrlencodedParser = __nccwpck_require__(8604) -const parseParams = __nccwpck_require__(2693) +const MultipartParser = __nccwpck_require__(5409) +const UrlencodedParser = __nccwpck_require__(9232) +const parseParams = __nccwpck_require__(9741) function Busboy (opts) { if (!(this instanceof Busboy)) { return new Busboy(opts) } @@ -25145,7 +25602,7 @@ module.exports.Dicer = Dicer /***/ }), -/***/ 7435: +/***/ 5409: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; @@ -25161,12 +25618,12 @@ module.exports.Dicer = Dicer const { Readable } = __nccwpck_require__(4492) const { inherits } = __nccwpck_require__(7261) -const Dicer = __nccwpck_require__(3186) +const Dicer = __nccwpck_require__(7464) -const parseParams = __nccwpck_require__(2693) -const decodeText = __nccwpck_require__(9464) -const basename = __nccwpck_require__(1628) -const getLimit = __nccwpck_require__(4323) +const parseParams = __nccwpck_require__(9741) +const decodeText = __nccwpck_require__(6897) +const basename = __nccwpck_require__(2149) +const getLimit = __nccwpck_require__(9281) const RE_BOUNDARY = /^boundary$/i const RE_FIELD = /^form-data$/i @@ -25459,15 +25916,15 @@ module.exports = Multipart /***/ }), -/***/ 8604: +/***/ 9232: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -const Decoder = __nccwpck_require__(8660) -const decodeText = __nccwpck_require__(9464) -const getLimit = __nccwpck_require__(4323) +const Decoder = __nccwpck_require__(8698) +const decodeText = __nccwpck_require__(6897) +const getLimit = __nccwpck_require__(9281) const RE_CHARSET = /^charset$/i @@ -25657,7 +26114,7 @@ module.exports = UrlEncoded /***/ }), -/***/ 8660: +/***/ 8698: /***/ ((module) => { "use strict"; @@ -25719,7 +26176,7 @@ module.exports = Decoder /***/ }), -/***/ 1628: +/***/ 2149: /***/ ((module) => { "use strict"; @@ -25741,7 +26198,7 @@ module.exports = function basename (path) { /***/ }), -/***/ 9464: +/***/ 6897: /***/ (function(module) { "use strict"; @@ -25863,7 +26320,7 @@ module.exports = decodeText /***/ }), -/***/ 4323: +/***/ 9281: /***/ ((module) => { "use strict"; @@ -25887,14 +26344,14 @@ module.exports = function getLimit (limits, name, defaultLimit) { /***/ }), -/***/ 2693: +/***/ 9741: /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; /* eslint-disable object-property-newline */ -const decodeText = __nccwpck_require__(9464) +const decodeText = __nccwpck_require__(6897) const RE_ENCODED = /%[a-fA-F0-9][a-fA-F0-9]/g @@ -26139,10 +26596,17 @@ const archList = [{ arch: x86_64, runner: 'ubuntu-latest', docker_tag: 'manylinux2014_x86_64-plugins-deps', + asset_tag: 'manylinux2014_x86_64', }, { arch: aarch64, - runner: 'linux-arm64', + runner: 'linux-arm64-v2', docker_tag: 'manylinux2014_aarch64-plugins-deps', + asset_tag: 'manylinux2014_aarch64', +}, { + arch: aarch64, + runner: 'linux-arm64-v2', + docker_tag: 'manylinux_2_28_aarch64-plugins-deps', + asset_tag: 'manylinux_2_28_aarch64', }]; const pluginList = [{ @@ -26162,6 +26626,60 @@ const pluginList = [{ options: '-DWASMEDGE_PLUGIN_WASI_NN_BACKEND=PyTorch', archList: [x86_64], }], +}, { + name: 'wasm_bpf', + bin: 'libwasmedgePluginWasmBpf.so', + testBin: 'wasmBpfTests', + options: '-DWASMEDGE_PLUGIN_WASM_BPF=ON -DWASMEDGE_PLUGIN_WASM_BPF_BUILD_LIBBPF_WITH_PKG_CONF=OFF', + archList: [x86_64], +}, { + name: 'wasi_crypto', + bin: 'libwasmedgePluginWasiCrypto.so', + testBin: 'wasiCryptoTests', + options: '-DWASMEDGE_PLUGIN_WASI_CRYPTO=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasi_logging', + bin: 'libwasmedgePluginWasiLogging.so', + testBin: 'wasiLoggingTests', + options: '-DWASMEDGE_PLUGIN_WASI_LOGGING=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasmedge_process', + bin: 'libwasmedgePluginWasmEdgeProcess.so', + testBin: 'wasmedgeProcessTests', + options: '-DWASMEDGE_PLUGIN_PROCESS=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasmedge_tensorflow', + bin: 'libwasmedgePluginWasmEdgeTensorflow.so', + testBin: 'wasmedgeTensorflowTests', + options: '-DWASMEDGE_PLUGIN_TENSORFLOW=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasmedge_tensorflowlite', + bin: 'libwasmedgePluginWasmEdgeTensorflowLite.so', + testBin: 'wasmedgeTensorflowLiteTests', + options: '-DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasmedge_image', + bin: 'libwasmedgePluginWasmEdgeImage.so', + testBin: 'wasmedgeImageTests', + options: '-DWASMEDGE_PLUGIN_IMAGE=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasmedge_opencvmini', + bin: 'libwasmedgePluginWasmEdgeOpenCVMini.so', + testBin: 'wasmedgeOpencvminiTests', + options: '-DWASMEDGE_PLUGIN_OPENCVMINI=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasmedge_ffmpeg', + bin: 'libwasmedgePluginWasmEdgeFFmpeg.so', + testBin: 'wasmedgeFFmpegTests', + options: '-DWASMEDGE_PLUGIN_FFMPEG=ON', + archList: [aarch64, x86_64], }]; let expandVariables = () => { @@ -26192,7 +26710,7 @@ let expandVariables = () => { return ret; }; -const core = __nccwpck_require__(2619); +const core = __nccwpck_require__(5662); try { output = JSON.stringify(expandVariables()); diff --git a/.github/actions/expand-variables/main.js b/.github/actions/expand-variables/main.js index 5a393dedb59b..216fb2e65581 100644 --- a/.github/actions/expand-variables/main.js +++ b/.github/actions/expand-variables/main.js @@ -5,10 +5,17 @@ const archList = [{ arch: x86_64, runner: 'ubuntu-latest', docker_tag: 'manylinux2014_x86_64-plugins-deps', + asset_tag: 'manylinux2014_x86_64', }, { arch: aarch64, - runner: 'linux-arm64', + runner: 'linux-arm64-v2', docker_tag: 'manylinux2014_aarch64-plugins-deps', + asset_tag: 'manylinux2014_aarch64', +}, { + arch: aarch64, + runner: 'linux-arm64-v2', + docker_tag: 'manylinux_2_28_aarch64-plugins-deps', + asset_tag: 'manylinux_2_28_aarch64', }]; const pluginList = [{ @@ -28,6 +35,60 @@ const pluginList = [{ options: '-DWASMEDGE_PLUGIN_WASI_NN_BACKEND=PyTorch', archList: [x86_64], }], +}, { + name: 'wasm_bpf', + bin: 'libwasmedgePluginWasmBpf.so', + testBin: 'wasmBpfTests', + options: '-DWASMEDGE_PLUGIN_WASM_BPF=ON -DWASMEDGE_PLUGIN_WASM_BPF_BUILD_LIBBPF_WITH_PKG_CONF=OFF', + archList: [x86_64], +}, { + name: 'wasi_crypto', + bin: 'libwasmedgePluginWasiCrypto.so', + testBin: 'wasiCryptoTests', + options: '-DWASMEDGE_PLUGIN_WASI_CRYPTO=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasi_logging', + bin: 'libwasmedgePluginWasiLogging.so', + testBin: 'wasiLoggingTests', + options: '-DWASMEDGE_PLUGIN_WASI_LOGGING=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasmedge_process', + bin: 'libwasmedgePluginWasmEdgeProcess.so', + testBin: 'wasmedgeProcessTests', + options: '-DWASMEDGE_PLUGIN_PROCESS=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasmedge_tensorflow', + bin: 'libwasmedgePluginWasmEdgeTensorflow.so', + testBin: 'wasmedgeTensorflowTests', + options: '-DWASMEDGE_PLUGIN_TENSORFLOW=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasmedge_tensorflowlite', + bin: 'libwasmedgePluginWasmEdgeTensorflowLite.so', + testBin: 'wasmedgeTensorflowLiteTests', + options: '-DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasmedge_image', + bin: 'libwasmedgePluginWasmEdgeImage.so', + testBin: 'wasmedgeImageTests', + options: '-DWASMEDGE_PLUGIN_IMAGE=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasmedge_opencvmini', + bin: 'libwasmedgePluginWasmEdgeOpenCVMini.so', + testBin: 'wasmedgeOpencvminiTests', + options: '-DWASMEDGE_PLUGIN_OPENCVMINI=ON', + archList: [aarch64, x86_64], +}, { + name: 'wasmedge_ffmpeg', + bin: 'libwasmedgePluginWasmEdgeFFmpeg.so', + testBin: 'wasmedgeFFmpegTests', + options: '-DWASMEDGE_PLUGIN_FFMPEG=ON', + archList: [aarch64, x86_64], }]; let expandVariables = () => { diff --git a/.github/actions/expand-variables/package-lock.json b/.github/actions/expand-variables/package-lock.json index 0ce55136525c..0fc98f445bfb 100644 --- a/.github/actions/expand-variables/package-lock.json +++ b/.github/actions/expand-variables/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@actions/core": "^1.10.1" + "@actions/core": "^1.10.1", + "@actions/github": "^6.0.0" } }, "node_modules/@actions/core": { @@ -21,6 +22,17 @@ "uuid": "^8.3.2" } }, + "node_modules/@actions/github": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@actions/github/-/github-6.0.0.tgz", + "integrity": "sha512-alScpSVnYmjNEXboZjarjukQEzgCRmjMv6Xj47fsdnqGS73bjJNDpiiXmp8jr0UZLdUB6d9jW63IcmddUP+l0g==", + "dependencies": { + "@actions/http-client": "^2.2.0", + "@octokit/core": "^5.0.1", + "@octokit/plugin-paginate-rest": "^9.0.0", + "@octokit/plugin-rest-endpoint-methods": "^10.0.0" + } + }, "node_modules/@actions/http-client": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.0.tgz", @@ -38,6 +50,142 @@ "node": ">=14" } }, + "node_modules/@octokit/auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.1.0.tgz", + "integrity": "sha512-BDa2VAMLSh3otEiaMJ/3Y36GU4qf6GI+VivQ/P41NC6GHcdxpKlqV0ikSZ5gdQsmS3ojXeRx5vasgNTinF0Q4g==", + "dependencies": { + "@octokit/auth-token": "^4.0.0", + "@octokit/graphql": "^7.0.0", + "@octokit/request": "^8.0.2", + "@octokit/request-error": "^5.0.0", + "@octokit/types": "^12.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.4.tgz", + "integrity": "sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==", + "dependencies": { + "@octokit/types": "^12.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.0.2.tgz", + "integrity": "sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==", + "dependencies": { + "@octokit/request": "^8.0.1", + "@octokit/types": "^12.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", + "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.1.tgz", + "integrity": "sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw==", + "dependencies": { + "@octokit/types": "^12.6.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz", + "integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==", + "dependencies": { + "@octokit/types": "^12.6.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/request": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.2.0.tgz", + "integrity": "sha512-exPif6x5uwLqv1N1irkLG1zZNJkOtj8bZxuVHd71U5Ftuxf2wGNvAJyNBcPbPC+EBzwYEbBDdSFb8EPcjpYxPQ==", + "dependencies": { + "@octokit/endpoint": "^9.0.0", + "@octokit/request-error": "^5.0.0", + "@octokit/types": "^12.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz", + "integrity": "sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==", + "dependencies": { + "@octokit/types": "^12.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", + "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", + "dependencies": { + "@octokit/openapi-types": "^20.0.0" + } + }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -47,9 +195,9 @@ } }, "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==", + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -57,6 +205,11 @@ "node": ">=14.0" } }, + "node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==" + }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -64,6 +217,11 @@ "bin": { "uuid": "dist/bin/uuid" } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" } } } diff --git a/.github/actions/expand-variables/package.json b/.github/actions/expand-variables/package.json index 5391a153491d..d357eecb171b 100644 --- a/.github/actions/expand-variables/package.json +++ b/.github/actions/expand-variables/package.json @@ -10,6 +10,7 @@ "author": "", "license": "ISC", "dependencies": { - "@actions/core": "^1.10.1" + "@actions/core": "^1.10.1", + "@actions/github": "^6.0.0" } } diff --git a/.github/workflows/IWYU_scan.yml b/.github/workflows/IWYU_scan.yml index b026b0b514a6..26824b46c1fe 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 .. - - - uses: actions/checkout@v3 + 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@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,21 +112,38 @@ 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.21.zip + unzip 0.21.zip + patch -p1 -d include-what-you-use-0.21 <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.21 + 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: diff --git a/.github/workflows/README.md b/.github/workflows/README.md index e3be092b39da..d1ad924fcb16 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -38,7 +38,7 @@ flowchart LR "docker_tag": "manylinux2014_x86_64" }, { - "runner": "linux-arm64", + "runner": "linux-arm64-v2", "docker_tag": "manylinux2014_aarch64" } ] diff --git a/.github/workflows/bindings-java.yml b/.github/workflows/bindings-java.yml index b6ec7648351d..715e06eb6208 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 diff --git a/.github/workflows/build-extensions.yml b/.github/workflows/build-extensions.yml index 060c8b60db9e..4197227fa1d0 100644 --- a/.github/workflows/build-extensions.yml +++ b/.github/workflows/build-extensions.yml @@ -40,26 +40,22 @@ on: - "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 +71,8 @@ jobs: # Due to the dependencies and exclusions of WASI-NN, build them saperately. build_ubuntu_wasi_nn: + permissions: + contents: write strategy: matrix: include: @@ -99,11 +97,11 @@ jobs: OPENVINO_YEAR: "2023" 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 @@ -123,7 +121,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:" @@ -175,7 +173,68 @@ jobs: name: WasmEdge-plugin-wasi_nn-ggml-${{ needs.get_version.outputs.version }}-ubuntu22.04-${{ matrix.compiler }}.tar.gz path: plugin_wasi_nn-ggml.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 + 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: 19041 + - 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 + 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" + 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,18 +251,18 @@ 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_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 -DWASMEDGE_PLUGIN_FFMPEG=ON + tar_names: wasi_crypto wasi_logging wasmedge_process wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasm_bpf wasmedge_opencvmini wasmedge_zlib wasmedge_ffmpeg + test_bins: wasiCryptoTests wasiLoggingTests wasmedgeProcessTests wasmedgeTensorflowTests wasmedgeTensorflowLiteTests wasmedgeImageTests wasmBpfTests wasmedgeOpencvminiTests wasmedgeZlibTests wasmedgeFFmpegTests + output_bins: libwasmedgePluginWasiCrypto.so libwasmedgePluginWasiLogging.so libwasmedgePluginWasmEdgeProcess.so libwasmedgePluginWasmEdgeTensorflow.so libwasmedgePluginWasmEdgeTensorflowLite.so libwasmedgePluginWasmEdgeImage.so libwasmedgePluginWasmBpf.so libwasmedgePluginWasmEdgeOpenCVMini.so libwasmedgePluginWasmEdgeZlib.so libwasmedgePluginWasmEdgeFFmpeg.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 @@ -211,15 +270,20 @@ jobs: apt update apt install -y libssl-dev apt install -y libelf-dev zlib1g-dev pkg-config - apt install -y clang llvm + 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 +292,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++ )); @@ -293,144 +358,24 @@ 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 - # Due to the dependencies and exclusions of WASI-NN, build them saperately. - build_wasinn_manylinux: - name: WASI-NN (manylinux, g++, Release) + 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_manylinux: - 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 }} - env: - 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 - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Build and install dependencies - 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 - 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 - for (( i=0; i<${#testbin_array[@]}; i++ )); - do - echo "Building ${testbin_array[$i]} :" - cmake --build build --target ${testbin_array[$i]} - 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 - 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 }}}) - 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 - 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 - build_macos: + permissions: + contents: write strategy: matrix: include: @@ -441,7 +386,7 @@ jobs: 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 build_type: Release @@ -451,28 +396,29 @@ 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_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_WASI_LOGGING=ON -DWASMEDGE_PLUGIN_TENSORFLOW=ON -DWASMEDGE_PLUGIN_TENSORFLOWLITE=ON -DWASMEDGE_PLUGIN_IMAGE=ON -DWASMEDGE_PLUGIN_OPENCVMINI=ON -DWASMEDGE_PLUGIN_FFMPEG=ON + tar_names: wasi_crypto wasi_logging wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasmedge_opencvmini wasmedge_ffmpeg + test_bins: wasiCryptoTests wasiLoggingTests wasmedgeTensorflowTests wasmedgeTensorflowLiteTests wasmedgeImageTests wasmedgeOpencvminiTests wasmedgeFFmpegTests + output_bins: libwasmedgePluginWasiCrypto.dylib libwasmedgePluginWasiLogging.dylib libwasmedgePluginWasmEdgeTensorflow.dylib libwasmedgePluginWasmEdgeTensorflowLite.dylib libwasmedgePluginWasmEdgeImage.dylib libwasmedgePluginWasmEdgeOpenCVMini.dylib libwasmedgePluginWasmEdgeFFmpeg.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]} :" @@ -537,3 +483,8 @@ 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 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index abb87318214f..dd980a7981c1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,19 +40,15 @@ on: - "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 @@ -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,6 +79,8 @@ 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 @@ -89,16 +89,31 @@ jobs: 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'}]" - build_on_manylinux_2014: + 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'}, + {'name':'manylinux2014 aarch64','runner':'linux-arm64-v2','docker_tag':'manylinux2014_aarch64'}]" + + 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'}, + {'name':'manylinux_2_28 aarch64','runner':'linux-arm64-v2','docker_tag':'manylinux_2_28_aarch64'}]" 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,9 +130,12 @@ 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}, @@ -126,6 +146,8 @@ jobs: {'name':'ubuntu-22.04-coverage','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 +155,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 +164,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,6 +173,8 @@ 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 diff --git a/.github/workflows/build_for_openwrt.yml b/.github/workflows/build_for_openwrt.yml index 832f06d753f3..5c370f2f57c2 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 diff --git a/.github/workflows/build_for_riscv.yml b/.github/workflows/build_for_riscv.yml index ab069318ce1d..8e32531ebe1e 100644 --- a/.github/workflows/build_for_riscv.yml +++ b/.github/workflows/build_for_riscv.yml @@ -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 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..4ec32cb71f2e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -50,16 +50,40 @@ jobs: echo "docker_image=$DOCKER_IMAGE" >> $GITHUB_OUTPUT echo "created=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT + bake-base-images: + name: Bake `ci-image-base` + needs: [prep] + runs-on: ubuntu-latest + 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@v4 + with: + files: utils/docker/docker-bake.ci-image-base + push: ${{ github.event_name != 'pull_request' }} + build-docker-images: name: build-docker-images - needs: [prep] + needs: [prep, bake-base-images] 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,23 +95,6 @@ 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: @@ -145,7 +152,7 @@ jobs: uses: docker/build-push-action@v5 with: build-args: BASE=wasmedge/wasmedge:ubuntu-build-clang - context: ./utils/docker + context: ./utils file: ./utils/docker/Dockerfile.build-plugins-deps platforms: linux/amd64 push: ${{ github.event_name != 'pull_request' }} @@ -163,7 +170,7 @@ jobs: uses: docker/build-push-action@v5 with: build-args: BASE=wasmedge/wasmedge:ubuntu-build-gcc - context: ./utils/docker + context: ./utils file: ./utils/docker/Dockerfile.build-plugins-deps platforms: linux/amd64 push: ${{ github.event_name != 'pull_request' }} @@ -195,16 +202,48 @@ jobs: org.opencontainers.image.created=${{ needs.prep.outputs.created }} org.opencontainers.image.revision=${{ github.sha }} - build-manylinux2014_x86_64: - name: build-manylinux2014_x86_64 - runs-on: ubuntu-latest - needs: [prep] + build-manylinux-docker-images: + needs: [prep, bake-base-images] + strategy: + fail-fast: false + matrix: + include: + - name: manylinux2014 x86_64 + docker_tag: manylinux2014_x86_64 + dockerfile: utils/docker/Dockerfile.manylinux2014_x86_64 + dockerfile_plugin: utils/docker/Dockerfile.manylinux2014-build-plugins-deps + target_platforms: linux/amd64 + host_runner: ubuntu-latest + host_container: wasmedge/wasmedge:ci-image-base + - name: manylinux_2_28 x86_64 + docker_tag: manylinux_2_28_x86_64 + dockerfile: utils/docker/Dockerfile.manylinux_2_28_x86_64 + dockerfile_plugin: utils/docker/Dockerfile.manylinux_2_28-build-plugins-deps + target_platforms: linux/amd64 + host_runner: ubuntu-latest + host_container: wasmedge/wasmedge:ci-image-base + - name: manylinux2014 aarch64 + docker_tag: manylinux2014_aarch64 + dockerfile: utils/docker/Dockerfile.manylinux2014_aarch64 + dockerfile_plugin: utils/docker/Dockerfile.manylinux2014-build-plugins-deps + target_platforms: linux/arm64 + host_runner: linux-arm64-v2 + host_container: wasmedge/wasmedge:ci-image-base_aarch64 + - name: manylinux_2_28 aarch64 + docker_tag: manylinux_2_28_aarch64 + dockerfile: utils/docker/Dockerfile.manylinux_2_28_aarch64 + dockerfile_plugin: utils/docker/Dockerfile.manylinux_2_28-build-plugins-deps + target_platforms: linux/arm64 + host_runner: linux-arm64-v2 + host_container: wasmedge/wasmedge:ci-image-base_aarch64 + name: build ${{ matrix.name }} + runs-on: ${{ matrix.host_runner }} container: - image: wasmedge/wasmedge:ci-image-base + image: ${{ matrix.host_container }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -216,15 +255,15 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_ACCESS_TOKEN }} - - name: "Rebuild wasmedge/wasmedge:manylinux2014_x86_64" + - name: "Rebuild wasmedge/wasmedge:${{ matrix.docker_tag }}" uses: docker/build-push-action@v5 with: - build-args: BASE=quay.io/pypa/manylinux2014_x86_64 + build-args: BASE=quay.io/pypa/${{ matrix.docker_tag }} context: ./utils/docker - file: utils/docker/Dockerfile.manylinux2014_x86_64 - platforms: linux/amd64 + file: ${{ matrix.dockerfile }} + platforms: ${{ matrix.target_platforms }} push: ${{ github.event_name != 'pull_request' }} - tags: ${{ needs.prep.outputs.docker_image }}:manylinux2014_x86_64 + tags: ${{ needs.prep.outputs.docker_image }}:${{ matrix.docker_tag }} labels: | org.opencontainers.image.title=${{ github.event.repository.name }} org.opencontainers.image.description=${{ github.event.repository.description }} @@ -234,15 +273,15 @@ jobs: org.opencontainers.image.created=${{ needs.prep.outputs.created }} org.opencontainers.image.revision=${{ github.sha }} - - name: "Rebuild wasmedge/wasmedge:manylinux2014_x86_64-plugins-deps" + - name: "Rebuild wasmedge/wasmedge:${{ matrix.docker_tag }}-plugins-deps" uses: docker/build-push-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 + build-args: BASE=wasmedge/wasmedge:${{ matrix.docker_tag }} + context: ./utils + file: ${{ matrix.dockerfile_plugin }} + platforms: ${{ matrix.target_platforms }} push: ${{ github.event_name != 'pull_request' }} - tags: ${{ needs.prep.outputs.docker_image }}:manylinux2014_x86_64-plugins-deps + tags: ${{ needs.prep.outputs.docker_image }}:${{ matrix.docker_tag }}-plugins-deps labels: | org.opencontainers.image.title=${{ github.event.repository.name }} org.opencontainers.image.description=${{ github.event.repository.description }} diff --git a/.github/workflows/ignore_words b/.github/workflows/ignore_words index 3e6db4519ce6..135b899353a1 100644 --- a/.github/workflows/ignore_words +++ b/.github/workflows/ignore_words @@ -17,3 +17,5 @@ unexpect cript wit createor +inout +anull \ No newline at end of file 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/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..1832749958b9 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) @@ -73,8 +73,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','asset_tag':'manylinux2014_x86_64'}, + {'name':'manylinux2014 aarch64','runner':'linux-arm64-v2','docker_tag':'manylinux2014_aarch64','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 @@ -135,7 +146,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,7 +156,7 @@ 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 bash utils/wasi-nn/install-openvino.sh bash utils/wasi-nn/install-pytorch.sh - name: Build WASI-NN plugin @@ -157,7 +168,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:" @@ -206,15 +217,15 @@ jobs: 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_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 -DWASMEDGE_PLUGIN_FFMPEG=ON + tar_names: wasi_crypto wasi_logging wasmedge_process wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasm_bpf wasmedge_opencvmini wasmedge_zlib wasmedge_ffmpeg + output_bins: libwasmedgePluginWasiCrypto.so libwasmedgePluginWasiLogging.so libwasmedgePluginWasmEdgeProcess.so libwasmedgePluginWasmEdgeTensorflow.so libwasmedgePluginWasmEdgeTensorflowLite.so libwasmedgePluginWasmEdgeImage.so libwasmedgePluginWasmBpf.so libwasmedgePluginWasmEdgeOpenCVMini.so libwasmedgePluginWasmEdgeZlib.so libwasmedgePluginWasmEdgeFFmpeg.so needs: create_release container: image: wasmedge/wasmedge:ubuntu-build-clang-plugins-deps 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 +237,14 @@ 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 - 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 +256,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++ )); @@ -312,9 +327,15 @@ 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 - build_and_upload_wasinn_manylinux: - name: Build and upload WASI-NN on manylinux + build_and_upload_plugins_manylinux: + name: Build and upload plugins on manylinux needs: create_release uses: ./.github/workflows/reusable-build-extensions.yml with: @@ -322,133 +343,6 @@ jobs: release: true secrets: inherit - build_and_upload_plugin_manylinux: - 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 }} - env: - 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 }} - steps: - - name: Checkout code - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Grant the safe directory for git - run: | - git config --global --add safe.directory $(pwd) - - name: Build and install dependencies - 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 - 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 - 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 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 }}}) - 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 }} - 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 - 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 }} - 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 }} - 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 }} - 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 - 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 - 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 - build_and_upload_plugin_macos: strategy: matrix: @@ -459,7 +353,7 @@ jobs: 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 @@ -467,13 +361,13 @@ jobs: 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_WASI_LOGGING=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 + tar_names: wasi_crypto wasi_logging wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image wasmedge_opencvmini wasmedge_zlib wasmedge_ffmpeg + output_bins: libwasmedgePluginWasiCrypto.dylib libwasmedgePluginWasiLogging.dylib libwasmedgePluginWasmEdgeTensorflow.dylib libwasmedgePluginWasmEdgeTensorflowLite.dylib libwasmedgePluginWasmEdgeImage.dylib libwasmedgePluginWasmEdgeOpenCVMini.dylib libwasmedgePluginWasmEdgeZlib.dylib libwasmedgePluginWasmEdgeFFmpeg.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 +376,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 wabt 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]} :" @@ -560,6 +455,12 @@ 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 build_manylinux2014_runtime_only: name: Build runtime only on manylinux2014 platform @@ -575,7 +476,7 @@ 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: @@ -583,7 +484,7 @@ jobs: 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 + 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 ${{ matrix.name }} tar.gz package @@ -605,11 +506,11 @@ jobs: include_bin: "--include-bin /usr/local/bin/wasmedge" name: Build DockerSlim Images needs: - [create_release, build_on_manylinux2014, build_manylinux2014_runtime_only] + [ create_release, build_on_manylinux2014, build_manylinux2014_runtime_only ] runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Prepare tarball uses: actions/download-artifact@v3 with: @@ -665,7 +566,7 @@ jobs: 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-manylinux.yml b/.github/workflows/reusable-build-extensions-on-manylinux.yml index 12cb57ed80f7..d050d7da022a 100644 --- a/.github/workflows/reusable-build-extensions-on-manylinux.yml +++ b/.github/workflows/reusable-build-extensions-on-manylinux.yml @@ -12,6 +12,9 @@ on: docker_tag: type: string required: true + asset_tag: + type: string + required: true plugins: type: string required: true @@ -25,13 +28,26 @@ on: 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 variables + runs-on: ${{ inputs.runner }} + outputs: + cache_key_ws: ${{ steps.prep.outputs.cache_key_ws }} + cache_path_ws: ${{ steps.prep.outputs.cache_path_ws }} + cache_key_h: ${{ steps.prep.outputs.cache_key_h }} + cache_path_h: ${{ steps.prep.outputs.cache_path_h }} + steps: + - id: prep + run: | + echo "cache_key_ws=${{ github.workflow }}-${{ github.head_ref || github.ref }}-${{ inputs.docker_tag }}-1-${{ github.run_id }}" >> $GITHUB_OUTPUT + echo "cache_path_ws=${{ github.workspace }}" >> $GITHUB_OUTPUT + echo "cache_key_h=${{ github.workflow }}-${{ github.head_ref || github.ref }}-${{ inputs.docker_tag }}-2-${{ github.run_id }}" >> $GITHUB_OUTPUT + echo "cache_path_h=$HOME" >> $GITHUB_OUTPUT + + prepare_cache: + needs: [prepare] name: Prepare files (${{ inputs.docker_tag }}) runs-on: ${{ inputs.runner }} container: @@ -39,18 +55,7 @@ jobs: # 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 @@ -61,40 +66,40 @@ jobs: 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 + mkdir -p build + cmake -Bbuild -GNinja -DWASMEDGE_BUILD_TESTS=${build_tests} -DCMAKE_BUILD_TYPE=${build_type} -DWASMEDGE_USE_LLVM=OFF -DWASMEDGE_BUILD_TOOLS=OFF -DWASMEDGE_PLUGIN_WASI_LOGGING=ON -DOPENSSL_ROOT_DIR=${OpenSSL_DIR} + cmake --build build --target wasmedgePluginWasiLogging - uses: actions/cache/save@v3 with: - key: ${{ steps.prep.outputs.cache_key1 }} - path: ${{ steps.prep.outputs.cache_path1 }} + key: ${{ needs.prepare.outputs.cache_key_ws }} + path: ${{ needs.prepare.outputs.cache_path_ws }} - uses: actions/cache/save@v3 with: - key: ${{ steps.prep.outputs.cache_key2 }} - path: ${{ steps.prep.outputs.cache_path2 }} + key: ${{ needs.prepare.outputs.cache_key_h }} + path: ${{ needs.prepare.outputs.cache_path_h }} build_on_manylinux: - needs: [prepare] + needs: [prepare, prepare_cache] 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 }} + 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: ${{ inputs.release && matrix.bin || matrix.testBin }} @@ -103,25 +108,27 @@ jobs: steps: - id: prep run: | - echo "artifact=WasmEdge-plugin-${{ matrix.plugin }}-${{ inputs.version }}-${{ inputs.docker_tag }}.tar.gz" >> $GITHUB_OUTPUT + echo "artifact=WasmEdge-plugin-${{ matrix.plugin }}-${{ inputs.version }}-${{ inputs.asset_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 }} + key: ${{ needs.prepare.outputs.cache_key_ws }} + path: ${{ needs.prepare.outputs.cache_path_ws }} - uses: actions/cache/restore@v3 with: - key: ${{ needs.prepare.outputs.cache_key2 }} - path: ${{ needs.prepare.outputs.cache_path2 }} + key: ${{ needs.prepare.outputs.cache_key_h }} + path: ${{ needs.prepare.outputs.cache_path_h }} + - name: Ensure git safe directory + run: | + git config --global --add safe.directory $(pwd) - name: Install dependencies shell: bash run: | - mkdir -p build - bash ./utils/wasi-nn/install-pytorch.sh --disable-cxx11-abi + # Running tests of wasm_bpf requires proper ebpf running environment + mount -t debugfs none /sys/kernel/debug - 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} @@ -144,12 +151,6 @@ jobs: with: name: ${{ steps.prep.outputs.artifact }} path: ${{ steps.prep.outputs.filename }} - - name: Install gh on manylinux - if: ${{ inputs.release }} - 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 WasmEdge ${{ matrix.plugin }} plugin tar.gz package if: ${{ inputs.release }} env: diff --git a/.github/workflows/reusable-build-extensions.yml b/.github/workflows/reusable-build-extensions.yml index 9da37f86e882..e3b523ee4933 100644 --- a/.github/workflows/reusable-build-extensions.yml +++ b/.github/workflows/reusable-build-extensions.yml @@ -29,12 +29,13 @@ jobs: fail-fast: false matrix: include: ${{ fromJSON(needs.prepare.outputs.matrix) }} - name: Build all plugins on ${{ matrix.docker_tag }} + name: ${{ matrix.arch }} uses: ./.github/workflows/reusable-build-extensions-on-manylinux.yml with: arch: ${{ matrix.arch }} runner: ${{ matrix.runner }} docker_tag: ${{ matrix.docker_tag }} + asset_tag: ${{ matrix.asset_tag }} plugins: ${{ toJSON(matrix.plugins) }} version: ${{ inputs.version }} release: ${{ inputs.release }} diff --git a/.github/workflows/reusable-build-on-alpine-static.yml b/.github/workflows/reusable-build-on-alpine-static.yml index a2d82e2224a9..4a7e0cd4d063 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 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..afd4f4c4b63a 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 diff --git a/.github/workflows/reusable-build-on-fedora.yml b/.github/workflows/reusable-build-on-fedora.yml index 13e87fc1e7eb..319543505033 100644 --- a/.github/workflows/reusable-build-on-fedora.yml +++ b/.github/workflows/reusable-build-on-fedora.yml @@ -10,7 +10,10 @@ on: type: boolean upload_asset_url: type: string - + +permissions: + contents: read + jobs: build_fedora: permissions: @@ -25,7 +28,7 @@ jobs: 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 +52,5 @@ jobs: if: ${{ !inputs.release }} uses: actions/upload-artifact@v3 with: - name: WasmEdge-${{ inputs.version }}-fedora35.tar.gz + name: WasmEdge-${{ inputs.version }}-fedora.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..58c3d925b5a0 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: @@ -42,7 +45,7 @@ jobs: - name: Install gh on manylinux if: ${{ inputs.release }} run: | - type -p yum-config-manager >/dev/null || sudo yum install yum-utils + 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 diff --git a/.github/workflows/reusable-build-on-ubuntu.yml b/.github/workflows/reusable-build-on-ubuntu.yml index 4df645267a82..70ed6e75823c 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: @@ -26,11 +29,17 @@ jobs: 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 @@ -93,9 +102,10 @@ jobs: gh release upload ${{ inputs.version }} WasmEdge-${{ inputs.version }}-ubuntu20.04_x86_64.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..5b7bd4e1fdfa 100644 --- a/.github/workflows/reusable-build-on-windows-msvc.yml +++ b/.github/workflows/reusable-build-on-windows-msvc.yml @@ -8,7 +8,10 @@ on: required: true 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,7 +31,7 @@ jobs: uses: crazy-max/ghaction-chocolatey@v3 with: args: install cmake ninja vswhere - - uses: GuillaumeFalourd/setup-windows10-sdk-action@v1.11 + - uses: GuillaumeFalourd/setup-windows10-sdk-action@v2 with: sdk-version: 19041 - name: Set environment variables for release diff --git a/.github/workflows/reusable-build-on-windows.yml b/.github/workflows/reusable-build-on-windows.yml index 295b5e9a5875..b166e48bcddb 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 @@ -28,7 +28,7 @@ jobs: uses: crazy-max/ghaction-chocolatey@v3 with: args: install cmake ninja vswhere - - uses: GuillaumeFalourd/setup-windows10-sdk-action@v1.11 + - uses: GuillaumeFalourd/setup-windows10-sdk-action@v2 with: sdk-version: 19041 - name: Set environment variables for release 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..108fc32ce20a 100644 --- a/.github/workflows/test-install-script.yml +++ b/.github/workflows/test-install-script.yml @@ -72,7 +72,7 @@ jobs: 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 .. - 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 @@ -133,6 +133,16 @@ jobs: - name: Uninstall WasmEdge with wasi_nn-ggml run: | bash utils/uninstall.sh -q -V + - name: Install WasmEdge and wasi_nn-ggml-noavx plugin (0.13.5) + if: ${{ matrix.docker_image == 'ubuntu:20.04' }} + run: | + # 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: Install versions multiple times run: | bash utils/install.sh -e all -D @@ -166,24 +176,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-latest 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,26 +197,23 @@ 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' }} run: | bash utils/install.sh -e all -D - name: Uninstall WasmEdge with all extensions - if: ${{ matrix.name != 'MacOS-arm64' }} run: | bash utils/uninstall.sh -q -V - name: Install deprecated WasmEdge specific release (0.10.0) @@ -220,15 +223,12 @@ jobs: run: | bash utils/uninstall.sh -q -V - name: Install WasmEdge specific release (0.10.0) with all extensions - if: ${{ matrix.name != 'MacOS-arm64' }} run: | bash utils/install.sh -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: | 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) @@ -242,23 +242,71 @@ jobs: # 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: Tensorflow changes - libtensorflow_cc 2.6.0 will replace the old libtensorflow 2.6.0 + 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 + run: | + bash utils/uninstall.sh -q -V + - 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) + _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 -D + - name: Uninstall WasmEdge + shell: zsh {0} + run: | + bash utils/uninstall.sh -q -V + - name: Check for bashrc generation + shell: zsh {0} + run: | + 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: Install deprecated WasmEdge specific release (0.10.0) + shell: zsh {0} + run: | + bash utils/install.sh -v 0.10.0 -D + - name: Uninstall WasmEdge + shell: zsh {0} + run: | + bash utils/uninstall.sh -q -V - 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..a28b23831ec8 --- /dev/null +++ b/.github/workflows/test-installer-v2.yml @@ -0,0 +1,115 @@ +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: 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-latest + 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: 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..75828e3d5122 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 @@ -86,7 +86,7 @@ jobs: 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 .. - 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 @@ -197,6 +197,30 @@ jobs: 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-b2781 + 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-b2781 + 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: | @@ -343,43 +367,54 @@ 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 }} 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 + shell: zsh {0} if: ${{ matrix.name != 'MacOS-arm64' }} run: | python3 utils/install.py -e all -D - name: Uninstall WasmEdge with all extensions + shell: zsh {0} if: ${{ matrix.name != 'MacOS-arm64' }} run: | bash utils/uninstall.sh -q -V - name: Install WasmEdge specific release (0.10.0) + shell: zsh {0} run: | python3 utils/install.py -v 0.10.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 + shell: zsh {0} if: ${{ matrix.name != 'MacOS-arm64' }} run: | python3 utils/install.py -e all -v 0.10.0 -D - name: Uninstall WasmEdge with all extensions + shell: zsh {0} if: ${{ matrix.name != 'MacOS-arm64' }} run: | bash utils/uninstall.sh -q -V - name: Plugins Install check MacOS-x86 + shell: zsh {0} if: ${{ matrix.name != 'MacOS-arm64' }} run: | python3 utils/install.py -v 0.10.0-alpha.1 @@ -397,6 +432,7 @@ jobs: # ls /usr/lib/wasmedge/ | grep libwasmedgePluginWasmEdgeProcess.dylib && echo "Pass: Plugins found" || (echo "Fail: Plugins not found" && exit 1) - name: Plugins Install check MacOS-arm64 + shell: zsh {0} if: ${{ matrix.name == 'MacOS-arm64' }} run: | python3 utils/install.py -v 0.13.1 --plugins wasmedge_tensorflow @@ -407,6 +443,7 @@ jobs: 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 + shell: zsh {0} if: ${{ matrix.name != 'MacOS-arm64' }} run: | python3 utils/install.py -e tensorflow -D 2>&1 -v 0.12.0 @@ -414,12 +451,14 @@ jobs: 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 + shell: zsh {0} 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 + shell: zsh {0} if: ${{ matrix.name != 'MacOS-arm64' }} run: | python3 utils/install.py -e image -D 2>&1 -v 0.12.0 @@ -427,18 +466,21 @@ jobs: 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 + shell: zsh {0} if: ${{ matrix.name == 'MacOS-arm64' }} 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 + shell: zsh {0} 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 + shell: zsh {0} if: ${{ matrix.name != 'MacOS-arm64' }} run: | PYTHON_EXECUTABLE=python3 bash utils/installer_changes.sh "$HOME"/.wasmedge @@ -452,6 +494,7 @@ jobs: 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..b02ec72e26fe 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: @@ -32,7 +35,7 @@ jobs: os: [ubuntu-latest, macos-latest] 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,19 @@ 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: 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/CMakeLists.txt b/CMakeLists.txt index 7962eaf6f98e..b2daf6189eda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,20 @@ cmake_policy(SET CMP0091 NEW) if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") cmake_policy(SET CMP0135 NEW) endif() -project(WasmEdge) + +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/refs/tags/v0.25.3-qdrvm14.zip + SHA1 6fc0eb2ab6b85cec6f43d247eb43c0ab0ecdaa65 + LOCAL +) + +project(WasmEdge LANGUAGES CXX C) # Overwrite it if you want to use static MSVC runtime library. set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") @@ -51,7 +64,6 @@ 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) @@ -59,18 +71,26 @@ option(WASMEDGE_BUILD_FUZZING "Generate fuzzing test tools. Couldn't build with 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_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_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" 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_WASI_OCR "Enable WasmEdge wasm-ocr 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) @@ -79,6 +99,7 @@ option(WASMEDGE_PLUGIN_TENSORFLOWLITE "Enable WasmEdge TensorFlow-Lite plugin." 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_PLUGIN_FFMPEG "Enable WasmEdge ffmpeg plugin." OFF) if(WASMEDGE_BUILD_TOOLS AND WASMEDGE_BUILD_FUZZING) message(FATAL_ERROR "wasmedge tool and fuzzing tool are exclusive options.") @@ -111,22 +132,23 @@ if(WASMEDGE_BUILD_PLUGINS) 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") @@ -138,6 +160,12 @@ if(WASMEDGE_BUILD_COVERAGE) append_coverage_compiler_flags() endif() +if(WASMEDGE_USE_LLVM) + hunter_add_package(ZLIB) + hunter_add_package(LLVM) + hunter_add_package(LLD) +endif() + include(Helper) include(GNUInstallDirs) @@ -182,4 +210,3 @@ endif() include(CPack) include(CPackComponent) - diff --git a/Changelog.md b/Changelog.md index eba6f9c97737..8f1c3869a62f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,4 +1,4 @@ -### 0.14.0-alpha.1 (2024-01-05) +### 0.14.0 (2024-05-22) Breaking changes: @@ -29,16 +29,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 +87,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 `` 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 +133,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 +157,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) diff --git a/README.md b/README.md index 388642e477a4..3df8dfa191a6 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ 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/cmake/Helper.cmake b/cmake/Helper.cmake index 2b447ab23978..53685b54d40e 100644 --- a/cmake/Helper.cmake +++ b/cmake/Helper.cmake @@ -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 @@ -121,7 +140,7 @@ function(wasmedge_setup_target target) set_target_properties(${target} PROPERTIES CXX_STANDARD 17 CXX_EXTENSIONS OFF - CXX_VISIBILITY_PRESET hidden + # CXX_VISIBILITY_PRESET hidden ENABLE_EXPORTS ON POSITION_INDEPENDENT_CODE ON VISIBILITY_INLINES_HIDDEN ON @@ -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) @@ -251,22 +270,24 @@ if((WASMEDGE_LINK_LLVM_STATIC OR WASMEDGE_BUILD_STATIC_LIB) AND WASMEDGE_BUILD_A list(APPEND WASMEDGE_LLVM_LINK_SHARED_COMPONENTS rt ) - if(WASMEDGE_BUILD_STATIC_LIB) - # Static library will forcefully turn off the LTO. - # Therefore, libz and libtinfo can be statically linked. - find_package(ZLIB REQUIRED) - get_filename_component(ZLIB_PATH "${ZLIB_LIBRARIES}" DIRECTORY) - list(APPEND WASMEDGE_LLVM_LINK_STATIC_COMPONENTS ${ZLIB_PATH}/libz.a) - if(NOT WASMEDGE_DISABLE_LIBTINFO) - list(APPEND WASMEDGE_LLVM_LINK_STATIC_COMPONENTS ${ZLIB_PATH}/libtinfo.a) - endif() - else() - # If not build static lib, dynamic link libz and libtinfo. - list(APPEND WASMEDGE_LLVM_LINK_SHARED_COMPONENTS - z - ) - if(NOT WASMEDGE_DISABLE_LIBTINFO) - list(APPEND WASMEDGE_LLVM_LINK_SHARED_COMPONENTS tinfo) + if(WASMEDGE_PLUGIN_ZLIB) + if(WASMEDGE_BUILD_STATIC_LIB) + # Static library will forcefully turn off the LTO. + # Therefore, libz and libtinfo can be statically linked. + find_package(ZLIB REQUIRED) + get_filename_component(ZLIB_PATH "${ZLIB_LIBRARIES}" DIRECTORY) + list(APPEND WASMEDGE_LLVM_LINK_STATIC_COMPONENTS ${ZLIB_PATH}/libz.a) + if(NOT WASMEDGE_DISABLE_LIBTINFO) + list(APPEND WASMEDGE_LLVM_LINK_STATIC_COMPONENTS ${ZLIB_PATH}/libtinfo.a) + endif() + else() + # If not build static lib, dynamic link libz and libtinfo. + list(APPEND WASMEDGE_LLVM_LINK_SHARED_COMPONENTS + z + ) + if(NOT WASMEDGE_DISABLE_LIBTINFO) + list(APPEND WASMEDGE_LLVM_LINK_SHARED_COMPONENTS tinfo) + endif() endif() endif() endif() diff --git a/cmake/Hunter/config.cmake b/cmake/Hunter/config.cmake new file mode 100644 index 000000000000..e7f6175c1d22 --- /dev/null +++ b/cmake/Hunter/config.cmake @@ -0,0 +1,39 @@ +## Identify native architecture to reduce amount of targets to build +set(ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}") + +if(ARCHITECTURE MATCHES "^(aarch64.*|AARCH64.*|arm.*|ARM.*)") + set(ARCHITECTURE AArch64) +elseif(ARCHITECTURE MATCHES "^(x86_64.*|AMD64.*|i386.*|i686.*)") + set(ARCHITECTURE X86) +elseif(ARCHITECTURE MATCHES "^(riscv.*)") + set(ARCHITECTURE RISCV) +else() + message(WARNING "Unknown architecture: ${ARCHITECTURE}, using all architectures to build LLVM") + set(ARCHITECTURE AArch64;X86;RISCV) +endif() + +hunter_config( + LLVM + VERSION 17.0.6 + CMAKE_ARGS # inspired by https://github.com/WasmEdge/WasmEdge/blob/5e8556afa5a71f3d3ef9615334ecf1a9d4d0f1e8/utils/docker/Dockerfile.manylinux2014_x86_64#L57 + 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/HunterGate.cmake b/cmake/HunterGate.cmake new file mode 100644 index 000000000000..1da4c2de259a --- /dev/null +++ b/cmake/HunterGate.cmake @@ -0,0 +1,539 @@ +# Copyright (c) 2013-2019, Ruslan Baratov +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This is a gate file to Hunter package manager. +# Include this file using `include` command and add package you need, example: +# +# cmake_minimum_required(VERSION 3.5) +# +# include("cmake/HunterGate.cmake") +# HunterGate( +# URL "https://github.com/path/to/hunter/archive.tar.gz" +# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d" +# ) +# +# project(MyProject) +# +# hunter_add_package(Foo) +# hunter_add_package(Boo COMPONENTS Bar Baz) +# +# Projects: +# * https://github.com/hunter-packages/gate/ +# * https://github.com/ruslo/hunter + +option(HUNTER_ENABLED "Enable Hunter package manager support" ON) + +if(HUNTER_ENABLED) + if(CMAKE_VERSION VERSION_LESS "3.2") + message( + FATAL_ERROR + "At least CMake version 3.2 required for Hunter dependency management." + " Update CMake or set HUNTER_ENABLED to OFF." + ) + endif() +endif() + +include(CMakeParseArguments) # cmake_parse_arguments + +option(HUNTER_STATUS_PRINT "Print working status" ON) +option(HUNTER_STATUS_DEBUG "Print a lot info" OFF) +option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON) + +set(HUNTER_ERROR_PAGE "https://docs.hunter.sh/en/latest/reference/errors") + +function(hunter_gate_status_print) + if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG) + foreach(print_message ${ARGV}) + message(STATUS "[hunter] ${print_message}") + endforeach() + endif() +endfunction() + +function(hunter_gate_status_debug) + if(HUNTER_STATUS_DEBUG) + foreach(print_message ${ARGV}) + string(TIMESTAMP timestamp) + message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}") + endforeach() + endif() +endfunction() + +function(hunter_gate_error_page error_page) + message("------------------------------ ERROR ------------------------------") + message(" ${HUNTER_ERROR_PAGE}/${error_page}.html") + message("-------------------------------------------------------------------") + message("") + message(FATAL_ERROR "") +endfunction() + +function(hunter_gate_internal_error) + message("") + foreach(print_message ${ARGV}) + message("[hunter ** INTERNAL **] ${print_message}") + endforeach() + message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_error_page("error.internal") +endfunction() + +function(hunter_gate_fatal_error) + cmake_parse_arguments(hunter "" "ERROR_PAGE" "" "${ARGV}") + if("${hunter_ERROR_PAGE}" STREQUAL "") + hunter_gate_internal_error("Expected ERROR_PAGE") + endif() + message("") + foreach(x ${hunter_UNPARSED_ARGUMENTS}) + message("[hunter ** FATAL ERROR **] ${x}") + endforeach() + message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_error_page("${hunter_ERROR_PAGE}") +endfunction() + +function(hunter_gate_user_error) + hunter_gate_fatal_error(${ARGV} ERROR_PAGE "error.incorrect.input.data") +endfunction() + +function(hunter_gate_self root version sha1 result) + string(COMPARE EQUAL "${root}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("root is empty") + endif() + + string(COMPARE EQUAL "${version}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("version is empty") + endif() + + string(COMPARE EQUAL "${sha1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("sha1 is empty") + endif() + + string(SUBSTRING "${sha1}" 0 7 archive_id) + + if(EXISTS "${root}/cmake/Hunter") + set(hunter_self "${root}") + else() + set( + hunter_self + "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked" + ) + endif() + + set("${result}" "${hunter_self}" PARENT_SCOPE) +endfunction() + +# Set HUNTER_GATE_ROOT cmake variable to suitable value. +function(hunter_gate_detect_root) + # Check CMake variable + string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty) + if(not_empty) + set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable") + return() + endif() + + # Check environment variable + string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty) + if(not_empty) + set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by environment variable") + return() + endif() + + # Check HOME environment variable + string(COMPARE NOTEQUAL "$ENV{HOME}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable") + return() + endif() + + # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only) + if(WIN32) + string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using SYSTEMDRIVE environment variable" + ) + return() + endif() + + string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using USERPROFILE environment variable" + ) + return() + endif() + endif() + + hunter_gate_fatal_error( + "Can't detect HUNTER_ROOT" + ERROR_PAGE "error.detect.hunter.root" + ) +endfunction() + +function(hunter_gate_download dir) + string( + COMPARE + NOTEQUAL + "$ENV{HUNTER_DISABLE_AUTOINSTALL}" + "" + disable_autoinstall + ) + if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL) + hunter_gate_fatal_error( + "Hunter not found in '${dir}'" + "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'" + "Settings:" + " HUNTER_ROOT: ${HUNTER_GATE_ROOT}" + " HUNTER_SHA1: ${HUNTER_GATE_SHA1}" + ERROR_PAGE "error.run.install" + ) + endif() + string(COMPARE EQUAL "${dir}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("Empty 'dir' argument") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_SHA1 empty") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_URL empty") + endif() + + set(done_location "${dir}/DONE") + set(sha1_location "${dir}/SHA1") + + set(build_dir "${dir}/Build") + set(cmakelists "${dir}/CMakeLists.txt") + + hunter_gate_status_debug("Locking directory: ${dir}") + file(LOCK "${dir}" DIRECTORY GUARD FUNCTION) + hunter_gate_status_debug("Lock done") + + if(EXISTS "${done_location}") + # while waiting for lock other instance can do all the job + hunter_gate_status_debug("File '${done_location}' found, skip install") + return() + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(MAKE_DIRECTORY "${build_dir}") # check directory permissions + + # Disabling languages speeds up a little bit, reduces noise in the output + # and avoids path too long windows error + file( + WRITE + "${cmakelists}" + "cmake_minimum_required(VERSION 3.5)\n" + "project(HunterDownload LANGUAGES NONE)\n" + "include(ExternalProject)\n" + "ExternalProject_Add(\n" + " Hunter\n" + " URL\n" + " \"${HUNTER_GATE_URL}\"\n" + " URL_HASH\n" + " SHA1=${HUNTER_GATE_SHA1}\n" + " DOWNLOAD_DIR\n" + " \"${dir}\"\n" + " TLS_VERIFY\n" + " ${HUNTER_TLS_VERIFY}\n" + " SOURCE_DIR\n" + " \"${dir}/Unpacked\"\n" + " CONFIGURE_COMMAND\n" + " \"\"\n" + " BUILD_COMMAND\n" + " \"\"\n" + " INSTALL_COMMAND\n" + " \"\"\n" + ")\n" + ) + + if(HUNTER_STATUS_DEBUG) + set(logging_params "") + else() + set(logging_params OUTPUT_QUIET) + endif() + + hunter_gate_status_debug("Run generate") + + # Need to add toolchain file too. + # Otherwise on Visual Studio + MDD this will fail with error: + # "Could not find an appropriate version of the Windows 10 SDK installed on this machine" + if(EXISTS "${CMAKE_TOOLCHAIN_FILE}") + get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE) + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}") + else() + # 'toolchain_arg' can't be empty + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=") + endif() + + string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make) + if(no_make) + set(make_arg "") + else() + # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM + set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}") + endif() + + execute_process( + COMMAND + "${CMAKE_COMMAND}" + "-H${dir}" + "-B${build_dir}" + "-G${CMAKE_GENERATOR}" + "${toolchain_arg}" + ${make_arg} + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error( + "Configure project failed." + "To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}" + "In directory ${dir}" + ) + endif() + + hunter_gate_status_print( + "Initializing Hunter workspace (${HUNTER_GATE_SHA1})" + " ${HUNTER_GATE_URL}" + " -> ${dir}" + ) + execute_process( + COMMAND "${CMAKE_COMMAND}" --build "${build_dir}" + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error("Build project failed") + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}") + file(WRITE "${done_location}" "DONE") + + hunter_gate_status_debug("Finished") +endfunction() + +# Must be a macro so master file 'cmake/Hunter' can +# apply all variables easily just by 'include' command +# (otherwise PARENT_SCOPE magic needed) +macro(HunterGate) + if(HUNTER_GATE_DONE) + # variable HUNTER_GATE_DONE set explicitly for external project + # (see `hunter_download`) + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() + + # First HunterGate command will init Hunter, others will be ignored + get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET) + + if(NOT HUNTER_ENABLED) + # Empty function to avoid error "unknown function" + function(hunter_add_package) + endfunction() + + set( + _hunter_gate_disabled_mode_dir + "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode" + ) + if(EXISTS "${_hunter_gate_disabled_mode_dir}") + hunter_gate_status_debug( + "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}" + ) + list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}") + endif() + elseif(_hunter_gate_done) + hunter_gate_status_debug("Secondary HunterGate (use old settings)") + hunter_gate_self( + "${HUNTER_CACHED_ROOT}" + "${HUNTER_VERSION}" + "${HUNTER_SHA1}" + _hunter_self + ) + include("${_hunter_self}/cmake/Hunter") + else() + set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}") + + string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name) + if(_have_project_name) + hunter_gate_fatal_error( + "Please set HunterGate *before* 'project' command. " + "Detected project: ${PROJECT_NAME}" + ERROR_PAGE "error.huntergate.before.project" + ) + endif() + + cmake_parse_arguments( + HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV} + ) + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1) + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url) + string( + COMPARE + NOTEQUAL + "${HUNTER_GATE_UNPARSED_ARGUMENTS}" + "" + _have_unparsed + ) + string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global) + string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath) + + if(_have_unparsed) + hunter_gate_user_error( + "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}" + ) + endif() + if(_empty_sha1) + hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory") + endif() + if(_empty_url) + hunter_gate_user_error("URL suboption of HunterGate is mandatory") + endif() + if(_have_global) + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)") + endif() + endif() + if(HUNTER_GATE_LOCAL) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)") + endif() + endif() + if(_have_filepath) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)") + endif() + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)") + endif() + endif() + + hunter_gate_detect_root() # set HUNTER_GATE_ROOT + + # Beautify path, fix probable problems with windows path slashes + get_filename_component( + HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE + ) + hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}") + if(NOT HUNTER_ALLOW_SPACES_IN_PATH) + string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces) + if(NOT _contain_spaces EQUAL -1) + hunter_gate_fatal_error( + "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces." + "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error" + "(Use at your own risk!)" + ERROR_PAGE "error.spaces.in.hunter.root" + ) + endif() + endif() + + string( + REGEX + MATCH + "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*" + HUNTER_GATE_VERSION + "${HUNTER_GATE_URL}" + ) + string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty) + if(_is_empty) + set(HUNTER_GATE_VERSION "unknown") + endif() + + hunter_gate_self( + "${HUNTER_GATE_ROOT}" + "${HUNTER_GATE_VERSION}" + "${HUNTER_GATE_SHA1}" + _hunter_self + ) + + set(_master_location "${_hunter_self}/cmake/Hunter") + if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter") + # Hunter downloaded manually (e.g. by 'git clone') + set(_unused "xxxxxxxxxx") + set(HUNTER_GATE_SHA1 "${_unused}") + set(HUNTER_GATE_VERSION "${_unused}") + else() + get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE) + set(_done_location "${_archive_id_location}/DONE") + set(_sha1_location "${_archive_id_location}/SHA1") + + # Check Hunter already downloaded by HunterGate + if(NOT EXISTS "${_done_location}") + hunter_gate_download("${_archive_id_location}") + endif() + + if(NOT EXISTS "${_done_location}") + hunter_gate_internal_error("hunter_gate_download failed") + endif() + + if(NOT EXISTS "${_sha1_location}") + hunter_gate_internal_error("${_sha1_location} not found") + endif() + file(READ "${_sha1_location}" _sha1_value) + string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal) + if(NOT _is_equal) + hunter_gate_internal_error( + "Short SHA1 collision:" + " ${_sha1_value} (from ${_sha1_location})" + " ${HUNTER_GATE_SHA1} (HunterGate)" + ) + endif() + if(NOT EXISTS "${_master_location}") + hunter_gate_user_error( + "Master file not found:" + " ${_master_location}" + "try to update Hunter/HunterGate" + ) + endif() + endif() + include("${_master_location}") + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() +endmacro() diff --git a/cmake/WASINNDeps.cmake b/cmake/WASINNDeps.cmake index 43f235cf5b9a..b0de24c32b25 100644 --- a/cmake/WASINNDeps.cmake +++ b/cmake/WASINNDeps.cmake @@ -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 diff --git a/cmake/wasmedge-config.cmake b/cmake/wasmedge-config.cmake new file mode 100644 index 000000000000..58dfd78422bc --- /dev/null +++ b/cmake/wasmedge-config.cmake @@ -0,0 +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() + +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() 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/plugin/get-string/getstring.cpp b/examples/plugin/get-string/getstring.cpp index 8dcc274ac870..1335c9cd3a32 100644 --- a/examples/plugin/get-string/getstring.cpp +++ b/examples/plugin/get-string/getstring.cpp @@ -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/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..b660a4b4774c 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. @@ -29,14 +29,14 @@ export WASMEDGE_PLUGIN_PATH=$PWD/plugins/wasi_logging 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 +48,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 +62,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/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..60a0a62d7cff 100644 --- a/examples/plugin/wasmedge-zlib/README.md +++ b/examples/plugin/wasmedge-zlib/README.md @@ -31,7 +31,7 @@ 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 ``` diff --git a/flake.nix b/flake.nix index 071564ca2233..db8cd5dbcf12 100644 --- a/flake.nix +++ b/flake.nix @@ -53,7 +53,7 @@ -DCMAKE_BUILD_TYPE=Debug \ -DWASMEDGE_BUILD_PLUGINS=OFF \ -DWASMEDGE_BUILD_TESTS=OFF \ - -DWASMEDGE_BUILD_AOT_RUNTIME=ON \ + -DWASMEDGE_USE_LLVM=ON \ . ''; buildPhase = '' diff --git a/include/api/wasmedge/wasmedge.h b/include/api/wasmedge/wasmedge.h index f32471640efe..d6f9ea8d373c 100644 --- a/include/api/wasmedge/wasmedge.h +++ b/include/api/wasmedge/wasmedge.h @@ -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. @@ -4067,6 +4181,33 @@ WasmEdge_ExecutorExperimentalRegisterPostHostFunction( WasmEdge_ExecutorContext *Cxt, void *Data, void (*Func)(void *)); // <<<<<<<< WasmEdge Experimental Functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +// >>>>>>>> [qdrvm] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +typedef struct WasmEdge_DataSegment { + uint32_t Offset; + const uint8_t *Data; + uint32_t Length; +} WasmEdge_DataSegment; + +/// List the data section of the AST module. +/// +/// If the `Segments` buffer length is smaller than the result of the data +/// section size, the overflowed return values will be discarded. +/// +/// \param Cxt the WasmEdge_ASTModuleContext. +/// \param [out] Segments the data segment buffer. Can be NULL if data segments +/// are not needed. +/// \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); + +// <<<<<<<< [qdrvm] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + #ifdef __cplusplus } /// extern "C" #endif diff --git a/include/ast/description.h b/include/ast/description.h index 08b7679d9cfd..444a4625532b 100644 --- a/include/ast/description.h +++ b/include/ast/description.h @@ -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/instruction.h b/include/ast/instruction.h index 04e1d354680a..9e8e85f9f32d 100644 --- a/include/ast/instruction.h +++ b/include/ast/instruction.h @@ -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 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,6 +226,13 @@ 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__) || \ @@ -198,18 +252,43 @@ class Instruction { #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 +345,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..f1d07621b23d 100644 --- a/include/ast/module.h +++ b/include/ast/module.h @@ -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 S) noexcept { + void setSymbol(Symbol 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 IntrSymbol; + Symbol IntrSymbol; /// @} /// \name Validated flag. @@ -143,15 +118,22 @@ class Module { class CoreModuleSection : public Section { public: /// Getter of content. - Span getContent() const noexcept { return Content; } - std::vector &getContent() noexcept { return Content; } + const Module &getContent() const noexcept { return Content; } + Module &getContent() noexcept { return Content; } private: - std::vector Content; + Module Content; }; namespace Component { + class Component { + using Section = + std::variant; + public: /// Getter of magic vector. const std::vector &getMagic() const noexcept { return Magic; } @@ -165,32 +147,8 @@ class Component { const std::vector &getLayer() const noexcept { return Layer; } std::vector &getLayer() noexcept { return Layer; } - std::vector &getCustomSections() noexcept { - return CustomSecs; - } - CoreModuleSection &getCoreModuleSection() noexcept { return CoreModSec; } - const CoreModuleSection &getCoreModuleSection() const noexcept { - return CoreModSec; - } - std::vector &getCoreInstanceSection() noexcept { - return CoreInstSec; - } - std::vector &getCoreTypeSection() noexcept { - return CoreTypeSec; - } - ComponentSection &getComponentSection() noexcept { return CompSec; } - const ComponentSection &getComponentSection() const noexcept { - return CompSec; - } - std::vector &getInstanceSection() noexcept { - return InstSec; - } - std::vector &getAliasSection() noexcept { return AliasSec; } - std::vector &getTypeSection() noexcept { return TySec; } - std::vector &getCanonSection() noexcept { return CanonSec; } - StartSection &getStartSection() noexcept { return StartSec; } - std::vector &getImportSection() noexcept { return ImSec; } - std::vector &getExportSection() noexcept { return ExSec; } + std::vector
&getSections() noexcept { return Secs; } + Span getSections() const noexcept { return Secs; } private: /// \name Data of Module node. @@ -198,18 +156,8 @@ class Component { std::vector Magic; std::vector Version; std::vector Layer; - std::vector CustomSecs; - CoreModuleSection CoreModSec; - std::vector CoreInstSec; - std::vector CoreTypeSec; - ComponentSection CompSec; - std::vector InstSec; - std::vector AliasSec; - std::vector TySec; - std::vector CanonSec; - StartSection StartSec; - std::vector ImSec; - std::vector ExSec; + + std::vector
Secs; /// @} }; diff --git a/include/ast/section.h b/include/ast/section.h index a492dcdc9991..5590231aff04 100644 --- a/include/ast/section.h +++ b/include/ast/section.h @@ -70,13 +70,13 @@ class CustomSection : public Section { class TypeSection : public Section { public: /// Getter of content vector. - Span getContent() const noexcept { return Content; } - std::vector &getContent() noexcept { return Content; } + Span getContent() const noexcept { return Content; } + std::vector &getContent() noexcept { return Content; } private: /// \name Data of TypeSection. /// @{ - std::vector Content; + std::vector 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 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 getContent() const noexcept { return Content; } + std::vector &getContent() noexcept { return Content; } + +private: + /// \name Data of TagSection. + /// @{ + std::vector Content; + /// @} +}; + class AOTSection { public: /// Getter and setter of version. @@ -286,6 +300,7 @@ class AOTSection { std::vector CodesAddress; std::vector>> Sections; + std::vector Bytecodes; /// @} }; @@ -372,13 +387,13 @@ class CanonSection : public Section { class StartSection : public Section { public: /// Getter of content module. - Span getContent() const noexcept { return Content; } - std::vector &getContent() noexcept { return Content; } + const Start &getContent() const noexcept { return Content; } + Start &getContent() noexcept { return Content; } private: /// \name Data of StartSection. /// @{ - std::vector Content; + Start Content; /// @} }; @@ -411,18 +426,13 @@ class ExportSection : public Section { class Component; class ComponentSection : public Section { - public: /// Getter of content. - Span> getContent() const noexcept { - return Content; - } - std::vector> &getContent() noexcept { - return Content; - } + const Component &getContent() const noexcept { return *Content; } + std::shared_ptr getContent() noexcept { return Content; } private: - std::vector> Content; + std::shared_ptr Content; }; } // namespace Component diff --git a/include/ast/type.h b/include/ast/type.h index b9490e6776cb..55e08c266ebc 100644 --- a/include/ast/type.h +++ b/include/ast/type.h @@ -14,10 +14,12 @@ //===----------------------------------------------------------------------===// #pragma once +#include "common/executable.h" #include "common/span.h" #include "common/symbol.h" #include "common/types.h" +#include #include 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 P, Span R) + FunctionType() noexcept = default; + FunctionType(Span P, Span R) noexcept : ParamTypes(P.begin(), P.end()), ReturnTypes(R.begin(), R.end()) {} - FunctionType(Span P, Span R, Symbol S) + FunctionType(Span P, Span R, + Symbol 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 S) noexcept { WrapSymbol = std::move(S); } + void setSymbol(Symbol S) noexcept { + WrapSymbol = std::move(S); + } private: /// \name Data of FunctionType. /// @{ std::vector ParamTypes; std::vector ReturnTypes; - Symbol WrapSymbol; + Symbol 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(&FType); + } + FunctionType &getFuncType() noexcept { + return *std::get_if(&FType); + } + const std::vector &getFieldTypes() const noexcept { + return *std::get_if>(&FType); + } + + /// Setter of content. + void setArrayType(FieldType &&FT) noexcept { + Type = TypeCode::Array; + FType = std::vector{std::move(FT)}; + } + void setStructType(std::vector &&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, 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 getSuperTypeIndices() const noexcept { + return SuperTypeIndices; + } + std::vector &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 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 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 SuperTypeIndices; + /// Content of composite type. + CompositeType CompType; + /// @} + + /// \name Information for defined types. + /// @{ + /// Recursive type information. Record the index in the recursive type. + std::optional RecTypeInfo; + /// Type index in the module. Record for backward iteration. + std::optional TypeIndex; + /// @} +}; + +/// AST Type match helper class. +class TypeMatcher { +public: + /// Validator: Match 2 defined types in the same module. + static bool matchType(Span 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 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 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 TypeList, + Span Exp, + Span 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 ExpTypeList, uint32_t ExpIdx, + Span 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 ExpTypeList, + const ValType &Exp, + Span 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 LHSList, + uint32_t LHSIdx, + Span 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 LHSList, + uint32_t LStartIdx, + Span 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 &LFieldTypes, + const std::vector &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(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,34 @@ 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( + Type->getCompositeType().getFuncType().getParamTypes().size()); + } else { + return 0; + } + } + +private: + uint32_t TypeIdx; + const SubType *Type; +}; + } // namespace AST } // namespace WasmEdge diff --git a/include/common/configure.h b/include/common/configure.h index add57945b5c2..bc62eea16ae8 100644 --- a/include/common/configure.h +++ b/include/common/configure.h @@ -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 MaxMemPage = 65536; + std::atomic EnableJIT = false; std::atomic ForceInterpreter = false; std::atomic 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(Proposal::GC))) { + // Proposal dependency: GC depends FunctionReferences. + return; + } + if (Type == Proposal::ReferenceTypes && + (Proposals.test(static_cast(Proposal::GC)) || + Proposals.test(static_cast(Proposal::FunctionReferences)))) { + // Proposal dependency: GC and FunctionReferences depend on + // ReferenceTypes. + return; + } Proposals.reset(static_cast(Type)); } @@ -329,6 +351,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 +377,15 @@ class Configure { void unsafeAddProposal(const Proposal Type) noexcept { Proposals.set(static_cast(Type)); + // Proposal dependency: FunctionReferences depends on ReferenceTypes. + if (Type == Proposal::FunctionReferences) { + Proposals.set(static_cast(Proposal::ReferenceTypes)); + } + // Proposal dependency: GC depends on FunctionReferences and ReferenceTypes. + if (Type == Proposal::GC) { + Proposals.set(static_cast(Proposal::FunctionReferences)); + Proposals.set(static_cast(Proposal::ReferenceTypes)); + } } void unsafeAddHostRegistration(const HostRegistration Host) noexcept { diff --git a/include/common/defines.h b/include/common/defines.h index 96e358a8722d..9ac468837606 100644 --- a/include/common/defines.h +++ b/include/common/defines.h @@ -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/enum.inc b/include/common/enum.inc index 33c376b4d55b..2151b39b3361 100644 --- a/include/common/enum.inc +++ b/include/common/enum.inc @@ -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,667 @@ 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 - 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 +793,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 // @{ @@ -805,58 +884,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 @@ -921,8 +1004,12 @@ 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 @@ -1002,6 +1089,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 +1098,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 +1128,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 @@ -1066,6 +1158,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..be41833a9cb2 100644 --- a/include/common/enum_ast.hpp +++ b/include/common/enum_ast.hpp @@ -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 #include @@ -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 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_errcode.hpp b/include/common/enum_errcode.hpp index 643d3178286d..a50f49dfbfdd 100644 --- a/include/common/enum_errcode.hpp +++ b/include/common/enum_errcode.hpp @@ -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 #include diff --git a/include/common/errcode.h b/include/common/errcode.h index 8dcc2c53b70e..4f73a121eb78 100644 --- a/include/common/errcode.h +++ b/include/common/errcode.h @@ -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 #include diff --git a/include/common/errinfo.h b/include/common/errinfo.h index 975e127f744e..a18bb1c36eba 100644 --- a/include/common/errinfo.h +++ b/include/common/errinfo.h @@ -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 diff --git a/include/common/executable.h b/include/common/executable.h new file mode 100644 index 000000000000..c03493c30d61 --- /dev/null +++ b/include/common/executable.h @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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 +#include +#include + +namespace WasmEdge { + +/// Holder class for library handle +class Executable : public std::enable_shared_from_this { + 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 getIntrinsics() noexcept = 0; + + virtual std::vector> getTypes(size_t Size) noexcept = 0; + + virtual std::vector> getCodes(size_t Offset, + size_t Size) noexcept = 0; + +protected: + template Symbol createSymbol(T *Pointer) const noexcept { + return Symbol(shared_from_this(), Pointer); + } +}; + +} // namespace WasmEdge diff --git a/include/common/log.h b/include/common/spdlog.h similarity index 95% rename from include/common/log.h rename to include/common/spdlog.h index fa3ec2df93b6..b42970a18ea6 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 -//===-- wasmedge/common/log.h - Logging system ----------------------------===// +//===-- wasmedge/common/spdlog.h - Logging system -------------------------===// // // Part of the WasmEdge Project. // diff --git a/include/common/statistics.h b/include/common/statistics.h index d06f8460f71d..1f7b10beea48 100644 --- a/include/common/statistics.h +++ b/include/common/statistics.h @@ -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 diff --git a/include/common/symbol.h b/include/common/symbol.h index 282333b56df9..9258cb1826d5 100644 --- a/include/common/symbol.h +++ b/include/common/symbol.h @@ -16,19 +16,16 @@ #include -namespace WasmEdge::Loader { -class SharedLibrary; -} - namespace WasmEdge { +class Executable; /// Holder class for library symbol template class Symbol { private: - friend class Loader::SharedLibrary; + friend class Executable; template friend class Symbol; - Symbol(std::shared_ptr H, T *S) noexcept + Symbol(std::shared_ptr H, T *S) noexcept : Library(std::move(H)), Pointer(S) {} public: @@ -57,16 +54,16 @@ template class Symbol { } private: - std::shared_ptr Library; + std::shared_ptr Library; T *Pointer = nullptr; }; template class Symbol { private: - friend class Loader::SharedLibrary; + friend class Executable; template friend class Symbol; - Symbol(std::shared_ptr H, T (*S)[]) noexcept + Symbol(std::shared_ptr H, T (*S)[]) noexcept : Library(std::move(H)), Pointer(*S) {} public: @@ -88,7 +85,7 @@ template class Symbol { } private: - std::shared_ptr Library; + std::shared_ptr Library; T *Pointer = nullptr; }; diff --git a/include/common/types.h b/include/common/types.h index a13cd555c94e..e0614486e83f 100644 --- a/include/common/types.h +++ b/include/common/types.h @@ -61,20 +61,22 @@ using doublex2_t = SIMDArray; using floatx4_t = SIMDArray; // 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,6 +127,7 @@ 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; @@ -136,14 +141,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 +213,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 +228,76 @@ 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: + 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 +360,8 @@ class BlockType { /// FuncRef definition. namespace Runtime::Instance { class FunctionInstance; +class StructInstance; +class ArrayInstance; } // namespace Runtime::Instance /// NumType and RefType variant definitions. @@ -317,9 +376,18 @@ struct RefVariant { template RefVariant(const T *P) noexcept { setData(TypeCode::ExternRef, reinterpret_cast(P)); } + template RefVariant(const ValType &VT, const T *P) noexcept { + setData(VT, reinterpret_cast(P)); + } RefVariant(const Runtime::Instance::FunctionInstance *P) noexcept { setData(TypeCode::FuncRef, reinterpret_cast(P)); } + RefVariant(const Runtime::Instance::StructInstance *P) noexcept { + setData(TypeCode::StructRef, reinterpret_cast(P)); + } + RefVariant(const Runtime::Instance::ArrayInstance *P) noexcept { + setData(TypeCode::ArrayRef, reinterpret_cast(P)); + } // Getter of type. const ValType &getType() const noexcept { diff --git a/include/driver/compiler.h b/include/driver/compiler.h index ca86b813a056..07bc64ff1083 100644 --- a/include/driver/compiler.h +++ b/include/driver/compiler.h @@ -53,6 +53,8 @@ struct DriverCompilerOptions { 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)), PropAll(PO::Description("Enable all features"sv)), PropOptimizationLevel( PO::Description("Optimization level, one of 0, 1, 2, 3, s, z."sv), @@ -78,6 +80,7 @@ struct DriverCompilerOptions { PO::Option PropTailCall; PO::Option PropExtendConst; PO::Option PropThreads; + PO::Option PropFunctionReference; PO::Option PropAll; PO::Option PropOptimizationLevel; @@ -102,6 +105,7 @@ struct DriverCompilerOptions { .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-all"sv, PropAll) .add_option("optimize"sv, PropOptimizationLevel); } diff --git a/include/driver/tool.h b/include/driver/tool.h index 63cafb655908..cf9515e4ad1f 100644 --- a/include/driver/tool.h +++ b/include/driver/tool.h @@ -62,8 +62,11 @@ struct DriverToolOptions { 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)), PropComponent(PO::Description( "Enable Component Model proposal, this is experimental"sv)), + PropExceptionHandling( + PO::Description("Enable Exception handling proposal"sv)), PropAll(PO::Description("Enable all features"sv)), ConfEnableInstructionCounting(PO::Description( "Enable generating code for counting Wasm instructions executed."sv)), @@ -73,6 +76,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( @@ -108,12 +113,15 @@ struct DriverToolOptions { PO::Option PropExtendConst; PO::Option PropThreads; PO::Option PropFunctionReference; + PO::Option PropGC; PO::Option PropComponent; + PO::Option PropExceptionHandling; PO::Option PropAll; PO::Option ConfEnableInstructionCounting; PO::Option ConfEnableGasMeasuring; PO::Option ConfEnableTimeMeasuring; PO::Option ConfEnableAllStatistics; + PO::Option ConfEnableJIT; PO::Option ConfForceInterpreter; PO::Option TimeLim; PO::List GasLim; @@ -131,6 +139,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) @@ -145,7 +154,9 @@ struct DriverToolOptions { .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-component"sv, PropComponent) + .add_option("enable-exception-handling"sv, PropExceptionHandling) .add_option("enable-all"sv, PropAll) .add_option("time-limit"sv, TimeLim) .add_option("gas-limit"sv, GasLim) 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..443730303c2b 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 @@ -114,7 +114,8 @@ class GraphService final : public wasi_ephemeral_nn::Graph::Service { 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( + 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) @@ -131,6 +132,48 @@ class GraphService final : public wasi_ephemeral_nn::Graph::Service { return grpc::Status::OK; } + /* + Expect + 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( + Name.size()); // does not include the '\0' terminator + uint32_t ConfigPtr = static_cast( + 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 NameVec(Name.begin(), Name.end()); + std::vector 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(FuncName, Errno); + } + uint32_t GraphHandle = *MemInst.getPointer(OutPtr); + RPCResult->set_graph_handle(GraphHandle); + return grpc::Status::OK; + } + private: const Runtime::Instance::ModuleInstance &NNMod; }; @@ -191,7 +234,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(TensorData.size()); /* clang-format off */ /** diff --git a/include/executor/executor.h b/include/executor/executor.h index 1107313a5282..b63366cdf443 100644 --- a/include/executor/executor.h +++ b/include/executor/executor.h @@ -187,6 +187,10 @@ class Executor { atomicNotifyAll(); } + // [qdrvm] + Expect dataSegmentOffset(Runtime::StackManager &StackMgr, + const AST::DataSegment &DataSeg); + private: /// Run Wasm bytecode expression for initialization. Expect runExpression(Runtime::StackManager &StackMgr, @@ -228,6 +232,10 @@ class Executor { Expect instantiate(Runtime::Instance::ModuleInstance &ModInst, const AST::MemorySection &MemSec); + /// Instantiateion of Tag Instances. + Expect instantiate(Runtime::Instance::ModuleInstance &ModInst, + const AST::TagSection &TagSec); + /// Instantiation of Global Instances. Expect instantiate(Runtime::StackManager &StackMgr, Runtime::Instance::ModuleInstance &ModInst, @@ -266,26 +274,21 @@ class Executor { /// Helper function for branching to label. Expect 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 Exp, - const Runtime::Instance::ModuleInstance &ModGot, - Span Got) const noexcept; + /// Helper function for throwing an exception. + Expect 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; @@ -298,6 +301,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; @@ -309,6 +316,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 @@ -317,21 +331,31 @@ class Executor { Expect runIfElseOp(Runtime::StackManager &StackMgr, const AST::Instruction &Instr, AST::InstrView::iterator &PC) noexcept; + Expect runThrowOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept; + Expect runThrowRefOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept; Expect runBrOp(Runtime::StackManager &StackMgr, const AST::Instruction &Instr, AST::InstrView::iterator &PC) noexcept; Expect runBrIfOp(Runtime::StackManager &StackMgr, const AST::Instruction &Instr, AST::InstrView::iterator &PC) noexcept; - Expect runBrOnNull(Runtime::StackManager &StackMgr, - const AST::Instruction &Instr, - AST::InstrView::iterator &PC) noexcept; - Expect runBrOnNonNull(Runtime::StackManager &StackMgr, - const AST::Instruction &Instr, - AST::InstrView::iterator &PC) noexcept; + Expect runBrOnNullOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept; + Expect runBrOnNonNullOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept; Expect runBrTableOp(Runtime::StackManager &StackMgr, const AST::Instruction &Instr, AST::InstrView::iterator &PC) noexcept; + Expect runBrOnCastOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC, + bool IsReverse = false) noexcept; Expect runReturnOp(Runtime::StackManager &StackMgr, AST::InstrView::iterator &PC) noexcept; Expect runCallOp(Runtime::StackManager &StackMgr, @@ -346,6 +370,9 @@ class Executor { const AST::Instruction &Instr, AST::InstrView::iterator &PC, bool IsTailCall = false) noexcept; + Expect runTryTableOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept; /// ======= Variable instructions ======= Expect runLocalGetOp(Runtime::StackManager &StackMgr, uint32_t StackOffset) const noexcept; @@ -357,6 +384,76 @@ class Executor { uint32_t Idx) const noexcept; Expect runGlobalSetOp(Runtime::StackManager &StackMgr, uint32_t Idx) const noexcept; + /// ======= Reference instructions ======= + Expect runRefNullOp(Runtime::StackManager &StackMgr, + const ValType &Type) const noexcept; + Expect runRefIsNullOp(ValVariant &Val) const noexcept; + Expect runRefFuncOp(Runtime::StackManager &StackMgr, + uint32_t Idx) const noexcept; + Expect runRefEqOp(ValVariant &Val1, + const ValVariant &Val2) const noexcept; + Expect runRefAsNonNullOp(RefVariant &Val, + const AST::Instruction &Instr) const noexcept; + Expect runStructNewOp(Runtime::StackManager &StackMgr, + const uint32_t DefIndex, + bool IsDefault = false) const noexcept; + Expect runStructGetOp(ValVariant &Val, const uint32_t Idx, + const AST::CompositeType &CompType, + const AST::Instruction &Instr, + bool IsSigned = false) const noexcept; + Expect runStructSetOp(const ValVariant &Val, const RefVariant &InstRef, + const AST::CompositeType &CompType, uint32_t Idx, + const AST::Instruction &Instr) const noexcept; + Expect runArrayNewOp(Runtime::StackManager &StackMgr, + const uint32_t DefIndex, uint32_t InitCnt, + uint32_t ValCnt) const noexcept; + Expect + runArrayNewDataOp(Runtime::StackManager &StackMgr, + const Runtime::Instance::DataInstance &DataInst, + const AST::Instruction &Instr) const noexcept; + Expect + runArrayNewElemOp(Runtime::StackManager &StackMgr, + const Runtime::Instance::ElementInstance &ElemInst, + const AST::Instruction &Instr) const noexcept; + Expect runArraySetOp(const ValVariant &Val, const uint32_t Idx, + const RefVariant &InstRef, + const AST::CompositeType &CompType, + const AST::Instruction &Instr) const noexcept; + Expect runArrayGetOp(ValVariant &Val, const uint32_t Idx, + const AST::CompositeType &CompType, + const AST::Instruction &Instr, + bool IsSigned = false) const noexcept; + Expect runArrayLenOp(ValVariant &Val, + const AST::Instruction &Instr) const noexcept; + Expect runArrayFillOp(uint32_t N, const ValVariant &Val, uint32_t D, + const RefVariant &InstRef, + const AST::CompositeType &CompType, + const AST::Instruction &Instr) const noexcept; + Expect 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 + 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 + 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 runRefTestOp(const Runtime::Instance::ModuleInstance *ModInst, + ValVariant &Val, const AST::Instruction &Instr, + bool IsCast = false) const noexcept; + Expect runRefConvOp(RefVariant &Val, TypeCode TCode) const noexcept; + Expect runRefI31Op(ValVariant &Val) const noexcept; + Expect runI31GetOp(ValVariant &Val, const AST::Instruction &Instr, + bool IsSigned = false) const noexcept; /// ======= Table instructions ======= Expect runTableGetOp(Runtime::StackManager &StackMgr, Runtime::Instance::TableInstance &TabInst, @@ -703,7 +800,7 @@ class Executor { template struct ProxyHelper; /// Callbacks for compiled modules - static const AST::Module::IntrinsicsTable Intrinsics; + static const Executable::IntrinsicsTable Intrinsics; private: template @@ -751,6 +848,25 @@ class Executor { std::atomic_uint32_t *StopToken; }; + struct SavedThreadLocal { + SavedThreadLocal() + : SavedThis(This), SavedCurrentStack(CurrentStack), + SavedExecutionContext(ExecutionContext) {} + + SavedThreadLocal(const SavedThreadLocal &) = delete; + SavedThreadLocal(SavedThreadLocal &&) = delete; + + ~SavedThreadLocal() { + This = SavedThis; + CurrentStack = SavedCurrentStack; + ExecutionContext = SavedExecutionContext; + } + + Executor *SavedThis; + Runtime::StackManager *SavedCurrentStack; + ExecutionContextStruct SavedExecutionContext; + }; + /// Pointer to current object. static thread_local Executor *This; /// Stack for passing into compiled functions diff --git a/include/experimental/expected.hpp b/include/experimental/expected.hpp index 1242e52332cc..61fdb5a670e2 100644 --- a/include/experimental/expected.hpp +++ b/include/experimental/expected.hpp @@ -1615,7 +1615,14 @@ class expected : public detail::expected_move_assign_base, } 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(std::move(error()))); +#if defined(_MSC_VER) +#pragma warning(pop) +#endif } return std::move(impl_base::val()); } @@ -1627,7 +1634,14 @@ class expected : public detail::expected_move_assign_base, } constexpr rvalue_reference_type value() && { if (!has_value()) { +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:5272) +#endif throw(bad_expected_access(std::move(error()))); +#if defined(_MSC_VER) +#pragma warning(pop) +#endif } return std::move(impl_base::val()); } diff --git a/include/host/mock/log.h b/include/host/mock/log.h index d25c2cc57f04..6978b260c0b1 100644 --- a/include/host/mock/log.h +++ b/include/host/mock/log.h @@ -5,7 +5,7 @@ #include -#include "common/log.h" +#include "common/spdlog.h" namespace WasmEdge { namespace Host { diff --git a/include/host/wasi/error.h b/include/host/wasi/error.h index 3c294d54e1fc..9fc889761e4c 100644 --- a/include/host/wasi/error.h +++ b/include/host/wasi/error.h @@ -4,7 +4,7 @@ #pragma once #include "common/expected.h" -#include "common/log.h" +#include "common/spdlog.h" #include "wasi/api.hpp" #include diff --git a/include/host/wasi/inode.h b/include/host/wasi/inode.h index c53ce420be3c..286c7fc46e8a 100644 --- a/include/host/wasi/inode.h +++ b/include/host/wasi/inode.h @@ -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 { diff --git a/include/llvm/codegen.h b/include/llvm/codegen.h new file mode 100644 index 000000000000..48a9de813773 --- /dev/null +++ b/include/llvm/codegen.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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 + +namespace WasmEdge::LLVM { + +/// Compiling LLVM Module into loadable executable binary. +class CodeGen { +public: + CodeGen(const Configure &Conf) noexcept : Conf(Conf) {} + Expect codegen(Span 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 80% rename from include/aot/compiler.h rename to include/llvm/compiler.h index 3ace24de2729..e603039eb5d6 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 -//===-- 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 -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 compile(Span Data, const AST::Module &Module, - std::filesystem::path OutputPath) noexcept; + Expect 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..22594d0ad04f --- /dev/null +++ b/include/llvm/data.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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 + +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 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..78e3c5ec9bc6 --- /dev/null +++ b/include/llvm/jit.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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 + +namespace WasmEdge::LLVM { +class OrcLLJIT; + +class JITLibrary : public Executable { +public: + JITLibrary(OrcLLJIT JIT) noexcept; + ~JITLibrary() noexcept override; + + Symbol getIntrinsics() noexcept override; + + std::vector> getTypes(size_t Size) noexcept override; + + std::vector> getCodes(size_t Offset, + size_t Size) noexcept override; + +private: + OrcLLJIT *J; +}; + +class JIT { +public: + JIT(const Configure &Conf) noexcept : Conf(Conf) {} + Expect> 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..b6666bf965f6 --- /dev/null +++ b/include/loader/aot_section.h @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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 +#include +#include + +namespace WasmEdge { +namespace Loader { + +/// Holder class for library handle +class AOTSection : public Executable { +public: + AOTSection() noexcept = default; + ~AOTSection() noexcept override { unload(); } + Expect load(const AST::AOTSection &AOTSec) noexcept; + void unload() noexcept; + + Symbol getIntrinsics() noexcept override { + if (Binary) { + return createSymbol( + getPointer(IntrinsicsAddress)); + } + return {}; + } + + std::vector> getTypes(size_t) noexcept override { + std::vector> Result; + if (Binary) { + Result.reserve(TypesAddress.size()); + for (const auto Address : TypesAddress) { + Result.push_back(createSymbol(getPointer(Address))); + } + } + return Result; + } + + std::vector> getCodes(size_t, size_t) noexcept override { + std::vector> Result; + if (Binary) { + Result.reserve(CodesAddress.size()); + for (const auto Address : CodesAddress) { + Result.push_back(createSymbol(getPointer(Address))); + } + } + return Result; + } + +private: + uintptr_t getOffset() const noexcept { + return reinterpret_cast(Binary); + } + + template T *getPointer(uint64_t Address) const noexcept { + return reinterpret_cast(getOffset() + Address); + } + + uint8_t *Binary = nullptr; + uint64_t BinarySize = 0; + uint64_t IntrinsicsAddress = 0; + std::vector TypesAddress; + std::vector 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..596d62ac56c8 100644 --- a/include/loader/filemgr.h +++ b/include/loader/filemgr.h @@ -86,6 +86,9 @@ class FileMgr { /// Read a string, which is size(unsigned int) + bytes. Expect readName(); + /// Peek one byte. + Expect 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 -#include -#include - -namespace WasmEdge { - -/// Loadable manager interface. -class LDMgr { -public: - LDMgr(const void *IT = nullptr) : Intrinsics(IT) {} - - /// Set the file path. - Expect setPath(const std::filesystem::path &FilePath); - - /// Read embedded Wasm binary. - Expect> getWasm(); - - /// Read wasmedge version. - Expect getVersion(); - - /// Get symbol. - template auto getSymbol(const char *Name) noexcept { - return Library->get(Name); - } - - /// Reset status. - void reset() noexcept { - Intrinsics = nullptr; - Library.reset(); - } - -private: - std::shared_ptr Library; - const void *Intrinsics; -}; - -} // namespace WasmEdge diff --git a/include/loader/loader.h b/include/loader/loader.h index 0aa2b0d946c4..b5b2aaa7b5e1 100644 --- a/include/loader/loader.h +++ b/include/loader/loader.h @@ -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 #include @@ -73,6 +73,18 @@ template <> inline ASTNodeAttr NodeAttrFromAST() noexcept { return ASTNodeAttr::Sec_DataCount; } +template <> inline ASTNodeAttr NodeAttrFromAST() noexcept { + return ASTNodeAttr::Type_Rec; +} +template <> inline ASTNodeAttr NodeAttrFromAST() noexcept { + return ASTNodeAttr::Type_Function; +} +template <> inline ASTNodeAttr NodeAttrFromAST() noexcept { + return ASTNodeAttr::Seg_Element; +} +template <> inline ASTNodeAttr NodeAttrFromAST() noexcept { + return ASTNodeAttr::Sec_Tag; +} template <> inline ASTNodeAttr NodeAttrFromAST() noexcept { return ASTNodeAttr::Sec_Alias; @@ -126,8 +138,8 @@ NodeAttrFromAST() 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> 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 loadExecutable(AST::Module &Mod, + std::shared_ptr 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::unique_ptr>> loadUnit(); Expect, std::vector>> loadPreamble(); - - /// \name Load AST Component functions - /// @{ - Expect loadComponent(AST::Component::Component &Comp); - /// @} - - /// \name Load AST Module functions - /// @{ Expect loadModule(AST::Module &Mod); Expect loadModuleInBound(AST::Module &Mod, std::optional Bound); - Expect loadCompiled(AST::Module &Mod); + Expect loadUniversalWASM(AST::Module &Mod); + Expect loadModuleAOT(AST::AOTSection &AOTSection); + Expect loadComponent(AST::Component::Component &Comp); /// @} /// \name Load AST section node helper functions /// @{ - Expect loadUniversalWASM(AST::Module &Mod); - Expect loadModuleAOT(AST::AOTSection &AOTSection); - - Expect loadSectionSize(ASTNodeAttr Node); - template - Expect loadSectionContent(T &Sec, L &&Func) { - Sec.setStartOffset(FMgr.getOffset()); - if (auto Res = loadSectionSize(NodeAttrFromAST())) { - // 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()); + Expect 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 - Expect loadSectionContentVec(T &Sec, L &&Func) { + + template + Expect loadVec(std::vector &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()); - } - Sec.getContent().resize(VecCnt); + Vec.resize(*Res); } else { return logLoadError(Res.error(), FMgr.getLastOffset(), - NodeAttrFromAST()); + NodeAttrFromAST()); } // 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())); + if (auto Res = Func(Vec[I]); !Res) { + spdlog::error(ErrInfo::InfoAST(NodeAttrFromAST())); return Unexpect(Res); } } return {}; } - template - Expect loadVec(std::vector &Vec, L &&Func) { - uint32_t VecCnt = 0; - // Read the vector size. + template + Expect 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()); } - 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()); + } } else { return logLoadError(Res.error(), FMgr.getLastOffset(), NodeAttrFromAST()); } + 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())); - 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 + Expect loadSectionContentVec(T &Sec, ElemLoader &&Func) { + return loadVec(Sec.getContent(), std::move(Func)); } + /// @} /// \name Load AST nodes functions /// @{ @@ -300,6 +308,7 @@ class Loader { Expect loadSection(AST::CodeSection &Sec); Expect loadSection(AST::DataSection &Sec); Expect loadSection(AST::DataCountSection &Sec); + Expect loadSection(AST::TagSection &Sec); Expect loadSection(AST::Component::ComponentSection &Sec); Expect loadSection(AST::CoreModuleSection &Sec); Expect loadSection(AST::Component::CoreInstanceSection &Sec); @@ -307,6 +316,7 @@ class Loader { Expect loadSection(AST::Component::AliasSection &Sec); Expect loadSection(AST::Component::CoreTypeSection &Sec); Expect loadSection(AST::Component::TypeSection &Sec); + Expect loadSection(AST::Component::StartSection &Sec); Expect loadSection(AST::Component::CanonSection &Sec); Expect loadSection(AST::Component::ImportSection &Sec); Expect loadSection(AST::Component::ExportSection &Sec); @@ -326,12 +336,17 @@ class Loader { Expect loadDesc(AST::ExportDesc &ExpDesc); Expect loadHeapType(TypeCode TC, ASTNodeAttr From); Expect loadRefType(ASTNodeAttr From); - Expect loadValType(ASTNodeAttr From); + Expect loadValType(ASTNodeAttr From, bool IsStorageType = false); + Expect loadMutability(ASTNodeAttr From); + Expect loadFieldType(AST::FieldType &FType); + Expect loadCompositeType(AST::CompositeType &CType); Expect loadLimit(AST::Limit &Lim); + Expect loadType(AST::SubType &SType); Expect loadType(AST::FunctionType &FuncType); Expect loadType(AST::MemoryType &MemType); Expect loadType(AST::TableType &TabType); Expect loadType(AST::GlobalType &GlobType); + Expect loadType(AST::TagType &TgType); Expect loadType(AST::Component::DefType &Ty); Expect 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..fa71dfaea935 100644 --- a/include/loader/serialize.h +++ b/include/loader/serialize.h @@ -88,6 +88,8 @@ class Serializer { std::vector &OutVec) const noexcept; Expect serializeLimit(const AST::Limit &Lim, std::vector &OutVec) const noexcept; + Expect serializeType(const AST::SubType &SType, + std::vector &OutVec) const noexcept; Expect serializeType(const AST::FunctionType &Type, std::vector &OutVec) const noexcept; Expect serializeType(const AST::TableType &Type, diff --git a/include/loader/shared_library.h b/include/loader/shared_library.h index ea765d13b1fc..d376a69c4da8 100644 --- a/include/loader/shared_library.h +++ b/include/loader/shared_library.h @@ -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 @@ -29,12 +27,7 @@ namespace WasmEdge { namespace Loader { /// Holder class for library handle -class SharedLibrary : public std::enable_shared_from_this { - 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 { #endif SharedLibrary() noexcept = default; - ~SharedLibrary() noexcept { unload(); } + ~SharedLibrary() noexcept override { unload(); } Expect load(const std::filesystem::path &Path) noexcept; - Expect load(const AST::AOTSection &AOTSec) noexcept; void unload() noexcept; - template Symbol get(const char *Name) { - return Symbol(shared_from_this(), - reinterpret_cast(getSymbolAddr(Name))); + Symbol getIntrinsics() noexcept override { + return get("intrinsics"); } - uintptr_t getOffset() const noexcept; + std::vector> getTypes(size_t Size) noexcept override { + using namespace std::literals; + std::vector> 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(Name.c_str())) { + Result.push_back(std::move(Symbol)); + } + } - template T *getPointer(uint64_t Address) const noexcept { - return reinterpret_cast(getOffset() + Address); + return Result; } - template Symbol getIntrinsics() noexcept { - if (Binary) { - return Symbol(shared_from_this(), getPointer(IntrinsicsAddress)); + std::vector> getCodes(size_t Offset, + size_t Size) noexcept override { + using namespace std::literals; + std::vector> 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(Name.c_str())) { + Result.push_back(std::move(Symbol)); + } } - return {}; + + return Result; } - template std::vector> getTypes() noexcept { - std::vector> Result; - if (Binary) { - Result.reserve(TypesAddress.size()); - for (const auto Address : TypesAddress) { - Result.push_back(Symbol(shared_from_this(), getPointer(Address))); - } + /// Read embedded Wasm binary. + Expect> getWasm() noexcept { + const auto Size = get("wasm.size"); + if (unlikely(!Size)) { + spdlog::error(ErrCode::Value::IllegalGrammar); + return Unexpect(ErrCode::Value::IllegalGrammar); } - return Result; + const auto Code = get("wasm.code"); + if (unlikely(!Code)) { + spdlog::error(ErrCode::Value::IllegalGrammar); + return Unexpect(ErrCode::Value::IllegalGrammar); + } + + return std::vector(Code.get(), Code.get() + *Size); } - template std::vector> getCodes() noexcept { - std::vector> Result; - if (Binary) { - Result.reserve(CodesAddress.size()); - for (const auto Address : CodesAddress) { - Result.push_back(Symbol(shared_from_this(), getPointer(Address))); - } + /// Read wasmedge version. + Expect getVersion() noexcept { + const auto Version = get("version"); + if (unlikely(!Version)) { + spdlog::error(ErrCode::Value::IllegalGrammar); + return Unexpect(ErrCode::Value::IllegalGrammar); } - return Result; + return *Version; + } + + template Symbol get(const char *Name) { + return createSymbol(reinterpret_cast(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 TypesAddress; - std::vector 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..e89013ad31f3 100644 --- a/include/plugin/plugin.h +++ b/include/plugin/plugin.h @@ -29,6 +29,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 { @@ -105,6 +111,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); @@ -139,8 +146,8 @@ class Plugin { std::filesystem::path path() const noexcept { return Path; } private: - static std::vector &PluginRegistry; - static std::unordered_map &PluginNameLookup; + static std::vector PluginRegistry; + static std::unordered_map PluginNameLookup; std::filesystem::path Path; const PluginDescriptor *Desc = nullptr; @@ -150,18 +157,10 @@ class Plugin { static bool loadFile(const std::filesystem::path &Path) noexcept; - explicit Plugin(const PluginDescriptor *D) noexcept; - public: - WASMEDGE_EXPORT static void + WASMEDGE_EXPORT static bool registerPlugin(const PluginDescriptor *Desc) noexcept; }; -struct PluginRegister { - WASMEDGE_EXPORT PluginRegister(const Plugin::PluginDescriptor *Desc) noexcept; - - WASMEDGE_EXPORT ~PluginRegister() noexcept; -}; - } // namespace Plugin } // namespace WasmEdge diff --git a/include/po/argument_parser.h b/include/po/argument_parser.h index 54d30925abe3..a294d69293de 100644 --- a/include/po/argument_parser.h +++ b/include/po/argument_parser.h @@ -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/runtime/hostfunc.h b/include/runtime/hostfunc.h index 783aa8e3013a..cb100b25a864 100644 --- a/include/runtime/hostfunc.h +++ b/include/runtime/hostfunc.h @@ -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 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 class HostFunction : public HostFunctionBase { } void initializeFuncType() { + auto &FuncType = DefType.getCompositeType().getFuncType(); using F = FuncTraits; using ArgsT = typename F::ArgsT; FuncType.getParamTypes().reserve(F::ArgsN); @@ -145,6 +152,7 @@ template class HostFunction : public HostFunctionBase { template void pushValType(std::index_sequence) { + auto &FuncType = DefType.getCompositeType().getFuncType(); (FuncType.getParamTypes().push_back( ValTypeFromType>()), ...); @@ -152,6 +160,7 @@ template class HostFunction : public HostFunctionBase { template void pushRetType(std::index_sequence) { + auto &FuncType = DefType.getCompositeType().getFuncType(); (FuncType.getReturnTypes().push_back( ValTypeFromType>()), ...); diff --git a/include/runtime/instance/array.h b/include/runtime/instance/array.h new file mode 100644 index 000000000000..446025dea696 --- /dev/null +++ b/include/runtime/instance/array.h @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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 + +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 &&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 getArray() noexcept { return Data; } + Span getArray() const noexcept { return Data; } + + /// Get array length. + uint32_t getLength() const noexcept { + return static_cast(Data.size()); + } + + /// Get boundary index. + uint32_t getBoundIdx() const noexcept { + return std::max(static_cast(Data.size()), UINT32_C(1)) - + UINT32_C(1); + } + +private: + /// \name Data of array instance. + /// @{ + std::vector Data; + /// @} +}; + +} // 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..e8b9024e6a3e --- /dev/null +++ b/include/runtime/instance/composite.h @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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 + +namespace WasmEdge { +namespace Runtime { +namespace Instance { + +class ModuleInstance; + +class CompositeBase { +public: + /// Constructor for only host function instance case. + CompositeBase() noexcept : ModInst(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); + } + + /// Getter of module instance of this instance. + const ModuleInstance *getModule() const noexcept { return ModInst; } + + /// 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) { + return ValType(TypeCode::Ref, TypeIdx); + } else { + // nullptr `ModInst` case is only for host function instance case. + return ValType(TypeCode::Ref, TypeCode::FuncRef); + } + } + +protected: + friend class ModuleInstance; + void linkDefinedType(const ModuleInstance *Mod, + const uint32_t Index) noexcept { + assuming(Mod); + ModInst = Mod; + TypeIdx = Index; + } + + /// \name Data of composite instances. + /// @{ + const ModuleInstance *ModInst; + 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..ae227a1d5351 100644 --- a/include/runtime/instance/data.h +++ b/include/runtime/instance/data.h @@ -34,6 +34,20 @@ class DataInstance { /// Get data in data instance. Span 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(Offset) + static_cast(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/function.h b/include/runtime/instance/function.h index 5730e91afe5f..0ec9845e8b75 100644 --- a/include/runtime/instance/function.h +++ b/include/runtime/instance/function.h @@ -16,6 +16,7 @@ #include "ast/instruction.h" #include "common/symbol.h" #include "runtime/hostfunc.h" +#include "runtime/instance/composite.h" #include #include @@ -28,30 +29,44 @@ 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> Locs, AST::InstrView Expr) noexcept - : ModInst(Mod), FuncType(Type), - Data(std::in_place_type_t(), Locs, Expr) {} + : CompositeBase(Mod, TIdx), FuncType(Type), + Data(std::in_place_type_t(), 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 S) noexcept - : ModInst(Mod), FuncType(Type), - Data(std::in_place_type_t>(), std::move(S)) {} - /// Constructor for host function. - FunctionInstance(const ModuleInstance *Mod, + : CompositeBase(Mod, TIdx), FuncType(Type), + Data(std::in_place_type_t>(), std::move(S)) { + assuming(ModInst); + } + /// Constructors for host function. + FunctionInstance(const ModuleInstance *Mod, const uint32_t TIdx, std::unique_ptr &&Func) noexcept - : ModInst(Mod), FuncType(Func->getFuncType()), + : CompositeBase(Mod, TIdx), FuncType(Func->getFuncType()), + Data(std::in_place_type_t>(), + std::move(Func)) { + assuming(ModInst); + } + FunctionInstance(std::unique_ptr &&Func) noexcept + : CompositeBase(), FuncType(Func->getFuncType()), Data(std::in_place_type_t>(), std::move(Func)) {} @@ -70,9 +85,6 @@ class FunctionInstance { return std::holds_alternative>(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 +136,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, std::unique_ptr> diff --git a/include/runtime/instance/global.h b/include/runtime/instance/global.h index fcbf590ba97f..9915b82de5af 100644 --- a/include/runtime/instance/global.h +++ b/include/runtime/instance/global.h @@ -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..c60788964162 100644 --- a/include/runtime/instance/memory.h +++ b/include/runtime/instance/memory.h @@ -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 diff --git a/include/runtime/instance/module.h b/include/runtime/instance/module.h index d9b3a1a440a8..704dce93c448 100644 --- a/include/runtime/instance/module.h +++ b/include/runtime/instance/module.h @@ -16,12 +16,15 @@ #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 #include @@ -54,7 +57,8 @@ inline constexpr const bool IsEntityV = std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v; + std::is_same_v || + std::is_same_v; /// Return true if T is an instance. template @@ -91,31 +95,35 @@ class ModuleInstance { void addHostFunc(std::string_view Name, std::unique_ptr &&Func) { std::unique_lock Lock(Mutex); - unsafeAddHostInstance(Name, OwnedFuncInsts, FuncInsts, ExpFuncs, - std::make_unique( - this, std::move(Func))); + unsafeImportDefinedType(Func->getDefinedType()); + unsafeAddHostInstance( + Name, OwnedFuncInsts, FuncInsts, ExpFuncs, + std::make_unique( + this, static_cast(Types.size()) - 1, std::move(Func))); } void addHostFunc(std::string_view Name, - std::unique_ptr &&Func) { + std::unique_ptr &&Func) { std::unique_lock Lock(Mutex); - Func->setModule(this); + assuming(Func->isHostFunction()); + unsafeImportDefinedType(Func->getHostFunc().getDefinedType()); + Func->linkDefinedType(this, static_cast(Types.size()) - 1); unsafeAddHostInstance(Name, OwnedFuncInsts, FuncInsts, ExpFuncs, std::move(Func)); } void addHostTable(std::string_view Name, - std::unique_ptr &&Tab) { + std::unique_ptr &&Tab) { std::unique_lock Lock(Mutex); unsafeAddHostInstance(Name, OwnedTabInsts, TabInsts, ExpTables, std::move(Tab)); } void addHostMemory(std::string_view Name, - std::unique_ptr &&Mem) { + std::unique_ptr &&Mem) { std::unique_lock Lock(Mutex); unsafeAddHostInstance(Name, OwnedMemInsts, MemInsts, ExpMems, std::move(Mem)); } void addHostGlobal(std::string_view Name, - std::unique_ptr &&Glob) { + std::unique_ptr &&Glob) { std::unique_lock Lock(Mutex); unsafeAddHostInstance(Name, OwnedGlobInsts, GlobInsts, ExpGlobals, std::move(Glob)); @@ -134,6 +142,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 +164,10 @@ class ModuleInstance { std::shared_lock Lock(Mutex); return static_cast(ExpMems.size()); } + uint32_t getTagExportNum() const noexcept { + std::shared_lock Lock(Mutex); + return static_cast(ExpTags.size()); + } uint32_t getGlobalExportNum() const noexcept { std::shared_lock Lock(Mutex); return static_cast(ExpGlobals.size()); @@ -174,6 +190,11 @@ class ModuleInstance { return std::forward(CallBack)(ExpMems); } template + auto getTagExports(CallbackT &&CallBack) const noexcept { + std::shared_lock Lock(Mutex); + return std::forward(CallBack)(ExpTags); + } + template auto getGlobalExports(CallbackT &&CallBack) const noexcept { std::shared_lock Lock(Mutex); return std::forward(CallBack)(ExpGlobals); @@ -183,10 +204,11 @@ class ModuleInstance { friend class Executor::Executor; 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(SType)); + Types.push_back(OwnedTypes.back().get()); } /// Create and add instances into this module instance. @@ -203,6 +225,10 @@ class ModuleInstance { std::unique_lock Lock(Mutex); unsafeAddInstance(OwnedMemInsts, MemInsts, std::forward(Values)...); } + template void addTag(Args &&...Values) { + std::unique_lock Lock(Mutex); + unsafeAddInstance(OwnedTagInsts, TagInsts, std::forward(Values)...); + } template void addGlobal(Args &&...Values) { std::unique_lock Lock(Mutex); unsafeAddInstance(OwnedGlobInsts, GlobInsts, std::forward(Values)...); @@ -215,6 +241,18 @@ class ModuleInstance { std::unique_lock Lock(Mutex); unsafeAddInstance(OwnedDataInsts, DataInsts, std::forward(Values)...); } + template ArrayInstance *newArray(Args &&...Values) { + std::unique_lock Lock(Mutex); + OwnedArrayInsts.push_back( + std::make_unique(this, std::forward(Values)...)); + return OwnedArrayInsts.back().get(); + } + template StructInstance *newStruct(Args &&...Values) { + std::unique_lock Lock(Mutex); + OwnedStructInsts.push_back( + std::make_unique(this, std::forward(Values)...)); + return OwnedStructInsts.back().get(); + } /// Import instances into this module instance. void importFunction(FunctionInstance *Func) { @@ -229,6 +267,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 +294,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 getTypeList() const noexcept { return Types; } - /// Get function type by index. - Expect getFuncType(uint32_t Idx) const noexcept { + /// Get instance pointer by index. + Expect 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 getFunc(uint32_t Idx) const noexcept { std::shared_lock Lock(Mutex); if (Idx >= FuncInsts.size()) { @@ -297,6 +347,9 @@ class ModuleInstance { MemoryInstance *unsafeGetMemory(uint32_t Idx) const noexcept { return MemInsts[Idx]; } + TagInstance *unsafeGetTag(uint32_t Idx) const noexcept { + return TagInsts[Idx]; + } Expect getGlobal(uint32_t Idx) const noexcept { std::shared_lock Lock(Mutex); if (Idx >= GlobInsts.size()) { @@ -360,13 +413,20 @@ class ModuleInstance { return StartFunc; } - /// Add the instances under the module by pointers. + /// Unsafe import instance into this module. template std::enable_if_t, void> unsafeImportInstance(std::vector &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(Types.back()) + ->setTypeIndex(static_cast(Types.size()) - 1); + } + /// Unsafe create and add the instance into this module. template std::enable_if_t, void> @@ -429,21 +489,26 @@ class ModuleInstance { /// Module name. const std::string ModName; - /// Function types. - std::vector FuncTypes; + /// Defined types. + std::vector Types; + std::vector> OwnedTypes; /// Owned instances in this module. - std::vector> OwnedFuncInsts; - std::vector> OwnedTabInsts; - std::vector> OwnedMemInsts; - std::vector> OwnedGlobInsts; - std::vector> OwnedElemInsts; - std::vector> OwnedDataInsts; + std::vector> OwnedFuncInsts; + std::vector> OwnedTabInsts; + std::vector> OwnedMemInsts; + std::vector> OwnedTagInsts; + std::vector> OwnedGlobInsts; + std::vector> OwnedElemInsts; + std::vector> OwnedDataInsts; + std::vector> OwnedArrayInsts; + std::vector> OwnedStructInsts; /// Imported and added instances in this module. std::vector FuncInsts; std::vector TabInsts; std::vector MemInsts; + std::vector TagInsts; std::vector GlobInsts; std::vector ElemInsts; std::vector DataInsts; @@ -455,6 +520,7 @@ class ModuleInstance { std::map> ExpFuncs; std::map> ExpTables; std::map> ExpMems; + std::map> ExpTags; std::map> ExpGlobals; /// Start function instance. diff --git a/include/runtime/instance/struct.h b/include/runtime/instance/struct.h new file mode 100644 index 000000000000..df6cb1754b41 --- /dev/null +++ b/include/runtime/instance/struct.h @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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 + +namespace WasmEdge { +namespace Runtime { +namespace Instance { + +class StructInstance : public CompositeBase { +public: + StructInstance() = delete; + StructInstance(const ModuleInstance *Mod, const uint32_t Idx, + std::vector &&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 Data; + /// @} +}; + +} // namespace Instance +} // namespace Runtime +} // namespace WasmEdge diff --git a/include/runtime/instance/table.h b/include/runtime/instance/table.h index e2fc29630fa6..9d8251a7e003 100644 --- a/include/runtime/instance/table.h +++ b/include/runtime/instance/table.h @@ -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 #include diff --git a/include/runtime/instance/tag.h b/include/runtime/instance/tag.h new file mode 100644 index 000000000000..6307faffe0f3 --- /dev/null +++ b/include/runtime/instance/tag.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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..385d2655e63b 100644 --- a/include/runtime/stackmgr.h +++ b/include/runtime/stackmgr.h @@ -16,6 +16,7 @@ #include "ast/instruction.h" #include "runtime/instance/module.h" +#include #include 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 C) + : Try(TryIt), VPos(V), CatchClause(C) {} + AST::InstrView::iterator Try; + uint32_t VPos; + Span 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 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 getTopSpan(uint32_t N) { return Span(ValueStack.end() - N, N); } @@ -68,18 +79,32 @@ class StackManager { ValueStack.push_back(std::forward(Val)); } - /// Unsafe Pop and return the top entry. + /// Push a vector of value to stack + void pushValVec(const std::vector &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 pop(uint32_t N) { + std::vector 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(ValueStack.size())); } else { @@ -94,6 +119,7 @@ class StackManager { FrameStack.back().Locals = LocalNum; FrameStack.back().Arity = Arity; FrameStack.back().VPos = static_cast(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 Catch) noexcept { + assuming(!FrameStack.empty()); + FrameStack.back().HandlerStack.emplace_back( + TryIt, static_cast(ValueStack.size()) - BlockParamNum, Catch); + } + + /// Pop the top handler on the stack. + std::optional 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/system/fault.h b/include/system/fault.h index 6b92bec08dac..562f32584ce4 100644 --- a/include/system/fault.h +++ b/include/system/fault.h @@ -15,7 +15,6 @@ #pragma once #include "common/errcode.h" - #include namespace WasmEdge { diff --git a/include/system/winapi.h b/include/system/winapi.h index ee60c6355493..913f872e2242 100644 --- a/include/system/winapi.h +++ b/include/system/winapi.h @@ -1694,4 +1694,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..3af5cf83225d 100644 --- a/include/validator/formchecker.h +++ b/include/validator/formchecker.h @@ -32,14 +32,6 @@ typedef std::optional 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 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 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 Exp, - Span Got) const noexcept; - + /// Control frame struct CtrlFrame { CtrlFrame() = default; CtrlFrame(struct CtrlFrame &&F) @@ -136,7 +126,7 @@ class FormChecker { Expect StackPopAny(); /// Contexts. - std::vector, std::vector>> Types; + std::vector Types; std::vector Funcs; std::vector Tables; uint32_t Mems = 0; @@ -149,6 +139,7 @@ class FormChecker { std::vector Locals; std::vector LocalInits; std::vector Returns; + std::vector Tags; /// Running stack. std::vector CtrlStack; diff --git a/include/validator/validator.h b/include/validator/validator.h index a508ad9af7c4..bde267be62b7 100644 --- a/include/validator/validator.h +++ b/include/validator/validator.h @@ -37,6 +37,7 @@ class Validator { private: /// Validate AST::Types + Expect validate(const AST::SubType &Type); Expect validate(const AST::Limit &Lim); Expect validate(const AST::TableType &Tab); Expect validate(const AST::MemoryType &Mem); @@ -66,6 +67,7 @@ class Validator { Expect validate(const AST::DataSection &DataSec); Expect validate(const AST::StartSection &StartSec); Expect validate(const AST::ExportSection &ExportSec); + Expect validate(const AST::TagSection &TagSec); /// Validate const expression Expect validateConstExpr(AST::InstrView Instrs, diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index a7f09e1c6ada..9d836a12ac9f 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 -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..494055b10f97 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 -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/api/CMakeLists.txt b/lib/api/CMakeLists.txt index 5e8e46e11a2b..44052571d2c2 100644 --- a/lib/api/CMakeLists.txt +++ b/lib/api/CMakeLists.txt @@ -3,8 +3,8 @@ 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() @@ -155,46 +156,57 @@ if(WASMEDGE_BUILD_STATIC_LIB) 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") + set(WASMEDGE_LIBRARY_NAME "libwasmedged.a") + else() + set(WASMEDGE_LIBRARY_NAME "libwasmedge.a") endif() if(CMAKE_AR_NAME STREQUAL "libtool") - add_custom_command(OUTPUT "libwasmedge.a" - COMMAND ${CMAKE_AR} -static -o libwasmedge.a ${WASMEDGE_STATIC_LIB_LIBTOOL_FILES} $ + add_custom_command(OUTPUT "${WASMEDGE_LIBRARY_NAME}" + COMMAND ${CMAKE_AR} -static -o "${WASMEDGE_LIBRARY_NAME}" ${WASMEDGE_STATIC_LIB_LIBTOOL_FILES} $ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${WASMEDGE_STATIC_LIB_DEPS} wasmedgeCAPI ) else() - add_custom_command(OUTPUT "libwasmedge.a" + add_custom_command(OUTPUT "${WASMEDGE_LIBRARY_NAME}" ${WASMEDGE_STATIC_LIB_AR_CMDS} ${WASMEDGE_STATIC_LLVM_LIB_AR_CMDS} - COMMAND ${CMAKE_AR} -qcs libwasmedge.a $ objs/*/*.o + COMMAND ${CMAKE_AR} -qcs "${WASMEDGE_LIBRARY_NAME}" $ objs/*/*.o COMMAND ${CMAKE_COMMAND} -E remove_directory objs WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${WASMEDGE_STATIC_LIB_DEPS} wasmedgeCAPI ) endif() - add_custom_target(wasmedge_static_target ALL DEPENDS "libwasmedge.a") + add_custom_target(wasmedge_static_target ALL DEPENDS "${WASMEDGE_LIBRARY_NAME}") add_library(wasmedge_static STATIC IMPORTED GLOBAL) add_dependencies(wasmedge_static wasmedge_static_target) set_target_properties(wasmedge_static PROPERTIES - IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/libwasmedge.a" - INTERFACE_INCLUDE_DIRECTORIES ${PROJECT_BINARY_DIR}/include/api + IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/${WASMEDGE_LIBRARY_NAME}" + INTERFACE_INCLUDE_DIRECTORIES "${PROJECT_BINARY_DIR}/include/api" ) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libwasmedge.a + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${WASMEDGE_LIBRARY_NAME}" DESTINATION ${CMAKE_INSTALL_LIBDIR} ) - install(FILES ${WASMEDGE_CAPI_HEADERS} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/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 a94d487118f2..bc9525aba205 100644 --- a/lib/api/wasmedge.cpp +++ b/lib/api/wasmedge.cpp @@ -3,8 +3,8 @@ #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 run(const Runtime::CallingFrame &CallFrame, Span Args, Span Rets) override { + auto &FuncType = DefType.getCompositeType().getFuncType(); std::vector 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 { std::filesystem::path InputPath = std::filesystem::absolute(InPath); std::filesystem::path OutputPath = std::filesystem::absolute(OutPath); std::vector Data; std::unique_ptr 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 { std::filesystem::path OutputPath = std::filesystem::absolute(OutPath); auto Data = genSpan(Bytes.Buf, Bytes.Length); std::unique_ptr 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(Res.error()); + return genWasmEdge_Result(Err); + } else if (auto Res2 = JIT.load(std::move(*Res)); !Res2) { + const auto Err = static_cast(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>( "allow-command"sv, std::vector(AllowedCmds, AllowedCmds + CmdsLen)); - Parser.set_raw_value("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(fromFuncTypeCxt(Type), HostFunc, - Data, Cost))); + std::make_unique(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(fromFuncTypeCxt(Type), WrapFunc, - Binding, Data, Cost))); + std::make_unique(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); @@ -3282,6 +3409,37 @@ WASMEDGE_CAPI_EXPORT void WasmEdge_ExecutorExperimentalRegisterPostHostFunction( } // <<<<<<<< WasmEdge Experimental Functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +// >>>>>>>> [qdrvm] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +WASMEDGE_CAPI_EXPORT uint32_t WasmEdge_ASTModuleListDataSegments( + const WasmEdge_ASTModuleContext *Cxt, WasmEdge_DataSegment *Segments, + const uint32_t Len) { + if (!Cxt) { + return 0; + } + const auto &DataSegSpan = fromASTModCxt(Cxt)->getDataSection().getContent(); + WasmEdge::Configure Conf; + WasmEdge::Executor::Executor Executor{Conf}; + WasmEdge::Runtime::StackManager StackMgr; + uint32_t I = 0; + for (const auto &DataSeg : DataSegSpan) { + auto Offset = Executor.dataSegmentOffset(StackMgr, DataSeg); + if (!Offset) { + return 0; + } + if (I < Len) { + Segments[I].Offset = Offset.value(); + Segments[I].Data = DataSeg.getData().data(); + Segments[I].Length = DataSeg.getData().size(); + } + ++I; + } + return DataSegSpan.size(); +} + +// <<<<<<<< [qdrvm] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/common/CMakeLists.txt b/lib/common/CMakeLists.txt index 7207ec0813e8..6a05e75a0200 100644 --- a/lib/common/CMakeLists.txt +++ b/lib/common/CMakeLists.txt @@ -1,39 +1,14 @@ # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: 2019-2022 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 ) diff --git a/lib/common/errinfo.cpp b/lib/common/errinfo.cpp index f2bd01bfea24..188a183602d7 100644 --- a/lib/common/errinfo.cpp +++ b/lib/common/errinfo.cpp @@ -305,7 +305,7 @@ fmt::formatter::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/log.cpp b/lib/common/spdlog.cpp similarity index 95% rename from lib/common/log.cpp rename to lib/common/spdlog.cpp index c3af5bfe8d06..a6da7c1743f7 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 -#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..1a6b947864f1 100644 --- a/lib/driver/CMakeLists.txt +++ b/lib/driver/CMakeLists.txt @@ -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..7a4318aafa29 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 -#include "aot/compiler.h" #include "common/configure.h" #include "common/defines.h" #include "common/filesystem.h" @@ -9,6 +8,8 @@ #include "driver/compiler.h" #include "loader/loader.h" #include "validator/validator.h" +#include "llvm/codegen.h" +#include "llvm/compiler.h" #include #include #include @@ -26,7 +27,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()) { @@ -154,11 +155,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(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(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..987b0b7e2937 100644 --- a/lib/driver/fuzzPO.cpp +++ b/lib/driver/fuzzPO.cpp @@ -3,7 +3,7 @@ #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" diff --git a/lib/driver/fuzzTool.cpp b/lib/driver/fuzzTool.cpp index 83ffcc8bcc89..0b4974dff6fd 100644 --- a/lib/driver/fuzzTool.cpp +++ b/lib/driver/fuzzTool.cpp @@ -3,10 +3,11 @@ #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(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(Res.error()); spdlog::error("Compilation failed. Error code: {}"sv, Err); return EXIT_FAILURE; + } else if (auto Res2 = CodeGen.codegen(Span(Data, Size), + std::move(*Res), "/dev/null"sv); + !Res2) { + const auto Err = static_cast(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..33d8a2b55e3a 100644 --- a/lib/driver/runtimeTool.cpp +++ b/lib/driver/runtimeTool.cpp @@ -3,7 +3,7 @@ #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" @@ -68,15 +68,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 Timeout; @@ -108,6 +120,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); } diff --git a/lib/driver/uniTool.cpp b/lib/driver/uniTool.cpp index 03f4af7c3ccb..06db2ae2ac93 100644 --- a/lib/driver/uniTool.cpp +++ b/lib/driver/uniTool.cpp @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: 2019-2022 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" diff --git a/lib/driver/wasiNNRPCServerTool.cpp b/lib/driver/wasiNNRPCServerTool.cpp index a760f06d9673..c3e52868a13f 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" diff --git a/lib/executor/CMakeLists.txt b/lib/executor/CMakeLists.txt index 79c3b978fddf..9b5238f89a39 100644 --- a/lib/executor/CMakeLists.txt +++ b/lib/executor/CMakeLists.txt @@ -11,12 +11,14 @@ wasmedge_add_library(wasmedgeExecutor instantiate/data.cpp instantiate/export.cpp instantiate/module.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..6c53c63df022 100644 --- a/lib/executor/engine/controlInstr.cpp +++ b/lib/executor/engine/controlInstr.cpp @@ -33,12 +33,32 @@ Expect Executor::runIfElseOp(Runtime::StackManager &StackMgr, return {}; } +Expect 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 Executor::runThrowRefOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept { + const auto Ref = StackMgr.pop().get(); + 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(); + return throwException(StackMgr, *TagInst, PC); +} + Expect 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 Executor::runBrIfOp(Runtime::StackManager &StackMgr, @@ -50,9 +70,9 @@ Expect Executor::runBrIfOp(Runtime::StackManager &StackMgr, return {}; } -Expect Executor::runBrOnNull(Runtime::StackManager &StackMgr, - const AST::Instruction &Instr, - AST::InstrView::iterator &PC) noexcept { +Expect Executor::runBrOnNullOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept { if (StackMgr.getTop().get().isNull()) { StackMgr.pop(); return runBrOp(StackMgr, Instr, PC); @@ -60,9 +80,9 @@ Expect Executor::runBrOnNull(Runtime::StackManager &StackMgr, return {}; } -Expect Executor::runBrOnNonNull(Runtime::StackManager &StackMgr, - const AST::Instruction &Instr, - AST::InstrView::iterator &PC) noexcept { +Expect Executor::runBrOnNonNullOp(Runtime::StackManager &StackMgr, + const AST::Instruction &Instr, + AST::InstrView::iterator &PC) noexcept { if (!StackMgr.getTop().get().isNull()) { return runBrOp(StackMgr, Instr, PC); } @@ -80,13 +100,35 @@ Expect Executor::runBrTableOp(Runtime::StackManager &StackMgr, auto LabelTable = Instr.getLabelList(); const auto LabelTableSize = static_cast(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 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(); + const auto &VT = Val.getType(); + Span GotTypeList = ModInst->getTypeList(); + if (!VT.isAbsHeapType()) { + auto *Inst = Val.getPtr(); + // 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 Executor::runReturnOp(Runtime::StackManager &StackMgr, @@ -105,8 +147,7 @@ Expect 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 Executor::runCallRefOp(Runtime::StackManager &StackMgr, const AST::Instruction &Instr, AST::InstrView::iterator &PC, bool IsTailCall) noexcept { - const auto Ref = StackMgr.pop().get(); if (Ref.isNull()) { spdlog::error(ErrCode::Value::AccessNullFunc); @@ -147,7 +187,7 @@ Expect 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(); @@ -173,18 +213,28 @@ Expect 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()})); 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 Executor::runCallIndirectOp(Runtime::StackManager &StackMgr, return {}; } +Expect 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..e5b54e69b065 100644 --- a/lib/executor/engine/engine.cpp +++ b/lib/executor/engine/engine.cpp @@ -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().getPtr() && + Params[I].get().getType().isNullableRefType()) { + auto Val = Params[I]; + Val.get().getType().toNonNullableRef(); + StackMgr.push(Val); + } else { + StackMgr.push(Params[I]); + } } // Enter and execute function. @@ -85,6 +95,16 @@ Expect Executor::execute(Runtime::StackManager &StackMgr, auto Dispatch = [this, &PC, &StackMgr]() -> Expect { 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 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 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 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().isNull()) { - Val.emplace(UINT32_C(1)); - } else { - Val.emplace(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().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(), 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(); + return runStructSetOp(Val, StructRef, GetDstCompType(), + Instr.getSourceIndex(), Instr); + } + case OpCode::Array__new: + return runArrayNewOp(StackMgr, Instr.getTargetIndex(), 1, + StackMgr.pop().get()); + case OpCode::Array__new_default: + return runArrayNewOp(StackMgr, Instr.getTargetIndex(), 0, + StackMgr.pop().get()); + 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(); + return runArrayGetOp(StackMgr.getTop(), Idx, GetDstCompType(), Instr); + } + case OpCode::Array__get_s: { + const uint32_t Idx = StackMgr.pop().get(); + return runArrayGetOp(StackMgr.getTop(), Idx, GetDstCompType(), Instr, + true); + } + case OpCode::Array__set: { + ValVariant Val = StackMgr.pop(); + const uint32_t Idx = StackMgr.pop().get(); + RefVariant ArrayRef = StackMgr.pop().get(); + 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(); + const ValVariant Val = StackMgr.pop(); + const uint32_t D = StackMgr.pop().get(); + RefVariant ArrayRef = StackMgr.pop().get(); + return runArrayFillOp(N, Val, D, ArrayRef, GetDstCompType(), Instr); + } + case OpCode::Array__copy: { + const uint32_t N = StackMgr.pop().get(); + const uint32_t S = StackMgr.pop().get(); + RefVariant SrcArrayRef = StackMgr.pop().get(); + const uint32_t D = StackMgr.pop().get(); + RefVariant DstArrayRef = StackMgr.pop().get(); + return runArrayCopyOp(N, S, SrcArrayRef, D, DstArrayRef, GetSrcCompType(), + GetDstCompType(), Instr); + } + case OpCode::Array__init_data: { + const uint32_t N = StackMgr.pop().get(); + const uint32_t S = StackMgr.pop().get(); + const uint32_t D = StackMgr.pop().get(); + RefVariant ArrayRef = StackMgr.pop().get(); + return runArrayInitDataOp( + N, S, D, ArrayRef, GetDstCompType(), + *getDataInstByIdx(StackMgr, Instr.getSourceIndex()), Instr); + } + case OpCode::Array__init_elem: { + const uint32_t N = StackMgr.pop().get(); + const uint32_t S = StackMgr.pop().get(); + const uint32_t D = StackMgr.pop().get(); + RefVariant ArrayRef = StackMgr.pop().get(); + 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(), + TypeCode::AnyRef); + case OpCode::Extern__convert_any: + return runRefConvOp(StackMgr.getTop().get(), + 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: diff --git a/lib/executor/engine/proxy.cpp b/lib/executor/engine/proxy.cpp index c2ede34f09b8..bbd9188e43b0 100644 --- a/lib/executor/engine/proxy.cpp +++ b/lib/executor/engine/proxy.cpp @@ -18,11 +18,7 @@ struct Executor::ProxyHelper (Executor::*)(Runtime::StackManager &, ArgsT...) noexcept> { template (Executor::*Func)(Runtime::StackManager &, ArgsT...) noexcept> - static auto proxy(ArgsT... Args) -#if !WASMEDGE_OS_WINDOWS - noexcept -#endif - { + static auto proxy(ArgsT... Args) { Expect Res = (This->*Func)(*CurrentStack, Args...); if (unlikely(!Res)) { Fault::emitFault(Res.error()); @@ -45,14 +41,14 @@ struct Executor::ProxyHelper (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(&Executor::ProxyHelper< \ decltype(&Executor::FUNC)>::proxy<&Executor::FUNC>) #else #define ENTRY(NAME, FUNC) \ - [uint8_t(AST::Module::Intrinsics::NAME)] = reinterpret_cast( \ + [uint8_t(Executable::Intrinsics::NAME)] = reinterpret_cast( \ &Executor::ProxyHelper::proxy< \ &Executor::FUNC>) #endif @@ -142,15 +138,22 @@ Expect 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(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..0782c34c2c4c --- /dev/null +++ b/lib/executor/engine/refInstr.cpp @@ -0,0 +1,576 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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() & 0xFFU); + case TypeCode::I16: + return ValVariant(Val.get() & 0xFFFFU); + default: + assumingUnreachable(); + } + } + return Val; +} + +ValVariant unpackVal(const ValType &Type, const ValVariant &Val, + bool IsSigned = false) { + if (Type.isPackType()) { + uint32_t Num = Val.get(); + switch (Type.getCode()) { + case TypeCode::I8: + if (IsSigned) { + return static_cast(static_cast(Num)); + } else { + return static_cast(static_cast(Num)); + } + case TypeCode::I16: + if (IsSigned) { + return static_cast(static_cast(Num)); + } else { + return static_cast(static_cast(Num)); + } + default: + assumingUnreachable(); + } + } + return Val; +} + +std::vector packVals(const ValType &Type, + std::vector &&Vals) { + for (uint32_t I = 0; I < Vals.size(); I++) { + Vals[I] = packVal(Type, Vals[I]); + } + return std::move(Vals); +} +} // namespace + +Expect 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 Executor::runRefIsNullOp(ValVariant &Val) const noexcept { + Val.emplace(Val.get().isNull() ? 1U : 0U); + return {}; +} + +Expect Executor::runRefFuncOp(Runtime::StackManager &StackMgr, + uint32_t Idx) const noexcept { + const auto *FuncInst = getFuncInstByIdx(StackMgr, Idx); + StackMgr.push(RefVariant(FuncInst->getDefType(), FuncInst)); + return {}; +} + +Expect Executor::runRefEqOp(ValVariant &Val1, + const ValVariant &Val2) const noexcept { + Val1.emplace(Val1.get().getPtr() == + Val2.get().getPtr() + ? 1U + : 0U); + return {}; +} + +Expect +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 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(CompType.getFieldTypes().size()); + std::vector 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(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(StackMgr.getModule()) + ->newStruct(DefIndex, std::move(Vals)); + StackMgr.push(RefVariant(Inst->getDefType(), Inst)); + + return {}; +} + +Expect 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().getPtr(); + 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 +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(); + 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 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(0)); + auto *Inst = + const_cast(StackMgr.getModule()) + ->newArray(DefIndex, ValCnt, InitVal); + StackMgr.push(RefVariant(Inst->getDefType(), Inst)); + } else if (InitCnt == 1) { + auto *Inst = + const_cast(StackMgr.getModule()) + ->newArray(DefIndex, ValCnt, packVal(VType, StackMgr.getTop())); + StackMgr.getTop().emplace(Inst->getDefType(), Inst); + } else { + auto *Inst = + const_cast(StackMgr.getModule()) + ->newArray(DefIndex, packVals(VType, StackMgr.pop(ValCnt))); + StackMgr.push(RefVariant(Inst->getDefType(), Inst)); + } + return {}; +} + +Expect +Executor::runArrayNewDataOp(Runtime::StackManager &StackMgr, + const Runtime::Instance::DataInstance &DataInst, + const AST::Instruction &Instr) const noexcept { + const uint32_t N = StackMgr.pop().get(); + const uint32_t S = StackMgr.getTop().get(); + const auto &CompType = + getDefTypeByIdx(StackMgr, Instr.getTargetIndex())->getCompositeType(); + const uint32_t BSize = + CompType.getFieldTypes()[0].getStorageType().getBitWidth() / 8; + if (static_cast(S) + static_cast(N) * BSize > + DataInst.getData().size()) { + spdlog::error(ErrCode::Value::MemoryOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary( + static_cast(S), N * BSize, + DataInst.getData().size() > 0 + ? static_cast(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(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(Inst->getDefType(), Inst); + return {}; +} + +Expect +Executor::runArrayNewElemOp(Runtime::StackManager &StackMgr, + const Runtime::Instance::ElementInstance &ElemInst, + const AST::Instruction &Instr) const noexcept { + const uint32_t N = StackMgr.pop().get(); + const uint32_t S = StackMgr.getTop().get(); + const auto &CompType = + getDefTypeByIdx(StackMgr, Instr.getTargetIndex())->getCompositeType(); + const auto &SType = CompType.getFieldTypes()[0].getStorageType(); + auto ElemSrc = ElemInst.getRefs(); + if (static_cast(S) + static_cast(N) > ElemSrc.size()) { + spdlog::error(ErrCode::Value::TableOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary( + static_cast(S), N, + ElemSrc.size() > 0 ? static_cast(ElemSrc.size() - 1) : 0U)); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::TableOutOfBounds); + } + std::vector 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(StackMgr.getModule()) + ->newArray(Instr.getTargetIndex(), packVals(SType, std::move(Refs))); + StackMgr.getTop().emplace(Inst->getDefType(), Inst); + return {}; +} + +Expect +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(); + 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 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().getPtr(); + 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 +Executor::runArrayLenOp(ValVariant &Val, + const AST::Instruction &Instr) const noexcept { + const auto *Inst = + Val.get().getPtr(); + if (Inst == nullptr) { + spdlog::error(ErrCode::Value::AccessNullArray); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullArray); + } + Val.emplace(Inst->getLength()); + return {}; +} + +Expect +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(); + if (Inst == nullptr) { + spdlog::error(ErrCode::Value::AccessNullArray); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullArray); + } + if (static_cast(D) + static_cast(N) > Inst->getLength()) { + spdlog::error(ErrCode::Value::ArrayOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary(static_cast(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 +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(); + auto *DstInst = DstInstRef.getPtr(); + 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(S) + static_cast(N) > + SrcInst->getLength()) { + spdlog::error(ErrCode::Value::ArrayOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary(static_cast(S), N, + SrcInst->getBoundIdx())); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::ArrayOutOfBounds); + } + if (static_cast(D) + static_cast(N) > + DstInst->getLength()) { + spdlog::error(ErrCode::Value::ArrayOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary(static_cast(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 +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(); + if (Inst == nullptr) { + spdlog::error(ErrCode::Value::AccessNullArray); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullArray); + } + if (static_cast(D) + static_cast(N) > Inst->getLength()) { + spdlog::error(ErrCode::Value::ArrayOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary(static_cast(D), N, + Inst->getBoundIdx())); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::ArrayOutOfBounds); + } + if (static_cast(S) + static_cast(N) * BSize > + DataInst.getData().size()) { + spdlog::error(ErrCode::Value::MemoryOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary( + static_cast(S), N * BSize, + DataInst.getData().size() > 0 + ? static_cast(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 +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(); + if (Inst == nullptr) { + spdlog::error(ErrCode::Value::AccessNullArray); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::AccessNullArray); + } + if (static_cast(D) + static_cast(N) > Inst->getLength()) { + spdlog::error(ErrCode::Value::ArrayOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary(static_cast(D), N, + Inst->getBoundIdx())); + spdlog::error( + ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); + return Unexpect(ErrCode::Value::ArrayOutOfBounds); + } + if (static_cast(S) + static_cast(N) > ElemSrc.size()) { + spdlog::error(ErrCode::Value::TableOutOfBounds); + spdlog::error(ErrInfo::InfoBoundary( + static_cast(S), N, + ElemSrc.size() > 0 ? static_cast(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 +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().getType(); + if (VT.isExternalized()) { + VT = ValType(TypeCode::Ref, TypeCode::ExternRef); + } + Span GotTypeList = ModInst->getTypeList(); + if (!VT.isAbsHeapType()) { + auto *Inst = + Val.get().getPtr(); + // 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(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(0U); + } + } + return {}; +} + +Expect 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 Executor::runRefI31Op(ValVariant &Val) const noexcept { + uint32_t RefNum = (Val.get() & 0x7FFFFFFFU) | 0x80000000U; + Val = RefVariant(ValType(TypeCode::Ref, TypeCode::I31Ref), + reinterpret_cast(static_cast(RefNum))); + return {}; +} + +Expect Executor::runI31GetOp(ValVariant &Val, + const AST::Instruction &Instr, + bool IsSigned) const noexcept { + uint32_t RefNum = static_cast( + reinterpret_cast(Val.get().getPtr())); + 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(RefNum); + return {}; +} + +} // namespace Executor +} // namespace WasmEdge diff --git a/lib/executor/engine/variableInstr.cpp b/lib/executor/engine/variableInstr.cpp index f57ee4fec1f0..0ea8ae4fd78a 100644 --- a/lib/executor/engine/variableInstr.cpp +++ b/lib/executor/engine/variableInstr.cpp @@ -39,7 +39,7 @@ Expect 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..f7bad204fb64 100644 --- a/lib/executor/executor.cpp +++ b/lib/executor/executor.cpp @@ -4,7 +4,7 @@ #include "executor/executor.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" namespace WasmEdge { namespace Executor { @@ -81,12 +81,18 @@ 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. + WasmEdge::Span 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 +121,40 @@ Executor::invoke(const Runtime::Instance::FunctionInstance *FuncInst, // Get return values. std::vector> 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().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().getPtr(); + 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 ec3ce4d6b2cd..9f6dfea51645 100644 --- a/lib/executor/helper.cpp +++ b/lib/executor/helper.cpp @@ -3,7 +3,7 @@ #include "executor/executor.h" -#include "common/log.h" +#include "common/spdlog.h" #include "system/fault.h" #include @@ -31,6 +31,10 @@ Executor::enterFunction(Runtime::StackManager &StackMgr, const uint32_t RetsN = static_cast(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 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 Rets(RetsN); auto Ret = HostFunc.run(CallFrame, std::move(Args), Rets); @@ -115,6 +124,8 @@ Executor::enterFunction(Runtime::StackManager &StackMgr, Span Args = StackMgr.getTopSpan(ArgsN); std::vector Rets(RetsN); + SavedThreadLocal SavedThreadLocal; + { // Prepare the execution context. auto *ModInst = @@ -131,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(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(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. @@ -181,22 +198,67 @@ Executor::enterFunction(Runtime::StackManager &StackMgr, } } -Expect Executor::branchToLabel(Runtime::StackManager &StackMgr, - uint32_t EraseBegin, uint32_t EraseEnd, - int32_t PCOffset, - AST::InstrView::iterator &PC) noexcept { - // Check stop token +Expect +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 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 { @@ -230,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 { @@ -263,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 Exp, - const Runtime::Instance::ModuleInstance &ModGot, - Span 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(); + Val.emplace(static_cast(0)); + Val.emplace(V); + break; + } + case TypeCode::F32: { + float V = Val.get(); + Val.emplace(static_cast(0)); + Val.emplace(V); + break; + } + case TypeCode::I64: { + uint64_t V = Val.get(); + Val.emplace(static_cast(0)); + Val.emplace(V); + break; + } + case TypeCode::F64: { + double V = Val.get(); + Val.emplace(static_cast(0)); + Val.emplace(V); + break; + } + default: + break; } } - return true; } } // namespace Executor diff --git a/lib/executor/instantiate/data.cpp b/lib/executor/instantiate/data.cpp index 8903dc2babc8..78359b0b27a9 100644 --- a/lib/executor/instantiate/data.cpp +++ b/lib/executor/instantiate/data.cpp @@ -4,7 +4,7 @@ #include "executor/executor.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" #include @@ -94,5 +94,17 @@ Expect Executor::initMemory(Runtime::StackManager &StackMgr, return {}; } +Expect 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)) { + return Unexpect(Res); + } + return StackMgr.pop().get(); + } + return 0; +} + } // namespace Executor } // namespace WasmEdge diff --git a/lib/executor/instantiate/elem.cpp b/lib/executor/instantiate/elem.cpp index 9643b396c465..8e8b1e900474 100644 --- a/lib/executor/instantiate/elem.cpp +++ b/lib/executor/instantiate/elem.cpp @@ -4,7 +4,7 @@ #include "executor/executor.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" #include #include diff --git a/lib/executor/instantiate/export.cpp b/lib/executor/instantiate/export.cpp index d7daa24e6cf5..435f64cb9051 100644 --- a/lib/executor/instantiate/export.cpp +++ b/lib/executor/instantiate/export.cpp @@ -33,6 +33,9 @@ Expect 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..ceb50d49a452 100644 --- a/lib/executor/instantiate/function.cpp +++ b/lib/executor/instantiate/function.cpp @@ -27,17 +27,20 @@ Expect 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/import.cpp b/lib/executor/instantiate/import.cpp index 612a6b8f7913..a6803caf6644 100644 --- a/lib/executor/instantiate/import.cpp +++ b/lib/executor/instantiate/import.cpp @@ -4,7 +4,7 @@ #include "executor/executor.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" #include #include @@ -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 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 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 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 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 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 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 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 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/module.cpp b/lib/executor/instantiate/module.cpp index f6f73d58e8cb..d1e7a98b3d38 100644 --- a/lib/executor/instantiate/module.cpp +++ b/lib/executor/instantiate/module.cpp @@ -4,7 +4,7 @@ #include "executor/executor.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" #include #include @@ -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 TmpModInst = - std::make_unique(""); - 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/tag.cpp b/lib/executor/instantiate/tag.cpp new file mode 100644 index 000000000000..008b9eb24f37 --- /dev/null +++ b/lib/executor/instantiate/tag.cpp @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 Second State INC + +#include "executor/executor.h" + +namespace WasmEdge { +namespace Executor { + +// Instantiate tag instance. See "include/executor/executor.h". +Expect 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/wasi/environ.cpp b/lib/host/wasi/environ.cpp index be0d904704bb..f813923c12a9 100644 --- a/lib/host/wasi/environ.cpp +++ b/lib/host/wasi/environ.cpp @@ -3,7 +3,7 @@ #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..59b3fa5a352d 100644 --- a/lib/host/wasi/inode-linux.cpp +++ b/lib/host/wasi/inode-linux.cpp @@ -87,9 +87,6 @@ constexpr int openFlags(__wasi_oflags_t OpenFlags, __wasi_fdflags_t FdFlags, } // 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::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 INode::fdAdvise(__wasi_filesize_t Offset, WasiExpect 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 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 INode::fdWrite(Span> 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(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::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(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..9dd091b4d5c0 100644 --- a/lib/host/wasi/inode-macos.cpp +++ b/lib/host/wasi/inode-macos.cpp @@ -5,7 +5,7 @@ #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" @@ -78,9 +78,6 @@ constexpr int openFlags(__wasi_oflags_t OpenFlags, __wasi_fdflags_t FdFlags, } // 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::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 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 INode::fdWrite(Span> 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::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..d876fdd54ac8 100644 --- a/lib/host/wasi/inode-win.cpp +++ b/lib/host/wasi/inode-win.cpp @@ -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 { @@ -86,6 +89,10 @@ WasiExpect> inline constexpr getOpenFlags( AttributeFlags |= FILE_FLAG_WRITE_THROUGH_; FdFlags &= ~__WASI_FDFLAGS_DSYNC; } + if (FdFlags & __WASI_FDFLAGS_NONBLOCK) { + // Ignore NONBLOCK flag + FdFlags &= ~__WASI_FDFLAGS_NONBLOCK; + } if (OpenFlags & __WASI_OFLAGS_DIRECTORY) { AttributeFlags |= FILE_ATTRIBUTE_DIRECTORY_; OpenFlags &= ~__WASI_OFLAGS_DIRECTORY; @@ -956,7 +963,7 @@ WasiExpect INode::fdPread(Span> IOVs, Query.OffsetHigh = LocalOffset.HighPart; Query.hEvent = nullptr; if (!ReadFileEx(Handle, IOV.data(), static_cast(IOV.size()), - &Query, nullptr)) { + &Query, &EmptyOverlappedCompletionRoutine)) { if (unlikely(GetLastError() != ERROR_IO_PENDING_)) { Result = WasiUnexpect(detail::fromLastError(GetLastError())); Queries.resize(I); @@ -1005,7 +1012,7 @@ WasiExpect INode::fdPwrite(Span> IOVs, } Query.hEvent = nullptr; if (!WriteFileEx(Handle, IOV.data(), static_cast(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)); @@ -1021,9 +1028,9 @@ WasiExpect INode::fdPwrite(Span> 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))) { + !GetOverlappedResult(Handle, &Query, &NumberOfBytesWrite, true))) { Result = WasiUnexpect(detail::fromLastError(GetLastError())); CancelIo(Handle); for (size_t J = I + 1; J < Queries.size(); ++J) { @@ -1031,7 +1038,7 @@ WasiExpect INode::fdPwrite(Span> IOVs, } break; } - NWritten += NumberOfBytesRead; + NWritten += NumberOfBytesWrite; } return Result; @@ -1055,7 +1062,7 @@ WasiExpect INode::fdRead(Span> IOVs, Query.OffsetHigh = static_cast(LocalOffset.HighPart); Query.hEvent = nullptr; if (!ReadFileEx(Handle, IOV.data(), static_cast(IOV.size()), - &Query, nullptr)) { + &Query, &EmptyOverlappedCompletionRoutine)) { if (unlikely(GetLastError() != ERROR_IO_PENDING_)) { Result = WasiUnexpect(detail::fromLastError(GetLastError())); Queries.resize(I); @@ -1187,7 +1194,7 @@ WasiExpect INode::fdWrite(Span> IOVs, } Query.hEvent = nullptr; if (!WriteFileEx(Handle, IOV.data(), static_cast(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,9 +1210,9 @@ WasiExpect INode::fdWrite(Span> 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))) { + !GetOverlappedResult(Handle, &Query, &NumberOfBytesWrite, true))) { Result = WasiUnexpect(detail::fromLastError(GetLastError())); CancelIo(Handle); for (size_t J = I + 1; J < Queries.size(); ++J) { @@ -1213,7 +1220,7 @@ WasiExpect INode::fdWrite(Span> IOVs, } break; } - NWritten += NumberOfBytesRead; + NWritten += NumberOfBytesWrite; } if (!Append) { @@ -1389,7 +1396,7 @@ WasiExpect INode::pathReadlink(std::string Path, Span 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_); + OPEN_EXISTING_, 0); if (unlikely(!Link.ok())) { return WasiUnexpect(detail::fromLastError(GetLastError())); diff --git a/lib/host/wasi/vinode.cpp b/lib/host/wasi/vinode.cpp index fe3fe70ed477..31bbe4ed8372 100644 --- a/lib/host/wasi/vinode.cpp +++ b/lib/host/wasi/vinode.cpp @@ -3,7 +3,7 @@ #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 @@ -106,7 +106,7 @@ WasiExpect> VINode::bind(__wasi_rights_t FRB, WasiExpect VINode::pathCreateDirectory(std::shared_ptr Fd, std::string_view Path) { std::vector 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); diff --git a/lib/host/wasi/wasifunc.cpp b/lib/host/wasi/wasifunc.cpp index a534f617ede9..440c00549a97 100644 --- a/lib/host/wasi/wasifunc.cpp +++ b/lib/host/wasi/wasifunc.cpp @@ -3,7 +3,7 @@ #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" diff --git a/lib/host/wasi/win.h b/lib/host/wasi/win.h index 1e98edb4ef7e..d13874f4bd54 100644 --- a/lib/host/wasi/win.h +++ b/lib/host/wasi/win.h @@ -208,7 +208,10 @@ using FiletimeDuration = std::chrono::duration< std::ratio_multiply, 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(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..8ac9141a08e0 --- /dev/null +++ b/lib/llvm/CMakeLists.txt @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2022 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..bbb1ff1e9abd --- /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 +#include +#include +#include +#include + +#if LLVM_VERSION_MAJOR >= 14 +#include +#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 +#include +#endif +#if WASMEDGE_OS_WINDOWS +#include +#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 getSDKVersionPair() noexcept { + // TODO: parse SDKSettings.json to get real version + return {UINT32_C(12), UINT32_C(1)}; +} +#endif + +Expect WriteByte(std::ostream &OS, uint8_t Data) noexcept { + OS.put(static_cast(Data)); + return {}; +} + +Expect WriteU32(std::ostream &OS, uint32_t Data) noexcept { + do { + uint8_t Byte = static_cast(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 WriteU64(std::ostream &OS, uint64_t Data) noexcept { + do { + uint8_t Byte = static_cast(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 WriteName(std::ostream &OS, std::string_view Data) noexcept { + WriteU32(OS, static_cast(Data.size())); + for (const auto C : Data) { + WriteByte(OS, static_cast(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 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('%')) { + String[I] = static_cast(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 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(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 { + "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{"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{ + "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 outputWasmLibrary(LLVM::Context LLContext, + const std::filesystem::path &OutputPath, + Span 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(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> 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(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 Types; + std::vector Codes; + uint64_t CodesMin = std::numeric_limits::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::max()) { + Codes.erase(Codes.begin(), + Codes.begin() + static_cast(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 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(Data.data()), + static_cast(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 CodeGen::codegen(Span 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(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 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 57196583df3a..e474d3f7942a 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 #include -#include #include #include #include -#include #include -#include #include #include -#include -#include #include #include #include -#if LLVM_VERSION_MAJOR >= 14 -#include -#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 -#include -#endif -#if WASMEDGE_OS_WINDOWS -#include -#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 getSDKVersionPair() noexcept { - // TODO: parse SDKSettings.json to get real version - return {UINT32_C(12), UINT32_C(1)}; -} -#endif - static bool isVoidReturn(WasmEdge::Span ValTypes) noexcept; -static LLVM::Type toLLVMType(LLVM::Context &LLContext, +static LLVM::Type toLLVMType(LLVM::Context LLContext, const WasmEdge::ValType &ValType) noexcept; static std::vector -toLLVMArgsType(LLVM::Context &LLContext, LLVM::Type ExecCtxPtrTy, +toLLVMArgsType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy, WasmEdge::Span ValTypes) noexcept; static LLVM::Type -toLLVMRetsType(LLVM::Context &LLContext, +toLLVMRetsType(LLVM::Context LLContext, WasmEdge::Span 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 unpackStruct(LLVM::Builder &Builder, LLVM::Value Struct) noexcept; @@ -153,7 +66,7 @@ toLLVMLevel(WasmEdge::CompilerConfigure::OptimizationLevel Level) noexcept { case OL::O0: return "default,function(tailcallelim)"; case OL::O1: - return "default"; + return "default,function(tailcallelim)"; case OL::O2: return "default"; case OL::O3: @@ -209,84 +122,10 @@ static inline LLVMCodeGenOptLevel toLLVMCodeGenLevel( assumingUnreachable(); } } - -WasmEdge::Expect WriteByte(std::ostream &OS, uint8_t Data) noexcept { - OS.put(static_cast(Data)); - return {}; -} - -WasmEdge::Expect WriteU32(std::ostream &OS, uint32_t Data) noexcept { - do { - uint8_t Byte = static_cast(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 WriteU64(std::ostream &OS, uint64_t Data) noexcept { - do { - uint8_t Byte = static_cast(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 WriteName(std::ostream &OS, - std::string_view Data) noexcept { - WriteU32(OS, static_cast(Data.size())); - for (const auto C : Data) { - WriteByte(OS, static_cast(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 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('%')) { - String[I] = static_cast(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 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(AST::Module::Intrinsics::kIntrinsicMax))), + static_cast(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(Index); auto PtrTy = Ty.getPointerTo(); @@ -561,11 +401,11 @@ namespace { using namespace WasmEdge; -static bool isVoidReturn(Span ValTypes) noexcept { +static bool isVoidReturn(Span 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 -toLLVMTypeVector(LLVM::Context &LLContext, +toLLVMTypeVector(LLVM::Context LLContext, Span ValTypes) noexcept { std::vector Result; Result.reserve(ValTypes.size()); @@ -597,14 +437,14 @@ toLLVMTypeVector(LLVM::Context &LLContext, } static std::vector -toLLVMArgsType(LLVM::Context &LLContext, LLVM::Type ExecCtxPtrTy, +toLLVMArgsType(LLVM::Context LLContext, LLVM::Type ExecCtxPtrTy, Span 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 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 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 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> Local; std::vector Stack; LLVM::Value LocalInstrCount = nullptr; @@ -5121,7 +4987,6 @@ class FunctionCompiler { std::unordered_map TrapBB; bool IsUnreachable = false; bool Interruptible = false; - bool OptNone = false; struct Control { size_t StackSize; bool Unreachable; @@ -5162,335 +5027,12 @@ std::vector unpackStruct(LLVM::Builder &Builder, return Ret; } -// Write output object and link -Expect 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(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 { - "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{"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{ - "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 outputWasmLibrary(const std::filesystem::path &OutputPath, - Span 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(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> 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(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 Types; - std::vector Codes; - uint64_t CodesMin = std::numeric_limits::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::max()) { - Codes.erase(Codes.begin(), - Codes.begin() + static_cast(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 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::ofstream OS(OutputPath, std::ios_base::binary); - if (!OS) { - spdlog::error("output failed."); - return Unexpect(ErrCode::Value::IllegalPath); - } - OS.write(reinterpret_cast(Data.data()), - static_cast(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); - return {}; -} - } // namespace namespace WasmEdge { -namespace AOT { +namespace LLVM { -Expect Compiler::compile(Span Data, const AST::Module &Module, - std::filesystem::path OutputPath) noexcept { +Expect Compiler::compile(const AST::Module &Module) noexcept { // Check the module is validated. if (unlikely(!Module.getIsValidated())) { spdlog::error(ErrCode::Value::NotValidated); @@ -5499,26 +5041,17 @@ Expect Compiler::compile(Span 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) { @@ -5545,75 +5078,18 @@ Expect Compiler::compile(Span 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(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; @@ -5627,90 +5103,69 @@ Expect Compiler::compile(Span 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(Executable::Intrinsics::kIntrinsicMax)); + LLModule.addGlobal( + IntrinsicsTableTy.getPointerTo(), false, LLVMExternalLinkage, + LLVM::Value::getConstNull(IntrinsicsTableTy), "intrinsics"); } - return {}; + spdlog::info("optimize done"); + return Expect{std::move(D)}; } void Compiler::compile(const AST::TypeSection &TypeSec) noexcept { @@ -5719,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; } @@ -5729,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 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 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 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 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); } } @@ -5846,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); @@ -5900,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}, @@ -5994,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); @@ -6014,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 LLVM } // namespace WasmEdge diff --git a/lib/llvm/data.cpp b/lib/llvm/data.cpp new file mode 100644 index 000000000000..9590f89b9670 --- /dev/null +++ b/lib/llvm/data.cpp @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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()) {} + +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..da602876d050 --- /dev/null +++ b/lib/llvm/data.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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..01e7cdfa10f5 --- /dev/null +++ b/lib/llvm/jit.cpp @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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(std::move(JIT)).release()) {} + +JITLibrary::~JITLibrary() noexcept { + std::unique_ptr JIT(std::exchange(J, nullptr)); +} + +Symbol +JITLibrary::getIntrinsics() noexcept { + if (auto Symbol = J->lookup("intrinsics")) { + return createSymbol(*Symbol); + } else { + spdlog::error("{}"sv, Symbol.error().message().string_view()); + return {}; + } +} + +std::vector> +JITLibrary::getTypes(size_t Size) noexcept { + std::vector> 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(Name.c_str())) { + Result.push_back(createSymbol(*Symbol)); + } else { + spdlog::error("{}"sv, Symbol.error().message().string_view()); + Result.emplace_back(); + } + } + + return Result; +} + +std::vector> JITLibrary::getCodes(size_t Offset, + size_t Size) noexcept { + std::vector> 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(Name.c_str())) { + Result.push_back(createSymbol(*Symbol)); + } else { + spdlog::error("{}"sv, Symbol.error().message().string_view()); + Result.emplace_back(); + } + } + + return Result; +} + +Expect> 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(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..31ac95d478fb 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 +#pragma once #include "common/errcode.h" #include "common/span.h" @@ -7,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +17,40 @@ #include #include +#if LLVM_VERSION_MAJOR >= 12 +#include +#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 #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 @@ -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(KindID.size()), + C.unwrap(), Kind.data(), static_cast(Kind.size()), Val.data(), static_cast(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 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 + cxx20::expected lookup(const char *Name) noexcept { + LLVMOrcJITTargetAddress Addr; + if (auto Err = LLVMOrcLLJITLookup(Ref, &Addr, Name)) { + return cxx20::unexpected(Err); + } + return reinterpret_cast(Addr); + } + + OrcIRTransformLayer getIRTransformLayer() noexcept { + return LLVMOrcLLJITGetIRTransformLayer(Ref); + } + +private: + LLVMOrcLLJITRef Ref = nullptr; + + static inline LLVMOrcLLJITBuilderRef getBuilder() noexcept; +}; + +} // namespace WasmEdge::LLVM #include #include #include +#if LLVM_VERSION_MAJOR < 12 || WASMEDGE_OS_WINDOWS +#include +#endif +#if LLVM_VERSION_MAJOR < 13 +#include +#include +#include +#endif + +#if WASMEDGE_OS_WINDOWS +#include +#include +#include +#include +#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(reinterpret_cast(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(); + 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(Preallocated.base()); + CodeMem = CodeFree = + llvm::sys::MemoryBlock(reinterpret_cast(base), CodeSize); + base += CodeSize; + RODataMem = RODataFree = + llvm::sys::MemoryBlock(reinterpret_cast(base), RODataSize); + base += RODataSize; + RWDataMem = RWDataFree = + llvm::sys::MemoryBlock(reinterpret_cast(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 OwnedMMapper; + + uint8_t *Allocate(llvm::sys::MemoryBlock &FreeBlock, std::uintptr_t Size, + unsigned alignment) { + using namespace std::literals; + const auto Base = reinterpret_cast(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(Base + PaddedSize), + FreeBlock.allocatedSize() - PaddedSize); + return reinterpret_cast(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(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(Addr); + const uint32_t EntryCount = + static_cast(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(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( + *unwrap(ES), []() { return std::make_unique(); }); + Layer->setOverrideObjectFlagsWithResponsibilityFlags(true); + Layer->setAutoClaimResponsibilityForObjectSymbols(true); + return wrap(static_cast(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( + 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 { + 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 e6aef48569bb..d396a962f8ba 100644 --- a/lib/loader/CMakeLists.txt +++ b/lib/loader/CMakeLists.txt @@ -3,8 +3,8 @@ wasmedge_add_library(wasmedgeLoaderFileMgr filemgr.cpp - ldmgr.cpp shared_library.cpp + aot_section.cpp ) target_link_libraries(wasmedgeLoaderFileMgr @@ -26,7 +26,7 @@ wasmedge_add_library(wasmedgeLoader ast/component/sort.cpp ast/component/instance.cpp ast/component/alias.cpp - ast/component/type.cpp + ast/component/component_type.cpp ast/component/canonical.cpp ast/component/start.cpp ast/component/import_export.cpp diff --git a/lib/loader/aot_section.cpp b/lib/loader/aot_section.cpp new file mode 100644 index 000000000000..bc09eb4adf23 --- /dev/null +++ b/lib/loader/aot_section.cpp @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2022 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 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> 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(Binary + Offset); + break; +#elif WASMEDGE_OS_MACOS + case 4: // EHFrame + EHFrameAddress = reinterpret_cast(Binary + Offset); + EHFrameSize = Size; + break; +#elif WASMEDGE_OS_WINDOWS + case 4: // PData + PDataAddress = reinterpret_cast(Binary + Offset); + PDataSize = + static_cast(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(Iter); + Iter += Length + 4; + } + } +#elif WASMEDGE_OS_WINDOWS + if (PDataSize != 0) { + winapi::RtlAddFunctionTable( + static_cast(PDataAddress), PDataSize, + reinterpret_cast(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(Iter); + Iter += Length + 4; + } + } +#elif WASMEDGE_OS_WINDOWS + if (PDataSize != 0) { + winapi::RtlDeleteFunctionTable( + static_cast(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..2b86a06ed022 100644 --- a/lib/loader/ast/component.cpp +++ b/lib/loader/ast/component.cpp @@ -31,6 +31,7 @@ Expect, std::vector>> Loader::loadPreamble() { } std::vector 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 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 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()); + !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()); + !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()); + !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()); + !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()); + !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()); + !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()); + !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()); + !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()); + !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()); + !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()); + !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()); + !Res) { spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); return Unexpect(Res); } - Comp.getExportSection().push_back(Sec); break; } default: diff --git a/lib/loader/ast/component/component_type.cpp b/lib/loader/ast/component/component_type.cpp new file mode 100644 index 000000000000..bcf73fffd515 --- /dev/null +++ b/lib/loader/ast/component/component_type.cpp @@ -0,0 +1,3 @@ +// "libwasmedge.a" is merged from objects extracted from libraries. +// "ar" can't extract duplicate "type.cpp.o" from "libwasmedgeLoader.a". +#include "./type.cpp" diff --git a/lib/loader/ast/component/type.cpp b/lib/loader/ast/component/type.cpp index 7afd5270b165..f2d75427b774 100644 --- a/lib/loader/ast/component/type.cpp +++ b/lib/loader/ast/component/type.cpp @@ -312,14 +312,13 @@ Expect Loader::loadType(ComponentType &Ty) { } Expect 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()); } else { + FMgr.readByte(); return loadImportDecl(Decl.emplace()); } } @@ -363,7 +362,7 @@ Expect Loader::loadType(FuncType &Ty) { // ps: rs: // => (func ps rs) if (auto Res = loadVec( - Ty.getParamList(), [this](LabelValType LV) { return loadType(LV); }); + Ty.getParamList(), [this](LabelValType &LV) { return loadType(LV); }); !Res) { return Unexpect(Res); } diff --git a/lib/loader/ast/description.cpp b/lib/loader/ast/description.cpp index fcfe5a66885b..18a408d3e561 100644 --- a/lib/loader/ast/description.cpp +++ b/lib/loader/ast/description.cpp @@ -66,6 +66,15 @@ Expect 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 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/instruction.cpp b/lib/loader/ast/instruction.cpp index f5b1679be61b..08353525be5b 100644 --- a/lib/loader/ast/instruction.cpp +++ b/lib/loader/ast/instruction.cpp @@ -12,23 +12,124 @@ namespace Loader { // OpCode loader. See "include/loader/loader.h". Expect 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(*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(Payload); } // Load instruction sequence. See "include/loader/loader.h". @@ -55,49 +156,58 @@ Expect Loader::loadInstrSeq(std::optional 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 { + 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 Loader::loadInstrSeq(std::optional 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(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); @@ -185,18 +339,7 @@ Expect 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 { auto StartOffset = FMgr.getOffset(); // Read the block return type. if (auto Res = FMgr.readS33()) { @@ -204,13 +347,13 @@ Expect Loader::loadInstruction(AST::Instruction &Instr) { TypeCode TypeByte = static_cast((*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 +366,110 @@ Expect Loader::loadInstruction(AST::Instruction &Instr) { Proposal::MultiValue, FMgr.getLastOffset(), ASTNodeAttr::Instruction); } - Instr.setBlockType(static_cast(*Res)); + Dst.setData(static_cast(*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 +511,8 @@ Expect 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 +520,85 @@ Expect 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 +606,11 @@ Expect 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); @@ -946,8 +1244,7 @@ Expect 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..a9cd745a9a7e 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 +#include "loader/aot_section.h" #include "loader/loader.h" +#include "loader/shared_library.h" #include #include @@ -21,7 +23,7 @@ Expect 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 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 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 Loader::loadModule(AST::Module &Mod) { return loadModuleInBound(Mod, std::nullopt); } -// Load compiled function from loadable manager. See "include/loader/loader.h". -Expect 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(Name.c_str())) { - FuncTypes[I].setSymbol(std::move(Symbol)); +// Setup symbols from loaded binary. See "include/loader/loader.h". +Expect Loader::loadExecutable(AST::Module &Mod, + std::shared_ptr 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 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(Name.c_str())) { - CodeSegs[I].setSymbol(std::move(Symbol)); - } - } - return {}; -} - -Expect Loader::loadUniversalWASM(AST::Module &Mod) { - bool FallBackInterpreter = false; - auto Library = std::make_shared(); - 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(); - auto CodeSymbols = Library->getCodes(); - auto IntrinsicsSymbol = - Library->getIntrinsics(); - 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 Loader::loadUniversalWASM(AST::Module &Mod) { + if (!Conf.getRuntimeConfigure().isForceInterpreter()) { + auto Exec = std::make_shared(); + 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..2afe17dbce7c 100644 --- a/lib/loader/ast/section.cpp +++ b/lib/loader/ast/section.cpp @@ -12,19 +12,6 @@ namespace WasmEdge { namespace Loader { -// Load content size. See "include/loader/loader.h". -Expect 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 Loader::loadSection(AST::CustomSection &Sec) { return loadSectionContent(Sec, [this, &Sec]() -> Expect { @@ -55,10 +42,57 @@ Expect Loader::loadSection(AST::CustomSection &Sec) { // Load vector of type section. See "include/loader/loader.h". Expect 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 { + // 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(*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 Loader::loadSection(AST::DataCountSection &Sec) { }); } +Expect Loader::loadSection(AST::TagSection &Sec) { + return loadSectionContent(Sec, [this, &Sec]() { + return loadSectionContentVec( + Sec, [this](AST::TagType &TgType) { return loadType(TgType); }); + }); +} + Expect Loader::loadSection(AST::Component::ComponentSection &Sec) { auto ResPreamble = Loader::loadPreamble(); if (!ResPreamble) { @@ -194,7 +235,7 @@ Expect 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 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 Loader::loadSection(AST::Component::TypeSection &Sec) { }); } +Expect Loader::loadSection(AST::Component::StartSection &Sec) { + return loadSectionContent(Sec, [this, &Sec]() -> Expect { + return loadStart(Sec.getContent()); + }); +} + Expect 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..6b7cea07d4bc 100644 --- a/lib/loader/ast/segment.cpp +++ b/lib/loader/ast/segment.cpp @@ -12,8 +12,7 @@ namespace Loader { // Load binary of TableSegment node. See "include/loader/loader.h". Expect 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 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 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 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( + ElemSeg.getInitExprs(), [this](AST::Expression &Expr) -> Expect { + return loadExpression(Expr); + }); } default: @@ -275,19 +256,14 @@ Expect 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 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..a4daf99efef2 100644 --- a/lib/loader/ast/type.cpp +++ b/lib/loader/ast/type.cpp @@ -12,7 +12,11 @@ namespace Loader { Expect 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(static_cast((*Res) & INT64_C(0x7F))); switch (HTCode) { @@ -29,6 +33,26 @@ Expect 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 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 Loader::loadRefType(ASTNodeAttr From) { } // Load binary and decode ValType. See "include/loader/loader.h". -Expect Loader::loadValType(ASTNodeAttr From) { +Expect Loader::loadValType(ASTNodeAttr From, bool IsStorageType) { if (auto Res = FMgr.readByte()) { TypeCode Code = static_cast(*Res); switch (Code) { @@ -98,6 +135,16 @@ Expect 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 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 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 Loader::loadMutability(ASTNodeAttr From) { + if (auto Res = FMgr.readByte()) { + switch (static_cast(*Res)) { + case ValMut::Const: + case ValMut::Var: + return static_cast(*Res); + default: + return logLoadError(ErrCode::Value::InvalidMut, FMgr.getLastOffset(), + From); } } else { return logLoadError(Res.error(), FMgr.getLastOffset(), From); } } +Expect 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 Loader::loadCompositeType(AST::CompositeType &CType) { + if (auto CodeByte = FMgr.readByte()) { + switch (static_cast(*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 FList; + if (auto Res = loadVec( + FList, + [this](AST::FieldType &FType) -> Expect { + // 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 Loader::loadLimit(AST::Limit &Lim) { // Read limit. @@ -186,69 +328,77 @@ Expect Loader::loadLimit(AST::Limit &Lim) { return {}; } -// Load binary to construct FunctionType node. See "include/loader/loader.h". -Expect Loader::loadType(AST::FunctionType &FuncType) { - uint32_t VecCnt = 0; - - // Read type of Func (0x60). - if (auto Res = FMgr.readByte()) { - if (static_cast(*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 Loader::loadType(AST::SubType &SType) { + if (auto CodeByte = FMgr.peekByte()) { + switch (static_cast(*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( + SType.getSuperTypeIndices(), + [this](uint32_t &Idx) -> Expect { + 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 Loader::loadType(AST::FunctionType &FuncType) { + // Read type of Func (0x60). Moved into the composite type. + auto LoadValType = [this](ValType &VT) -> Expect { 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(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(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 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 Loader::loadType(AST::TagType &TgType) { if (auto Res = FMgr.readByte()) { - GlobType.setValMut(static_cast(*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..a9d62384d8a6 100644 --- a/lib/loader/filemgr.cpp +++ b/lib/loader/filemgr.cpp @@ -370,6 +370,16 @@ Expect FileMgr::readName() { return Str; } +// Peek one byte. See "include/loader/filemgr.h". +Expect 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 - -namespace WasmEdge { - -// Set path to loadable manager. See "include/loader/ldmgr.h". -Expect LDMgr::setPath(const std::filesystem::path &FilePath) { - Library = std::make_shared(); - if (auto Res = Library->load(FilePath); unlikely(!Res)) { - return Unexpect(Res); - } - - const auto IntrinsicsTable = getSymbol("intrinsics"); - if (IntrinsicsTable) { - if (unlikely(!Intrinsics)) { - spdlog::error(ErrCode::Value::IntrinsicsTableNotFound); - return Unexpect(ErrCode::Value::IntrinsicsTableNotFound); - } - *IntrinsicsTable = Intrinsics; - } - return {}; -} - -Expect> LDMgr::getWasm() { - const auto Size = getSymbol("wasm.size"); - if (unlikely(!Size)) { - spdlog::error(ErrCode::Value::IllegalGrammar); - return Unexpect(ErrCode::Value::IllegalGrammar); - } - const auto Code = getSymbol("wasm.code"); - if (unlikely(!Code)) { - spdlog::error(ErrCode::Value::IllegalGrammar); - return Unexpect(ErrCode::Value::IllegalGrammar); - } - - return std::vector(Code.get(), Code.get() + *Size); -} - -Expect LDMgr::getVersion() { - const auto Version = getSymbol("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..508f7f37f2ad 100644 --- a/lib/loader/loader.cpp +++ b/lib/loader/loader.cpp @@ -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 Library = std::make_shared(); + 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 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 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> 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_instruction.cpp b/lib/loader/serialize/serial_instruction.cpp index 5be7b130bd8a..e28660049fd9 100644 --- a/lib/loader/serialize/serial_instruction.cpp +++ b/lib/loader/serialize/serial_instruction.cpp @@ -6,15 +6,6 @@ namespace WasmEdge { namespace Loader { -namespace { -void serializeOpCode(OpCode Code, std::vector &OutVec) { - if (static_cast(Code) >= 0x100U) { - OutVec.push_back(static_cast(Code) >> 8); - } - OutVec.push_back(static_cast(Code) & 0xFFU); -} -} // namespace - // Serialize instruction. See "include/loader/serialize.h". Expect 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(PREFIX)); \ + break; +#define Line_FB(NAME, STRING, PREFIX, EXTEND) \ + case OpCode::NAME: \ + OutVec.push_back(static_cast(PREFIX)); \ + serializeU32(EXTEND, OutVec); \ + break; +#define Line_FC(NAME, STRING, PREFIX, EXTEND) \ + case OpCode::NAME: \ + OutVec.push_back(static_cast(PREFIX)); \ + serializeU32(EXTEND, OutVec); \ + break; +#define Line_FD(NAME, STRING, PREFIX, EXTEND) \ + case OpCode::NAME: \ + OutVec.push_back(static_cast(PREFIX)); \ + serializeU32(EXTEND, OutVec); \ + break; +#define Line_FE(NAME, STRING, PREFIX, EXTEND) \ + case OpCode::NAME: \ + OutVec.push_back(static_cast(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: @@ -728,8 +755,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_section.cpp b/lib/loader/serialize/serial_section.cpp index d018b76e1f83..57cad5d43e7b 100644 --- a/lib/loader/serialize/serial_section.cpp +++ b/lib/loader/serialize/serial_section.cpp @@ -29,12 +29,43 @@ Serializer::serializeSection(const AST::CustomSection &Sec, Expect Serializer::serializeSection(const AST::TypeSection &Sec, std::vector &OutVec) const noexcept { - // Type section: 0x01 + size:u32 + content:vec(functype). - return serializeSectionContent( - Sec, 0x01U, OutVec, - [=](const AST::FunctionType &R, std::vector &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(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(OrgSize))); + // Backward insert the section size. + serializeU32(static_cast(OutVec.size() - OrgSize), OutVec, + std::next(OutVec.begin(), static_cast(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_type.cpp b/lib/loader/serialize/serial_type.cpp index f4a75ab98189..f9c6ea3802dd 100644 --- a/lib/loader/serialize/serial_type.cpp +++ b/lib/loader/serialize/serial_type.cpp @@ -123,13 +123,58 @@ Serializer::serializeLimit(const AST::Limit &Lim, return {}; } +// Serialize sub type. See "include/loader/serialize.h". +Expect +Serializer::serializeType(const AST::SubType &SType, + std::vector &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(TypeCode::SubFinal)); + } else { + OutVec.push_back(static_cast(TypeCode::Sub)); + } + serializeU32(static_cast(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(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 Serializer::serializeType(const AST::FunctionType &Type, std::vector &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(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..7fb6dfd64502 100644 --- a/lib/loader/shared_library.cpp +++ b/lib/loader/shared_library.cpp @@ -2,9 +2,7 @@ // SPDX-FileCopyrightText: 2019-2022 Second State INC #include "loader/shared_library.h" - -#include "common/log.h" -#include "system/allocator.h" +#include "common/spdlog.h" #include #include @@ -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 SharedLibrary::load(const std::filesystem::path &Path) noexcept { @@ -76,89 +54,7 @@ Expect SharedLibrary::load(const std::filesystem::path &Path) noexcept { return {}; } -Expect 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> 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(Binary + Offset); - PDataSize = - static_cast(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(PDataAddress), PDataSize, - reinterpret_cast(Binary)); - } -#endif - - return {}; -} - void SharedLibrary::unload() noexcept { - if (Binary) { -#if WASMEDGE_OS_WINDOWS - if (PDataSize != 0) { - winapi::RtlDeleteFunctionTable( - static_cast(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(Binary); -} - -} // namespace Loader -} // namespace WasmEdge +} // namespace WasmEdge::Loader diff --git a/lib/plugin/plugin.cpp b/lib/plugin/plugin.cpp index 0dd837280324..4b4ac85db18d 100644 --- a/lib/plugin/plugin.cpp +++ b/lib/plugin/plugin.cpp @@ -14,6 +14,33 @@ #include #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(FuncPtr), &Module)) { + return false; + } + + std::vector Buffer; + WasmEdge::winapi::DWORD_ CopiedSize; + do { + Buffer.resize(Buffer.size() + WasmEdge::winapi::MAX_PATH_); + CopiedSize = WasmEdge::winapi::GetModuleFileNameW( + Module, Buffer.data(), + static_cast(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 +63,6 @@ template <> struct Parser { namespace Plugin { namespace { -static unsigned int NiftyCounter = 0; -static std::aligned_storage_t), - alignof(std::vector)> - PluginRegistryStorage; -static std::aligned_storage_t< - sizeof(std::unordered_map), - alignof(std::unordered_map)> - PluginNameLookupStorage; - -void IncreaseNiftyCounter() noexcept { - if (NiftyCounter++ == 0) { - new (&PluginRegistryStorage) std::vector(); - new (&PluginNameLookupStorage) - std::unordered_map(); - } -} - -void DecreaseNiftyCounter() noexcept { - if (--NiftyCounter == 0) { - reinterpret_cast &>(PluginRegistryStorage) - .~vector(); - reinterpret_cast &>( - PluginNameLookupStorage) - .~unordered_map(); - } -} class CAPIPluginRegister { public: @@ -69,8 +70,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 +166,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 +212,8 @@ class CAPIPluginRegister { static std::unordered_map DescriptionLookup; + + bool Result = false; }; std::unordered_map @@ -222,11 +223,9 @@ std::vector> CAPIPluginRegisters; } // namespace -std::vector &Plugin::PluginRegistry = - reinterpret_cast &>(PluginRegistryStorage); -std::unordered_map &Plugin::PluginNameLookup = - reinterpret_cast &>( - PluginNameLookupStorage); +std::vector WasmEdge::Plugin::Plugin::PluginRegistry; +std::unordered_map + WasmEdge::Plugin::Plugin::PluginNameLookup; std::vector Plugin::getDefaultPluginPaths() noexcept { using namespace std::literals::string_view_literals; @@ -285,9 +284,15 @@ std::vector Plugin::getDefaultPluginPaths() noexcept { return std::vector(); } #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(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(); + } + // Local home plugin directory. std::filesystem::path Home; if (const auto HomeEnv = ::getenv("USERPROFILE")) { @@ -343,14 +348,18 @@ WASMEDGE_EXPORT bool Plugin::load(const std::filesystem::path &Path) noexcept { } bool Plugin::loadFile(const std::filesystem::path &Path) noexcept { - const auto Index = PluginRegistry.size(); - + bool Result = false; auto Lib = std::make_shared(); if (auto Res = Lib->load(Path); unlikely(!Res)) { return false; } - if (PluginRegistry.size() != Index + 1) { + if (auto GetDescriptor = + Lib->get("GetDescriptor")) { + Result = Plugin::registerPlugin(GetDescriptor()); + } + + if (!Result) { // Check C interface if (auto GetDescriptor = Lib->get( "WasmEdge_Plugin_GetDescriptor"); @@ -360,11 +369,17 @@ bool Plugin::loadFile(const std::filesystem::path &Path) noexcept { unlikely(!Descriptor)) { return false; } else { - CAPIPluginRegisters.push_back( - std::make_unique(Descriptor)); + Result = + CAPIPluginRegisters + .emplace_back(std::make_unique(Descriptor)) + ->result(); } } + if (!Result) { + return false; + } + auto &Plugin = PluginRegistry.back(); Plugin.Path = Path; Plugin.Lib = std::move(Lib); @@ -380,29 +395,32 @@ 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 Plugin::plugins() noexcept { return PluginRegistry; } -WASMEDGE_EXPORT void +WASMEDGE_EXPORT bool Plugin::registerPlugin(const PluginDescriptor *Desc) noexcept { - assuming(NiftyCounter != 0); if (Desc->APIVersion != CurrentAPIVersion) { - return; + spdlog::debug( + "Plugin: API version {} of plugin {} is not match to current {}."sv, + Desc->APIVersion, Desc->Name, CurrentAPIVersion); + return false; + } + if (PluginNameLookup.find(Desc->Name) != PluginNameLookup.end()) { + spdlog::debug("Plugin: {} has already loaded."sv, Desc->Name); + return false; } const auto Index = PluginRegistry.size(); - PluginRegistry.push_back(Plugin(Desc)); + PluginRegistry.emplace_back(Desc); PluginNameLookup.emplace(Desc->Name, Index); - return; + return true; } Plugin::Plugin(const PluginDescriptor *D) noexcept : Desc(D) { @@ -421,16 +439,5 @@ 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(); -} - } // namespace Plugin } // namespace WasmEdge diff --git a/lib/po/argument_parser.cpp b/lib/po/argument_parser.cpp index 3baafd51d5bc..2e9d7d50ec41 100644 --- a/lib/po/argument_parser.cpp +++ b/lib/po/argument_parser.cpp @@ -3,7 +3,7 @@ #include "po/argument_parser.h" #include "common/defines.h" -#include "common/log.h" +#include "common/spdlog.h" #include "system/winapi.h" #include diff --git a/lib/system/fault.cpp b/lib/system/fault.cpp index 673ce8aa1dd2..10b2e0630401 100644 --- a/lib/system/fault.cpp +++ b/lib/system/fault.cpp @@ -5,7 +5,7 @@ #include "common/config.h" #include "common/defines.h" -#include "common/log.h" +#include "common/spdlog.h" #include #include @@ -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,18 +46,18 @@ thread_local Fault *localHandler = nullptr; } void enableHandler() noexcept { - struct sigaction Action {}; + [[maybe_unused]] struct sigaction Action {}; Action.sa_sigaction = &signalHandler; Action.sa_flags = SA_SIGINFO; - sigaction(SIGFPE, &Action, nullptr); - sigaction(SIGBUS, &Action, nullptr); - sigaction(SIGSEGV, &Action, nullptr); + // sigaction(SIGFPE, &Action, nullptr); + // sigaction(SIGBUS, &Action, nullptr); + // sigaction(SIGSEGV, &Action, nullptr); } void disableHandler() noexcept { - std::signal(SIGFPE, SIG_DFL); - std::signal(SIGBUS, SIG_DFL); - std::signal(SIGSEGV, SIG_DFL); + // std::signal(SIGFPE, SIG_DFL); + // std::signal(SIGBUS, SIG_DFL); + // std::signal(SIGSEGV, SIG_DFL); } #elif WASMEDGE_OS_WINDOWS diff --git a/lib/validator/formchecker.cpp b/lib/validator/formchecker.cpp index 1d09abc06e63..fffc61e90b36 100644 --- a/lib/validator/formchecker.cpp +++ b/lib/validator/formchecker.cpp @@ -4,7 +4,7 @@ #include "validator/formchecker.h" #include "common/errinfo.h" -#include "common/log.h" +#include "common/spdlog.h" #include #include @@ -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 FormChecker::validate(const ValType &VT) const noexcept { return {}; } -void FormChecker::addType(const AST::FunctionType &Func) { - std::vector 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 Exp, - Span 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 FormChecker::checkExpr(AST::InstrView Instrs) { if (Instrs.size() > 0) { // Push ctrl frame ([] -> [Returns]) @@ -203,13 +141,31 @@ Expect FormChecker::checkInstrs(AST::InstrView Instrs) { } return {}; } + Expect 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 { + if (TIdx >= Types.size()) { + return logOutOfRange(ErrCode::Value::InvalidFuncTypeIdx, + ErrInfo::IndexCategory::FunctionType, TIdx, + static_cast(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 &Buffer, - const BlockType &BType) + auto checkBlockType = [this, checkDefinedType](std::vector &Buffer, + const BlockType &BType) -> Expect, Span>> { using ReturnType = std::pair, Span>; if (BType.isEmpty()) { @@ -223,14 +179,13 @@ Expect 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(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 FormChecker::checkInstr(const AST::Instruction &Instr) { // Helper lambda for checking value types matching. auto checkTypesMatching = [this](Span Exp, Span Got) -> Expect { - if (!matchTypes(Exp, Got)) { - std::vector 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 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 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(ValStack.size() - CtrlStack[D].Height); + Jump.StackEraseBegin = Remain + Arity; + Jump.StackEraseEnd = Arity; + Jump.PCOffset = static_cast(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 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 Buffer(1); Span 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 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(TryDesc).BlockParamNum = + static_cast(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(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 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(C.Jump), + static_cast(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(TryDesc).BlockParamNum = + static_cast(T1.size()); + } // Push ctrl frame ([t1*], [t2*]) const AST::Instruction *From = Instr.getOpCode() == OpCode::Loop ? &Instr @@ -360,15 +411,74 @@ Expect 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(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(Catch.Jump); + Jump.StackEraseBegin = + static_cast(ValStack.size() - Res->Height) + + static_cast(NTypes.size()); + Jump.StackEraseEnd = static_cast(NTypes.size()); + Jump.PCOffset = static_cast(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(Tags.size())); + } + if (auto CompType = + checkDefinedType(Tags[Instr.getTargetIndex()], TypeCode::Func)) { + std::vector 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 FormChecker::checkInstr(const AST::Instruction &Instr) { if (auto Res = popTypes(NTypes); !Res) { return Unexpect(Res); } - const uint32_t Remain = - static_cast(ValStack.size() - CtrlStack[*D].Height); - const uint32_t Arity = static_cast(NTypes.size()); - auto &Jump = const_cast(Instr).getJump(); - Jump.StackEraseBegin = Remain + Arity; - Jump.StackEraseEnd = Arity; - Jump.PCOffset = static_cast(CtrlStack[*D].Jump - &Instr); + recordJump(const_cast(Instr).getJump(), + static_cast(NTypes.size()), *D); return unreachable(); } case OpCode::Br_if: @@ -404,13 +509,8 @@ Expect FormChecker::checkInstr(const AST::Instruction &Instr) { if (auto Res = popTypes(NTypes); !Res) { return Unexpect(Res); } - const uint32_t Remain = - static_cast(ValStack.size() - CtrlStack[*D].Height); - const uint32_t Arity = static_cast(NTypes.size()); - auto &Jump = const_cast(Instr).getJump(); - Jump.StackEraseBegin = Remain + Arity; - Jump.StackEraseEnd = Arity; - Jump.PCOffset = static_cast(CtrlStack[*D].Jump - &Instr); + recordJump(const_cast(Instr).getJump(), + static_cast(NTypes.size()), *D); pushTypes(NTypes); return {}; } @@ -450,13 +550,8 @@ Expect FormChecker::checkInstr(const AST::Instruction &Instr) { return Unexpect(Res); } } - const uint32_t Remain = - static_cast(ValStack.size() - CtrlStack[*N].Height); - const uint32_t Arity = static_cast(NTypes.size()); - LabelTable[LabelIdx].StackEraseBegin = Remain + Arity; - LabelTable[LabelIdx].StackEraseEnd = Arity; - LabelTable[LabelIdx].PCOffset = - static_cast(CtrlStack[*N].Jump - &Instr); + recordJump(LabelTable[LabelIdx], static_cast(NTypes.size()), + *N); pushTypes(TypeBuf); } else { return Unexpect(N); @@ -466,13 +561,8 @@ Expect FormChecker::checkInstr(const AST::Instruction &Instr) { if (auto Res = popTypes(NTypes); !Res) { return Unexpect(Res); } - const uint32_t Remain = - static_cast(ValStack.size() - CtrlStack[*M].Height); - const uint32_t Arity = static_cast(NTypes.size()); - LabelTable[LabelTableSize].StackEraseBegin = Remain + Arity; - LabelTable[LabelTableSize].StackEraseEnd = Arity; - LabelTable[LabelTableSize].PCOffset = - static_cast(CtrlStack[*M].Jump - &Instr); + recordJump(LabelTable[LabelTableSize], + static_cast(NTypes.size()), *M); return unreachable(); } else { return Unexpect(M); @@ -481,30 +571,24 @@ Expect 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(ValStack.size() - CtrlStack[*D].Height); - const uint32_t Arity = static_cast(NTypes.size()); - auto &Jump = const_cast(Instr).getJump(); - Jump.StackEraseBegin = Remain + Arity; - Jump.StackEraseEnd = Arity; - Jump.PCOffset = static_cast(CtrlStack[*D].Jump - &Instr); + recordJump(const_cast(Instr).getJump(), + static_cast(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 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 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(ValStack.size() - CtrlStack[*D].Height); - const uint32_t Arity = static_cast(NTypes.size() + 1); - // We plus 1 here because we did `pop_back` on `NTypes` - auto &Jump = const_cast(Instr).getJump(); - Jump.StackEraseBegin = Remain + Arity; - Jump.StackEraseEnd = Arity; - Jump.PCOffset = static_cast(CtrlStack[*D].Jump - &Instr); + recordJump(const_cast(Instr).getJump(), + static_cast(NTypes.size()), *D); + // Push types [t*]. + NTypes.pop_back(); pushTypes(NTypes); return {}; } else { @@ -558,40 +634,43 @@ Expect 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(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(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(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 FormChecker::checkInstr(const AST::Instruction &Instr) { static_cast(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 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(Tables.size()))); - return Unexpect(ErrCode::Value::InvalidTableIdx); + if (unlikely(T >= Tables.size())) { + return logOutOfRange(ErrCode::Value::InvalidTableIdx, + ErrInfo::IndexCategory::Table, T, + static_cast(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(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(Types.size())) { - return logOutOfRange(ErrCode::Value::InvalidFuncTypeIdx, - ErrInfo::IndexCategory::FunctionType, TypeIdx, - static_cast(Types.size())); + case OpCode::Call_ref: + if (auto Res = checkDefinedType(Instr.getTargetIndex(), TypeCode::Func)) { + const auto &FType = (*Res)->getFuncType(); + std::vector Input = FType.getParamTypes(); + Input.push_back(ValType(TypeCode::RefNull, Instr.getTargetIndex())); + return StackTrans(Input, FType.getReturnTypes()); + } else { + return Unexpect(Res); } - std::vector 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(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 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(Catch.Jump); + Jump.StackEraseBegin = + static_cast(ValStack.size() - Res->Height); + Jump.StackEraseEnd = 0; + Jump.PCOffset = static_cast(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 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 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 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 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((*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((*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 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(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(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 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 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(Instr).getBrCast().Jump, + static_cast(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 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 FormChecker::checkInstr(const AST::Instruction &Instr) { Instr.getSourceIndex(), static_cast(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 FormChecker::checkInstr(const AST::Instruction &Instr) { Instr.getSourceIndex(), static_cast(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()])); @@ -1868,7 +2312,7 @@ Expect 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..54ade3f4b323 100644 --- a/lib/validator/validator.cpp +++ b/lib/validator/validator.cpp @@ -6,6 +6,7 @@ #include "common/errinfo.h" #include +#include #include #include #include @@ -14,14 +15,20 @@ namespace WasmEdge { namespace Validator { Expect 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 &C : - Comp.getComponentSection().getContent()) { - validate(*C); + for (auto &Sec : Comp.getSections()) { + if (std::holds_alternative(Sec)) { + auto &Mod = std::get(Sec).getContent(); + validate(Mod); + } else if (std::holds_alternative(Sec)) { + auto &C = std::get(Sec).getContent(); + validate(C); + } else { + // TODO: validate others section + } } return {}; @@ -74,6 +81,13 @@ Expect 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 Validator::validate(const AST::Module &Mod) { return {}; } +// Validate Sub type. See "include/validator/validator.h". +Expect 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(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 Validator::validate(const AST::Limit &Lim) { if (Lim.hasMax() && Lim.getMin() > Lim.getMax()) { @@ -257,7 +329,7 @@ Expect Validator::validate(const AST::ElementSegment &ElemSeg) { static_cast(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 Validator::validate(const AST::ElementSegment &ElemSeg) { // Validate Code segment. See "include/validator/validator.h". Expect 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 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 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 Validator::validate(const AST::ImportDesc &ImpDesc) { static_cast(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(Checker.getFunctions().size())); Checker.addFunc(TId, true); return {}; @@ -374,6 +455,20 @@ Expect 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(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 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(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 Validator::validate(const AST::ExportDesc &ExpDesc) { } Expect 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 Validator::validate(const AST::FunctionSection &FuncSec) { static_cast(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 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 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 Validator::validate(const AST::ExportSection &ExportSec) { return {}; } +// Validate Tag section. See "include/validator/validator.h". +Expect 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(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 Validator::validateConstExpr(AST::InstrView Instrs, Span Returns) { @@ -630,11 +793,14 @@ Expect 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(Checker.getGlobals().size()); + } + if (GlobIdx >= ValidGlobalSize) { spdlog::error(ErrCode::Value::InvalidGlobalIdx); - spdlog::error(ErrInfo::InfoForbidIndex( - ErrInfo::IndexCategory::Global, GlobIdx, - static_cast(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 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..072db4af7799 100644 --- a/lib/vm/CMakeLists.txt +++ b/lib/vm/CMakeLists.txt @@ -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..5643649d5c94 100644 --- a/lib/vm/vm.cpp +++ b/lib/vm/vm.cpp @@ -5,6 +5,8 @@ #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" @@ -398,6 +400,30 @@ Expect VM::unsafeInstantiate() { spdlog::error(ErrCode::Value::WrongVMWorkflow); return Unexpect(ErrCode::Value::WrongVMWorkflow); } + + 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(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(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.get())) { Stage = VMStage::Instantiated; ActiveModInst = std::move(*Res); diff --git a/lib/wasi_nn_rpc/wasi_ephemeral_nn.proto b/lib/wasi_nn_rpc/wasi_ephemeral_nn.proto index 3ed030e455dc..e3bf4ae9a282 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 { diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index abe3e8e6c78e..8de19e705cf4 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -54,6 +54,10 @@ if(WASMEDGE_PLUGIN_WASM_BPF) endif() endif() +if(WASMEDGE_PLUGIN_WASI_OCR) + add_subdirectory(wasi_ocr) +endif() + if(WASMEDGE_PLUGIN_OPENCVMINI) # Only Linux and MacOS support wasmedge_opencvmini now. if(CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin") @@ -74,3 +78,7 @@ endif() if(WASMEDGE_PLUGIN_ZLIB) add_subdirectory(wasmedge_zlib) endif() + +if(WASMEDGE_PLUGIN_FFMPEG) + add_subdirectory(wasmedge_ffmpeg) +endif() diff --git a/plugins/wasi_crypto/ctx.cpp b/plugins/wasi_crypto/ctx.cpp index 7ff586f68d9d..db2eefe1a26d 100644 --- a/plugins/wasi_crypto/ctx.cpp +++ b/plugins/wasi_crypto/ctx.cpp @@ -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::Instance; diff --git a/plugins/wasi_crypto/ctx.h b/plugins/wasi_crypto/ctx.h index f5eda8a74c64..46a93d841dc0 100644 --- a/plugins/wasi_crypto/ctx.h +++ b/plugins/wasi_crypto/ctx.h @@ -358,7 +358,6 @@ class Context { static std::shared_mutex Mutex; static std::weak_ptr Instance; - static Plugin::PluginRegister Register; }; } // namespace WasiCrypto diff --git a/plugins/wasi_crypto/utils/evp_wrapper.h b/plugins/wasi_crypto/utils/evp_wrapper.h index 67b4ecfbfd2d..d6edc89b9da6 100644 --- a/plugins/wasi_crypto/utils/evp_wrapper.h +++ b/plugins/wasi_crypto/utils/evp_wrapper.h @@ -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 #include diff --git a/plugins/wasi_crypto/utils/handles_manager.h b/plugins/wasi_crypto/utils/handles_manager.h index ba01f157989a..2282a283a2eb 100644 --- a/plugins/wasi_crypto/utils/handles_manager.h +++ b/plugins/wasi_crypto/utils/handles_manager.h @@ -48,7 +48,8 @@ template 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 close(HandleType Handle) noexcept { std::unique_lock Lock{Mutex}; @@ -140,6 +141,8 @@ class RcHandlesManager ManagerType>::HandleWrapper; public: + using detail::BaseHandlesManager::BaseHandlesManager; + /// Get the return copy. WasiCryptoExpect get(HandleType Handle) noexcept { std::shared_lock Lock{this->Mutex}; @@ -184,6 +187,8 @@ class RefHandlesManager ManagerType>::HandleWrapper; public: + using detail::BaseHandlesManager::BaseHandlesManager; + /// Get the return reference. WasiCryptoExpect> get(HandleType Handle) noexcept { diff --git a/plugins/wasi_logging/base.h b/plugins/wasi_logging/base.h new file mode 100644 index 000000000000..dc1c51ca9a73 --- /dev/null +++ b/plugins/wasi_logging/base.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#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 class Func : public Runtime::HostFunction { +public: + Func(LogEnv &HostEnv) : Runtime::HostFunction(0), Env(HostEnv) {} + +protected: + LogEnv &Env; +}; + +} // namespace WASILogging +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_logging/env.cpp b/plugins/wasi_logging/env.cpp index 0f55170fff8b..97f2b1419d69 100644 --- a/plugins/wasi_logging/env.cpp +++ b/plugins/wasi_logging/env.cpp @@ -1,5 +1,8 @@ -#include "wasi_logging/env.h" -#include "wasi_logging/module.h" +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "env.h" +#include "module.h" namespace WasmEdge { namespace Host { @@ -28,9 +31,8 @@ Plugin::Plugin::PluginDescriptor Descriptor{ .AddOptions = nullptr, }; -} // namespace - -Plugin::PluginRegister WasiLoggingEnvironment::Register(&Descriptor); +EXPORT_GET_DESCRIPTOR(Descriptor) +} // namespace } // namespace Host -} // namespace WasmEdge \ No newline at end of file +} // namespace WasmEdge diff --git a/plugins/wasi_logging/env.h b/plugins/wasi_logging/env.h new file mode 100644 index 000000000000..838c785000d5 --- /dev/null +++ b/plugins/wasi_logging/env.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#pragma once + +#include "plugin/plugin.h" + +#include +#include + +namespace WasmEdge { +namespace Host { +namespace WASILogging { + +class LogEnv { +public: + LogEnv() noexcept { + // TODO: Use the config in WasmEdge to set the logging level. + StdoutLogger->set_level(spdlog::level::trace); + StderrLogger->set_level(spdlog::level::trace); + StdoutLogger->set_pattern(DefFormat); + StderrLogger->set_pattern(DefFormat); + } + + const std::shared_ptr StdoutLogger = + spdlog::stdout_color_mt("wasi_logging_stdout"); + const std::shared_ptr StderrLogger = + spdlog::stderr_color_mt("wasi_logging_stderr"); + const std::string DefFormat = "[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v"; + std::shared_ptr FileLogger; + std::string LogFileName; +}; + +} // namespace WASILogging +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_logging/func.cpp b/plugins/wasi_logging/func.cpp index 5f0a2c0106b4..9d44d4c3598e 100644 --- a/plugins/wasi_logging/func.cpp +++ b/plugins/wasi_logging/func.cpp @@ -1,85 +1,99 @@ -#include "wasi_logging/func.h" -#include "wasi_logging/enum.h" +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "func.h" + #include namespace WasmEdge { namespace Host { +namespace WASILogging { using namespace std::literals; -Expect WasiLoggingLog::body(const Runtime::CallingFrame &Frame, - uint32_t Level, uint32_t CxtPtr, - uint32_t CxtLen, uint32_t MsgPtr, - uint32_t MsgLen) { +Expect 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 + // Get Buffer Pointer. char *CxtBuf = MemInst->getPointer(CxtPtr); char *MsgBuf = MemInst->getPointer(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)); + // Get Context and Message string_view + std::string_view CxtSV(CxtBuf, CxtLen); + std::string_view MsgSV(MsgBuf, MsgLen); // 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; + std::shared_ptr Logger; + if (CxtSV == "stdout"sv || CxtSV == ""sv) { + Logger = Env.StdoutLogger; + } else if (CxtSV == "stderr"sv) { + Logger = Env.StderrLogger; } else { - SpdlogMsg = MsgStr; + if (CxtSV != Env.LogFileName) { + try { + spdlog::drop("wasi_logging_file"); + Env.FileLogger = + spdlog::basic_logger_mt("wasi_logging_file", std::string(CxtSV)); + Env.FileLogger->set_pattern(Env.DefFormat); + Env.LogFileName = CxtSV; + // TODO: Use the config in WasmEdge to set the logging level. + Env.FileLogger->set_level(spdlog::level::trace); + } 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 (Level) { - case WASILOGGING::WasiLoggingLevel::Trace: - logger->trace(SpdlogMsg); + switch (static_cast(Level)) { + case LogLevel::Trace: + Logger->trace(MsgSV); break; - case WASILOGGING::WasiLoggingLevel::Debug: - logger->debug(SpdlogMsg); + case LogLevel::Debug: + Logger->debug(MsgSV); break; - case WASILOGGING::WasiLoggingLevel::Info: - logger->info(SpdlogMsg); + case LogLevel::Info: + Logger->info(MsgSV); break; - case WASILOGGING::WasiLoggingLevel::Warn: - logger->warn(SpdlogMsg); + case LogLevel::Warn: + Logger->warn(MsgSV); break; - case WASILOGGING::WasiLoggingLevel::Error: - logger->error(SpdlogMsg); + case LogLevel::Error: + Logger->error(MsgSV); break; - case WASILOGGING::WasiLoggingLevel::Critical: - logger->critical(SpdlogMsg); + case LogLevel::Critical: + Logger->critical(MsgSV); break; default: spdlog::error("[WasiLogging] Unrecognized Logging Level: {}"sv, Level); spdlog::error("[WasiLogging] Trace Level = {}"sv, - static_cast(WASILOGGING::WasiLoggingLevel::Trace)); + static_cast(LogLevel::Trace)); spdlog::error("[WasiLogging] Debug Level = {}"sv, - static_cast(WASILOGGING::WasiLoggingLevel::Debug)); + static_cast(LogLevel::Debug)); spdlog::error("[WasiLogging] Info Level = {}"sv, - static_cast(WASILOGGING::WasiLoggingLevel::Info)); + static_cast(LogLevel::Info)); spdlog::error("[WasiLogging] Warn Level = {}"sv, - static_cast(WASILOGGING::WasiLoggingLevel::Warn)); + static_cast(LogLevel::Warn)); spdlog::error("[WasiLogging] Error Level = {}"sv, - static_cast(WASILOGGING::WasiLoggingLevel::Error)); - spdlog::error( - "[WasiLogging] Critical Level = {}"sv, - static_cast(WASILOGGING::WasiLoggingLevel::Critical)); + static_cast(LogLevel::Error)); + spdlog::error("[WasiLogging] Critical Level = {}"sv, + static_cast(LogLevel::Critical)); return Unexpect(ErrCode::Value::HostFuncError); } return {}; } +} // namespace WASILogging } // namespace Host -} // namespace WasmEdge \ No newline at end of file +} // namespace WasmEdge diff --git a/plugins/wasi_logging/wasi_logging/func.h b/plugins/wasi_logging/func.h similarity index 55% rename from plugins/wasi_logging/wasi_logging/func.h rename to plugins/wasi_logging/func.h index f7631e985c8b..60e81c9dcb6c 100644 --- a/plugins/wasi_logging/wasi_logging/func.h +++ b/plugins/wasi_logging/func.h @@ -1,17 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + #pragma once -#include "wasi_logging/base.h" +#include "base.h" namespace WasmEdge { namespace Host { +namespace WASILogging { -class WasiLoggingLog : public WasiLogging { +class Log : public Func { public: - WasiLoggingLog(WasiLoggingEnvironment &HostEnv) : WasiLogging(HostEnv) {} + Log(LogEnv &HostEnv) : Func(HostEnv) {} Expect 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/plugins/wasi_logging/module.cpp b/plugins/wasi_logging/module.cpp index 6ebd7879f46f..938ecc20c309 100644 --- a/plugins/wasi_logging/module.cpp +++ b/plugins/wasi_logging/module.cpp @@ -1,5 +1,9 @@ -#include "wasi_logging/module.h" -#include "wasi_logging/func.h" +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "module.h" +#include "func.h" + #include namespace WasmEdge { @@ -9,8 +13,8 @@ using namespace std::literals; WasiLoggingModule::WasiLoggingModule() : ModuleInstance("wasi:logging/logging"sv) { - addHostFunc("log"sv, std::make_unique(Env)); + addHostFunc("log"sv, std::make_unique(Env)); } } // namespace Host -} // namespace WasmEdge \ No newline at end of file +} // namespace WasmEdge diff --git a/plugins/wasi_logging/wasi_logging/module.h b/plugins/wasi_logging/module.h similarity index 57% rename from plugins/wasi_logging/wasi_logging/module.h rename to plugins/wasi_logging/module.h index 12504522beeb..9cf1260e21cb 100644 --- a/plugins/wasi_logging/wasi_logging/module.h +++ b/plugins/wasi_logging/module.h @@ -1,7 +1,11 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + #pragma once +#include "env.h" + #include "runtime/instance/module.h" -#include "wasi_logging/env.h" namespace WasmEdge { namespace Host { @@ -10,10 +14,10 @@ class WasiLoggingModule : public Runtime::Instance::ModuleInstance { public: WasiLoggingModule(); - WasiLoggingEnvironment &getEnv() { return Env; } + WASILogging::LogEnv &getEnv() { return Env; } private: - WasiLoggingEnvironment Env; + WASILogging::LogEnv Env; }; } // namespace Host 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 class WasiLogging : public Runtime::HostFunction { -public: - WasiLogging(WasiLoggingEnvironment &HostEnv) - : Runtime::HostFunction(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 - -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 -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 StdoutLogger = - spdlog::stdout_color_mt("wasi_logging_stdout"); - inline const static std::shared_ptr StderrLogger = - spdlog::stderr_color_mt("wasi_logging_stderr"); - static Plugin::PluginRegister Register; -}; - -} // namespace Host -} // namespace WasmEdge diff --git a/plugins/wasi_nn/CMakeLists.txt b/plugins/wasi_nn/CMakeLists.txt index 6fceddf0ce77..45236ef33676 100644 --- a/plugins/wasi_nn/CMakeLists.txt +++ b/plugins/wasi_nn/CMakeLists.txt @@ -9,14 +9,23 @@ if(BACKEND STREQUAL "ggml") set(LLAMA_METAL_NDEBUG ON) set(LLAMA_ACCELERATE OFF) + if(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_NATIVE) + message(STATUS "WASI-NN GGML LLAMA backend: Enable LLAMA_NATIVE(AVX/AVX2/FMA)") + set(LLAMA_NATIVE ON) + else() + set(LLAMA_NATIVE OFF) + endif() + 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. + message(STATUS "WASI-NN GGML LLAMA backend: Enable LLAMA_CUDA") + set(LLAMA_CUDA ON) + # We need to set GGML_USE_CUDA for clip from llava. + add_compile_definitions(GGML_USE_CUDA) + # If CUDA 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) + message(STATUS "WASI-NN GGML LLAMA backend: Disable LLAMA_CUDA") + set(LLAMA_CUDA OFF) endif() if(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_BLAS) @@ -36,6 +45,7 @@ if(BACKEND STREQUAL "ggml") if(WASMEDGE_PLUGIN_WASI_NN_GGML_LLAMA_METAL) message(STATUS "WASI-NN GGML LLAMA backend: Enable LLAMA_METAL") set(LLAMA_METAL ON) + set(LLAMA_METAL_EMBED_LIBRARY ON) else() message(STATUS "WASI-NN GGML LLAMA backend: Disable LLAMA_METAL") set(LLAMA_METAL OFF) @@ -43,12 +53,50 @@ if(BACKEND STREQUAL "ggml") # setup llama.cpp message(STATUS "Downloading llama.cpp source") + if(MSVC) + add_compile_options( + $<$:/utf-8> + $<$:-Xcompiler=/utf-8> + $<$:/wd4067> # unexpected tokens following preprocessor directive - expected a newline + $<$:/wd4101> # 'identifier' : unreferenced local variable + $<$:/wd4189> # 'identifier' : local variable is initialized but not referenced + $<$:/wd4244> # 'argument' : conversion from 'type1' to 'type2', possible loss of data + $<$:/wd4267> # 'var' : conversion from 'size_t' to 'type', possible loss of data + $<$:/wd4297> # 'function' : function assumed not to throw an exception but does + $<$:/wd4456> # declaration of 'identifier' hides previous local declaration + $<$:/wd4505> # 'function' : unreferenced local function has been removed + ) + endif() + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + add_compile_options( + $<$:-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") + add_compile_options( + $<$:-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 + ) + endif() 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_TAG b2963 GIT_SHALLOW FALSE ) FetchContent_MakeAvailable(llama) @@ -66,20 +114,12 @@ if(BACKEND STREQUAL "ggml") FetchContent_Declare( simdjson GIT_REPOSITORY https://github.com/simdjson/simdjson.git - GIT_TAG tags/v3.2.1 + GIT_TAG tags/v3.9.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 + add_compile_options( -Wno-undef -Wno-suggest-override -Wno-documentation @@ -95,15 +135,11 @@ if(BACKEND STREQUAL "ggml") -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 + add_compile_options( /wd4100 # unreferenced formal parameter - ) + ) endif() endif() @@ -142,13 +178,41 @@ target_include_directories(wasmedgePluginWasiNN ) if(BACKEND STREQUAL "ggml") - target_include_directories(wasmedgePluginWasiNN PUBLIC ${CMAKE_BINARY_DIR}/_deps/llama-src) - target_link_libraries(wasmedgePluginWasiNN PRIVATE common simdjson) + # 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 "GNU|Clang") + target_compile_options(llava PRIVATE -Wno-error=unused-variable -Wno-error=unused-function) + 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 + ) + # Setup include and link from llama.cpp + target_include_directories(wasmedgePluginWasiNN PRIVATE + ${llama_SOURCE_DIR} + ${llama_SOURCE_DIR}examples/llava + ) + target_link_libraries(wasmedgePluginWasiNN PRIVATE + common + simdjson::simdjson + llava + ) + if(MSVC) + target_compile_options(wasmedgePluginWasiNN PUBLIC + /wd4067 # unexpected tokens following preprocessor directive - expected a newline + ) + endif() 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 + COMMAND ${CMAKE_COMMAND} -E copy ${llama_SOURCE_DIR}/ggml-metal.metal ggml-metal.metal + COMMAND ${CMAKE_COMMAND} -E copy ${llama_SOURCE_DIR}/ggml-common.h ggml-common.h ) endif() endif() diff --git a/plugins/wasi_nn/ggml.cpp b/plugins/wasi_nn/ggml.cpp index 2d83eafb4de6..e84c0a299eb2 100644 --- a/plugins/wasi_nn/ggml.cpp +++ b/plugins/wasi_nn/ggml.cpp @@ -6,16 +6,46 @@ #ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_GGML #include "simdjson.h" +#include +#include +#include #include #include +#include #include +#include #include #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 = *static_cast(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 parseMetadata(Graph &GraphRef, const std::string &Metadata, bool *IsModelUpdated = nullptr) noexcept { simdjson::dom::parser Parser; @@ -27,12 +57,39 @@ Expect 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 + // 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 + // 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.main_gpu = GraphRef.MainGPU; + ModelParams.tensor_split = GraphRef.TensorSplit.data(); // The plugin parameters. if (Doc.at_key("enable-log").error() == simdjson::SUCCESS) { @@ -42,7 +99,6 @@ Expect 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().get(GraphRef.EnableDebugLog); @@ -86,6 +142,26 @@ Expect 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().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().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 +172,44 @@ Expect 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().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().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); + } + uint32_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 (uint32_t Idx = GraphRef.TensorSplit.size(); Idx < NDevices; Idx++) { + GraphRef.TensorSplit.push_back(0.0f); + } + } // The context parameters. if (Doc.at_key("ctx-size").error() == simdjson::SUCCESS) { @@ -114,6 +228,14 @@ Expect 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().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().get(GraphRef.Threads); if (Err) { @@ -122,6 +244,7 @@ Expect 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().get(GraphRef.Temp); @@ -166,6 +289,16 @@ Expect 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().get(Grammar); + if (Err) { + spdlog::error( + "[WASI-NN] GGML backend: Unable to retrieve the grammar option."sv); + return ErrNo::InvalidArgument; + } + GraphRef.Grammar = Grammar; + } // Check if the model is updated. if (IsModelUpdated && ModelParams.n_gpu_layers != GraphRef.NGPULayers) { @@ -175,10 +308,31 @@ Expect parseMetadata(Graph &GraphRef, const std::string &Metadata, return ErrNo::Success; } +Expect setupGPTParam(Graph &GraphRef, gpt_params &GPTParams) { + GPTParams.sparams.temp = static_cast(GraphRef.Temp); + GPTParams.sparams.top_p = static_cast(GraphRef.TopP); + GPTParams.sparams.penalty_repeat = static_cast(GraphRef.RepeatPenalty); + GPTParams.sparams.penalty_present = + static_cast(GraphRef.PresencePenalty); + GPTParams.sparams.grammar = GraphRef.Grammar; + return ErrNo::Success; +} + +Expect setupContextParam(Graph &GraphRef, + llama_context_params &ContextParams) { + ContextParams.n_ctx = GraphRef.CtxSize; + ContextParams.n_batch = GraphRef.BatchSize; + ContextParams.n_ubatch = GraphRef.UBatchSize; + ContextParams.n_threads = GraphRef.Threads; + ContextParams.n_threads_batch = GraphRef.Threads; + ContextParams.embeddings = GraphRef.Embedding; + return ErrNo::Success; +} + Expect buildOutputMetadata(Context &CxtRef, std::string &Metadata) noexcept { std::ostringstream OS; - OS << R"({"input_tokens": )" << CxtRef.LlamaInputs.size() + OS << R"({"input_tokens": )" << CxtRef.LlamaNInputs << R"(, "output_tokens": )" << CxtRef.LlamaOutputTokens.size() << R"(, "llama_build_number": )" << LLAMA_BUILD_NUMBER << R"(, "llama_commit": ")" << LLAMA_COMMIT << R"("})"; @@ -210,6 +364,99 @@ void buildOutputEmbedding(std::string &Embedding, int32_t NEmbd, Embedding = OS.str(); } +ErrNo evaluateTokens(Graph &GraphRef, struct llama_context *LlamaContext, + std::vector Tokens, int &NPast) noexcept { + uint32_t NCtx = llama_n_ctx(LlamaContext); + + // End the inference if the context is full. + if (NPast + static_cast(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(Tokens.size()), NCtx); + } + return ErrNo::ContextFull; + } + + for (int I = 0; I < static_cast(Tokens.size()); + I += GraphRef.BatchSize) { + int NEval = static_cast(Tokens.size()) - I; + if (NEval > static_cast(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. + 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 &Tokens, + llama_seq_id SequenceId) noexcept { + for (int I = 0; I < static_cast(Tokens.size()); I++) { + // llama_batch_add_seq(llama_batch, llama_token, llama_pos, + // std::vector, logits); + llama_batch_add(Batch, Tokens[I], I, {SequenceId}, + I == static_cast(Tokens.size()) - 1); + } +} + +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 getEmbedding(WasiNNEnvironment &Env, uint32_t ContextId) noexcept { auto &CxtRef = Env.NNContext[ContextId].get(); @@ -241,56 +488,47 @@ Expect 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 , , ... 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(CxtRef.LlamaInputs.size()) > MaxTokensListSize) { + if (static_cast(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(GraphRef.BatchSize, /* embd */ 0, /* n_seq_max */ 1); + std::vector 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 +542,126 @@ Expect 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 = ""sv; +const std::string_view PromptImagePlaceholder = ""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 `` + 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(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, GraphRef.Threads, ImageBytes.data(), ImageBytes.size()); +} + +ErrNo replaceBase64ImagePlaceholderInPrompt(std::string &Prompt) noexcept { + // Replace the base64 image in the prompt with a placeholder. + + // 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 load(WasiNNEnvironment &Env, Span> Builders, [[maybe_unused]] Device Device, uint32_t &GraphId) noexcept { @@ -323,15 +672,14 @@ Expect load(WasiNNEnvironment &Env, Span> 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 +691,17 @@ Expect load(WasiNNEnvironment &Env, Span> 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(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 +719,21 @@ Expect load(WasiNNEnvironment &Env, Span> Builders, } // Handle the model path. auto Weight = Builders[0]; - const std::string BinModel(reinterpret_cast(Weight.data()), - Weight.size()); + const std::string_view BinModel(reinterpret_cast(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 +743,7 @@ Expect load(WasiNNEnvironment &Env, Span> 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 +754,12 @@ Expect load(WasiNNEnvironment &Env, Span> 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( @@ -410,6 +769,8 @@ Expect load(WasiNNEnvironment &Env, Span> Builders, GraphRef.ModelFilePath = ModelFilePath; llama_model_params ModelParams = llama_model_default_params(); ModelParams.n_gpu_layers = GraphRef.NGPULayers; + ModelParams.main_gpu = GraphRef.MainGPU; + ModelParams.tensor_split = GraphRef.TensorSplit.data(); GraphRef.LlamaModel = llama_load_model_from_file(GraphRef.ModelFilePath.c_str(), ModelParams); if (GraphRef.LlamaModel == nullptr) { @@ -433,13 +794,19 @@ Expect load(WasiNNEnvironment &Env, Span> Builders, Expect initExecCtx(WasiNNEnvironment &Env, uint32_t GraphId, uint32_t &ContextId) noexcept { + auto &GraphRef = Env.NNGraph[GraphId].get(); + if (GraphRef.EnableDebugLog) { + spdlog::info("[WASI-NN][Debug] GGML backend: initExecCtx"sv); + } Env.NNContext.emplace_back(GraphId, Env.NNGraph[GraphId]); ContextId = Env.NNContext.size() - 1; - auto &GraphRef = Env.NNGraph[GraphId].get(); 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 +827,7 @@ Expect setInput(WasiNNEnvironment &Env, uint32_t ContextId, } const std::string Metadata(reinterpret_cast(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); @@ -503,13 +869,8 @@ Expect 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 +880,111 @@ Expect 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(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(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, 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 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 EmbdInputBeforeImage = llama_tokenize( + LlamaContext, PromptBeforeImage, AddSpecial, ParseSpecial); + // Do not add special token (such as , , ... tokens.) to the + // tokens after the image. + std::vector 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,10 +1010,15 @@ Expect getOutput(WasiNNEnvironment &Env, uint32_t ContextId, uint32_t Index, Span OutBuffer, uint32_t &BytesWritten) noexcept { auto &CxtRef = Env.NNContext[ContextId].get(); + auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get(); + 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); @@ -559,12 +1026,22 @@ Expect getOutput(WasiNNEnvironment &Env, uint32_t ContextId, } std::copy_n(Metadata.data(), Metadata.length(), OutBuffer.data()); BytesWritten = 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(); + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: getOutput with Index {}...Done"sv, + Index); + } return ErrNo::Success; } @@ -576,7 +1053,7 @@ Expect 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 +1073,120 @@ Expect 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); - } + // 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; + llama_context_params ContextParams = llama_context_default_params(); + 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); - std::vector Embd; - uint64_t NPast = 0; - uint64_t NConsumed = 0; + // Prepare variables; + int32_t NPast = 0; int32_t NRemain = GraphRef.NPredict; - // Initialize the llama context. - llama_context_params ContextParams = llama_context_default_params(); - ContextParams.n_ctx = GraphRef.CtxSize; - ContextParams.n_batch = GraphRef.BatchSize; - 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 , , ... 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(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 EmbdInputBeforeImage( + CxtRef.LlamaInputs.begin(), + CxtRef.LlamaInputs.begin() + CxtRef.LlavaImagePosition); + std::vector 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, 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(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(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(Embd.size()), NCtx); - } - ReturnCode = ErrNo::ContextFull; - break; - } - - // Evaluate tokens in batches. - for (int I = 0; I < static_cast(Embd.size()); - I += GraphRef.BatchSize) { - uint64_t NEval = static_cast(Embd.size()) - I; - if (NEval > static_cast(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) { + std::cout << llama_token_to_piece(LlamaContext, Id) << std::flush; } - - Embd.clear(); - - if (static_cast(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; + // 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); } - // 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; - } - } else { - while (static_cast(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 +1194,20 @@ Expect 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,10 +1220,16 @@ Expect getOutputSingle(WasiNNEnvironment &Env, uint32_t ContextId, uint32_t Index, Span OutBuffer, uint32_t &BytesWritten) noexcept { auto &CxtRef = Env.NNContext[ContextId].get(); + auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get(); + 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); @@ -773,12 +1237,22 @@ Expect getOutputSingle(WasiNNEnvironment &Env, uint32_t ContextId, } std::copy_n(Metadata.data(), Metadata.length(), OutBuffer.data()); BytesWritten = 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(); + if (GraphRef.EnableDebugLog) { + spdlog::info( + "[WASI-NN][Debug] GGML backend: getOutputSingle with Index {}...Done"sv, + Index); + } return ErrNo::Success; } @@ -791,13 +1265,15 @@ Expect 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 +1288,124 @@ Expect 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 , , ... 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(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 , , ... tokens.) + const uint64_t MaxTokensListSize = NCtx - 4; + // Return value. + auto ReturnCode = ErrNo::Success; + + // Check if the input is too long. + if (static_cast(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(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(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(CxtRef.LlamaEmbd.size()), - NCtx); - } - return ErrNo::ContextFull; + } else { + // Llava format prompt with image data. + std::vector EmbdInputBeforeImage( + CxtRef.LlamaInputs.begin(), + CxtRef.LlamaInputs.begin() + CxtRef.LlavaImagePosition); + std::vector 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(CxtRef.LlamaEmbd.size()); - I += GraphRef.BatchSize) { - uint64_t NEval = static_cast(CxtRef.LlamaEmbd.size()) - I; - if (NEval > static_cast(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, + 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(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(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 finiSingle(WasiNNEnvironment &Env, uint32_t ContextId) noexcept { auto &CxtRef = Env.NNContext[ContextId].get(); auto &GraphRef = Env.NNGraph[CxtRef.GraphId].get(); + 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 +1432,49 @@ Expect 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 unload(WasiNNEnvironment &Env, uint32_t GraphId) noexcept { + auto &GraphRef = Env.NNGraph[GraphId].get(); + 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 reportBackendNotSupported() noexcept { @@ -1011,6 +1502,19 @@ Expect getOutput(WasiNNEnvironment &, uint32_t, uint32_t, Span, Expect compute(WasiNNEnvironment &, uint32_t) noexcept { return reportBackendNotSupported(); } +Expect getOutputSingle(WasiNNEnvironment &, uint32_t, uint32_t, + Span, uint32_t &) noexcept { + return reportBackendNotSupported(); +} +Expect computeSingle(WasiNNEnvironment &, uint32_t) noexcept { + return reportBackendNotSupported(); +} +Expect finiSingle(WasiNNEnvironment &, uint32_t) noexcept { + return reportBackendNotSupported(); +} +Expect 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..25c02caa6abc 100644 --- a/plugins/wasi_nn/ggml.h +++ b/plugins/wasi_nn/ggml.h @@ -9,6 +9,7 @@ #ifdef WASMEDGE_PLUGIN_WASI_NN_BACKEND_GGML #include #include +#include #endif namespace WasmEdge::Host::WASINN { @@ -28,11 +29,16 @@ 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 TensorSplit; // Context parameters: uint64_t CtxSize; uint64_t BatchSize; + uint64_t UBatchSize; uint64_t Threads; // Sampling parameters: double Temp = 0.80; @@ -40,6 +46,7 @@ struct Graph { double RepeatPenalty = 1.10; double PresencePenalty = 0.00; double FrequencyPenalty = 0.00; + std::string Grammar; }; struct Context { @@ -47,14 +54,16 @@ struct Context { Context(size_t GId, Graph &) noexcept : GraphId(GId) {} size_t GraphId; std::vector LlamaInputs; + uint64_t LlamaNInputs = 0; std::string LlamaOutputs; std::vector LlamaOutputTokens; // Preserve for computing single token llama_context *LlamaContext = nullptr; struct llama_sampling_context *LlamaSampling = nullptr; - std::vector 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 +97,6 @@ Expect computeSingle(WASINN::WasiNNEnvironment &Env, uint32_t ContextId) noexcept; Expect finiSingle(WASINN::WasiNNEnvironment &Env, uint32_t ContextId) noexcept; +Expect unload(WASINN::WasiNNEnvironment &Env, + uint32_t GraphId) noexcept; } // namespace WasmEdge::Host::WASINN::GGML diff --git a/plugins/wasi_nn/types.h b/plugins/wasi_nn/types.h index 453b320bed5f..81a06eeebdbb 100644 --- a/plugins/wasi_nn/types.h +++ b/plugins/wasi_nn/types.h @@ -2,8 +2,8 @@ // SPDX-FileCopyrightText: 2019-2022 Second State INC #pragma once -#include "common/log.h" #include "common/span.h" +#include "common/spdlog.h" #include namespace WasmEdge::Host::WASINN { @@ -21,6 +21,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 }; diff --git a/plugins/wasi_nn/wasinnenv.cpp b/plugins/wasi_nn/wasinnenv.cpp index 438c7f024554..b2228ff4208c 100644 --- a/plugins/wasi_nn/wasinnenv.cpp +++ b/plugins/wasi_nn/wasinnenv.cpp @@ -15,6 +15,7 @@ namespace Host { namespace WASINN { +namespace { Runtime::Instance::ModuleInstance * create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { return new WasiNNModule; @@ -48,6 +49,7 @@ bool load(const std::filesystem::path &Path, std::vector &Data) { File.close(); return true; } +} // namespace WasiNNEnvironment::WasiNNEnvironment() noexcept { #ifdef WASMEDGE_BUILD_WASI_NN_RPC @@ -129,6 +131,7 @@ PO::Option 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 +143,28 @@ 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, + /* 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..260a1659545a 100644 --- a/plugins/wasi_nn/wasinnenv.h +++ b/plugins/wasi_nn/wasinnenv.h @@ -3,7 +3,7 @@ #pragma once -#include "common/log.h" +#include "common/spdlog.h" #include "plugin/plugin.h" #include #include @@ -168,6 +168,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(GraphId)) { + It = MdMap.erase(It); + } else { + ++It; + } + } + } + Expect mdBuild(std::string Name, uint32_t &GraphId, Callback Load, std::vector Config = std::vector()) noexcept { @@ -206,7 +217,6 @@ struct WasiNNEnvironment : static PO::Option NNRPCURI; // For RPC client mode std::shared_ptr NNRPCChannel; #endif - static Plugin::PluginRegister Register; }; } // namespace WASINN diff --git a/plugins/wasi_nn/wasinnfunc.cpp b/plugins/wasi_nn/wasinnfunc.cpp index 6ccf2b459126..8466eaa433d1 100644 --- a/plugins/wasi_nn/wasinnfunc.cpp +++ b/plugins/wasi_nn/wasinnfunc.cpp @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: 2019-2022 Second State INC #include "wasinnfunc.h" -#include "common/log.h" +#include "common/spdlog.h" #include "wasinnenv.h" #include @@ -157,14 +157,6 @@ WasiNNLoadByName::bodyImpl(const Runtime::CallingFrame &Frame, uint32_t NamePtr, Expect 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 +184,28 @@ Expect 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()) { + spdlog::error( + "[WASI-NN] Failed when calling remote LoadByNameWithConfig: {}"sv, + Status.error_message()); + return WASINN::ErrNo::RuntimeError; + } + *GraphId = Res.graph_handle(); + return WASINN::ErrNo::Success; + } +#endif // ifdef WASMEDGE_BUILD_WASI_NN_RPC + // Get the model std::string ModelName(reinterpret_cast(Name), NameLen); std::vector ModelConfig(reinterpret_cast(Config), @@ -562,5 +576,33 @@ WasiNNFiniSingle::bodyImpl(const Runtime::CallingFrame &Frame, } } +Expect 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); + default: + spdlog::error("[WASI-NN] unlaod: Only GGML 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..dcda910cd2e8 100644 --- a/plugins/wasi_nn/wasinnfunc.h +++ b/plugins/wasi_nn/wasinnfunc.h @@ -161,5 +161,17 @@ class WasiNNFiniSingle : public WasiNN { uint32_t Context); }; +class WasiNNUnload : public WasiNN { +public: + WasiNNUnload(WASINN::WasiNNEnvironment &HostEnv) : WasiNN(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t GraphId) { + return bodyImpl(Frame, GraphId).map(castErrNo); + } + +private: + Expect 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..b2b2c6d5e4bc 100644 --- a/plugins/wasi_nn/wasinnmodule.cpp +++ b/plugins/wasi_nn/wasinnmodule.cpp @@ -21,6 +21,7 @@ WasiNNModule::WasiNNModule() : ModuleInstance("wasi_ephemeral_nn") { addHostFunc("compute", std::make_unique(Env)); addHostFunc("compute_single", std::make_unique(Env)); addHostFunc("fini_single", std::make_unique(Env)); + addHostFunc("unload", std::make_unique(Env)); } } // namespace Host diff --git a/plugins/wasi_ocr/CMakeLists.txt b/plugins/wasi_ocr/CMakeLists.txt new file mode 100644 index 000000000000..b2eef6d35b3d --- /dev/null +++ b/plugins/wasi_ocr/CMakeLists.txt @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2022 Second State INC + +add_library(wasmedgePluginWasiOCR + SHARED + wasiocrenv.cpp + wasiocrfunc.cpp + wasiocrmodule.cpp +) + +target_compile_options(wasmedgePluginWasiOCR + PUBLIC + -DWASMEDGE_PLUGIN +) + +target_include_directories(wasmedgePluginWasiOCR + PUBLIC + $ + ${CMAKE_CURRENT_SOURCE_DIR} +) + +if(WASMEDGE_LINK_PLUGINS_STATIC) + target_link_libraries(wasmedgePluginWasiOCR + PRIVATE + wasmedgeCAPI + ) +else() + target_link_libraries(wasmedgePluginWasiOCR + PRIVATE + wasmedge_shared + ) +endif() + +install(TARGETS wasmedgePluginWasiOCR 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(wasmedgePluginWasiOCR + PUBLIC + ${TESSERACT_INCLUDE_DIRS} + ${LEPTONICA_INCLUDE_DIRS} +) + +target_link_libraries(wasmedgePluginWasiOCR + PUBLIC + ${TESSERACT_LIBRARIES} + ${LEPTONICA_LIBRARIES} +) diff --git a/plugins/wasi_ocr/wasiocrbase.h b/plugins/wasi_ocr/wasiocrbase.h new file mode 100644 index 000000000000..38fd9d7225be --- /dev/null +++ b/plugins/wasi_ocr/wasiocrbase.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#pragma once + +#include "common/errcode.h" +#include "runtime/hostfunc.h" +#include "wasiocrenv.h" + +namespace WasmEdge { +namespace Host { + +template class WasiOCR : public Runtime::HostFunction { +public: + WasiOCR(WASIOCR::WasiOCREnvironment &HostEnv) + : Runtime::HostFunction(0), Env(HostEnv) {} + +protected: + WASIOCR::WasiOCREnvironment &Env; +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_ocr/wasiocrenv.cpp b/plugins/wasi_ocr/wasiocrenv.cpp new file mode 100644 index 000000000000..3df9d69c19d8 --- /dev/null +++ b/plugins/wasi_ocr/wasiocrenv.cpp @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#include "wasiocrenv.h" +#include "wasiocrmodule.h" + +namespace WasmEdge { +namespace Host { + +namespace { + +Runtime::Instance::ModuleInstance * +create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new WasiOCRModule; +} + +Plugin::Plugin::PluginDescriptor Descriptor{ + .Name = "wasi_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 = "wasi_ocr", + .Description = + "A WasmEdge Plugin for Optical Character Recognition (OCR) " + "powered by the Tesseract API.", + .Create = create, + }, + }, + .AddOptions = nullptr, +}; + +} // namespace + +Plugin::PluginRegister WASIOCR::WasiOCREnvironment::Register(&Descriptor); + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_ocr/wasiocrenv.h b/plugins/wasi_ocr/wasiocrenv.h new file mode 100644 index 000000000000..14ec756238b1 --- /dev/null +++ b/plugins/wasi_ocr/wasiocrenv.h @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#pragma once + +#include "common/spdlog.h" +#include "plugin/plugin.h" +#include + +#include +#include + +namespace WasmEdge { +namespace Host { +namespace WASIOCR { + +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 WasiOCREnvironment { +public: + WasiOCREnvironment() noexcept { + // check Tesseract API by initializing tesseract-ocr with English, without + // specifying tessdata path + if (TesseractApi->Init(NULL, "eng")) { + spdlog::error("[WASI-OCR] Error occurred when initializing tesseract."); + } + } + ~WasiOCREnvironment() noexcept { + if (TesseractApi) { + TesseractApi->End(); + ; + } + } + tesseract::TessBaseAPI *TesseractApi = new tesseract::TessBaseAPI(); + + static Plugin::PluginRegister Register; +}; + +} // namespace WASIOCR +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_ocr/wasiocrfunc.cpp b/plugins/wasi_ocr/wasiocrfunc.cpp new file mode 100644 index 000000000000..f63bd021a8b1 --- /dev/null +++ b/plugins/wasi_ocr/wasiocrfunc.cpp @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#include "wasiocrfunc.h" +#include "common/spdlog.h" + +#include +#include + +namespace WasmEdge { +namespace Host { + +Expect +WasiOCRNumOfExtractions::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(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(length); +} + +Expect WasiOCRGetOutput::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(OutBufferPtr, OutBufferMaxSize); + if (unlikely(Buf.empty())) { + spdlog::error( + "[WASI-OCR] Failed when accessing the return OutBufferPtr memory."); + return static_cast(WASIOCR::ErrNo::InvalidArgument); + } + + tesseract::PageIteratorLevel level = tesseract::RIL_WORD; + const char *outText = Env.TesseractApi->GetTSVText(level); + std::strcpy(Buf.data(), outText); + + // remaining free and deltee memory stuff + Env.TesseractApi->End(); + delete[] outText; // USE WHEN USING TESS API + + return static_cast(WASIOCR::ErrNo::Success); + // return outText; +} + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_ocr/wasiocrfunc.h b/plugins/wasi_ocr/wasiocrfunc.h new file mode 100644 index 000000000000..ad98639b7a47 --- /dev/null +++ b/plugins/wasi_ocr/wasiocrfunc.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#pragma once + +#include "runtime/callingframe.h" +#include "wasiocrbase.h" + +#include + +namespace WasmEdge { +namespace Host { + +class WasiOCRNumOfExtractions : public WasiOCR { +public: + WasiOCRNumOfExtractions(WASIOCR::WasiOCREnvironment &HostEnv) + : WasiOCR(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t ImagePathPtr, + uint32_t ImagePathLen); +}; + +class WasiOCRGetOutput : public WasiOCR { +public: + WasiOCRGetOutput(WASIOCR::WasiOCREnvironment &HostEnv) : WasiOCR(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t OutBufferPtr, + uint32_t OutBufferMaxSize); +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_ocr/wasiocrmodule.cpp b/plugins/wasi_ocr/wasiocrmodule.cpp new file mode 100644 index 000000000000..ea16f2156891 --- /dev/null +++ b/plugins/wasi_ocr/wasiocrmodule.cpp @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#include "wasiocrmodule.h" +#include "wasiocrfunc.h" + +namespace WasmEdge { +namespace Host { + +WasiOCRModule::WasiOCRModule() : ModuleInstance("wasi_ephemeral_ocr") { + addHostFunc("num_of_extractions", + std::make_unique(Env)); + addHostFunc("get_output", std::make_unique(Env)); +} + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasi_ocr/wasiocrmodule.h b/plugins/wasi_ocr/wasiocrmodule.h new file mode 100644 index 000000000000..cbab6d5c9161 --- /dev/null +++ b/plugins/wasi_ocr/wasiocrmodule.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Second State INC + +#pragma once + +#include "runtime/instance/module.h" +#include "wasiocrenv.h" + +namespace WasmEdge { +namespace Host { + +class WasiOCRModule : public Runtime::Instance::ModuleInstance { +public: + WasiOCRModule(); + + WASIOCR::WasiOCREnvironment &getEnv() { return Env; } + +private: + WASIOCR::WasiOCREnvironment Env; +}; + +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasm_bpf/wasm-bpf-module.cpp b/plugins/wasm_bpf/wasm-bpf-module.cpp index 9ae739d41a2b..6118f6ffca6b 100644 --- a/plugins/wasm_bpf/wasm-bpf-module.cpp +++ b/plugins/wasm_bpf/wasm-bpf-module.cpp @@ -53,7 +53,7 @@ Plugin::Plugin::PluginDescriptor Descriptor{ }, .AddOptions = nullptr}; -Plugin::PluginRegister Register(&Descriptor); +EXPORT_GET_DESCRIPTOR(Descriptor) } // namespace Host } // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/CMakeLists.txt b/plugins/wasmedge_ffmpeg/CMakeLists.txt new file mode 100644 index 000000000000..e78dcaa83149 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/CMakeLists.txt @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2022 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 + ffmpeg_env.cpp + + avcodec/module.cpp + avcodec/avcodec_func.cpp + avcodec/avCodecContext.cpp + avcodec/avCodec.cpp + avcodec/avCodecParameters.cpp + avcodec/avPacket.cpp + + avdevice/module.cpp + avdevice/avDevice_func.cpp + + avfilter/module.cpp + avfilter/avfilter_func.cpp + avfilter/buffer_source_sink.cpp + avfilter/avFilter.cpp + + avformat/module.cpp + avformat/avformat_func.cpp + avformat/avformatContext.cpp + avformat/avInputOutputFormat.cpp + avformat/avStream.cpp + avformat/avChapter.cpp + + avutil/module.cpp + avutil/avutil_func.cpp + avutil/error.cpp + avutil/avRational.cpp + avutil/avFrame.cpp + avutil/pixfmt.cpp + avutil/samplefmt.cpp + avutil/avDictionary.cpp + avutil/avTime.cpp + + swresample/module.cpp + swresample/swresample_func.cpp + + swscale/module.cpp + swscale/swscale_func.cpp + +) + +target_compile_options(wasmedgePluginWasmEdgeFFmpeg + PUBLIC + -DWASMEDGE_PLUGIN + -Wno-deprecated-declarations +) + +target_include_directories(wasmedgePluginWasmEdgeFFmpeg + PUBLIC + $ + ${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..242ccab043d1 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avCodec.cpp @@ -0,0 +1,241 @@ +#include "avCodec.h" + +extern "C" { +#include "libavcodec/avcodec.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +Expect AVCodecID::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return FFmpegUtils::CodecID::fromAVCodecID(AvCodec->id); +} + +Expect AVCodecType::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return FFmpegUtils::MediaType::fromMediaType(AvCodec->type); +} + +Expect AVCodecMaxLowres::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return AvCodec->max_lowres; +} + +Expect AVCodecCapabilities::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return AvCodec->capabilities; +} + +Expect AVCodecGetNameLen::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return strlen(AvCodec->name); +} + +Expect 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(ErrNo::Success); +} + +Expect AVCodecGetLongNameLen::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return strlen(AvCodec->long_name); +} + +Expect 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(ErrNo::Success); +} + +Expect AVCodecProfiles::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + if (AvCodec->profiles) + return 1; + return 0; +} + +Expect 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 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 +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 +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(ErrNo::Success); + } + + uint32_t Curr = 0; + while (Curr < Idx) { + Rational++; + Curr++; + } + + *NumId = Rational->num; + *DenId = Rational->den; + return static_cast(ErrNo::Success); +} + +Expect +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 +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 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 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 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 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..da1b5fab1fc3 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avCodec.h @@ -0,0 +1,163 @@ +#pragma once +#include "avcodec_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +class AVCodecID : public WasmEdgeFFmpegAVCodec { +public: + AVCodecID(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecType : public WasmEdgeFFmpegAVCodec { +public: + AVCodecType(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecMaxLowres : public WasmEdgeFFmpegAVCodec { +public: + AVCodecMaxLowres(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecCapabilities : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCapabilities(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecGetNameLen : public WasmEdgeFFmpegAVCodec { +public: + AVCodecGetNameLen(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecGetName : public WasmEdgeFFmpegAVCodec { +public: + AVCodecGetName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t NamePtr, uint32_t NameLen); +}; + +class AVCodecGetLongNameLen + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecGetLongNameLen(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecGetLongName : public WasmEdgeFFmpegAVCodec { +public: + AVCodecGetLongName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t LongNamePtr, uint32_t LongNameLen); +}; + +class AVCodecProfiles : public WasmEdgeFFmpegAVCodec { +public: + AVCodecProfiles(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecPixFmtsIsNull + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecPixFmtsIsNull(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecPixFmtsIter : public WasmEdgeFFmpegAVCodec { +public: + AVCodecPixFmtsIter(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t Idx); +}; + +class AVCodecSupportedFrameratesIsNull + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecSupportedFrameratesIsNull(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecSupportedFrameratesIter + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecSupportedFrameratesIter(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t Idx, uint32_t NumPtr, uint32_t DenPtr); +}; + +class AVCodecSupportedSampleRatesIsNull + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecSupportedSampleRatesIsNull(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecSupportedSampleRatesIter + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecSupportedSampleRatesIter(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t Idx); +}; + +class AVCodecChannelLayoutIsNull + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecChannelLayoutIsNull(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecChannelLayoutIter + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecChannelLayoutIter(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t Idx); +}; + +class AVCodecSampleFmtsIsNull + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecSampleFmtsIsNull(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecSampleFmtsIter + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecSampleFmtsIter(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect 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..b766ae781add --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avCodecContext.cpp @@ -0,0 +1,859 @@ +#include "avCodecContext.h" + +extern "C" { +#include "libavcodec/avcodec.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +Expect 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 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 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect AVCodecCtxWidth::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->width; +} + +Expect AVCodecCtxSetWidth::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t Width) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->width = Width; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxHeight::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->height; +} + +Expect AVCodecCtxSetHeight::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Height) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->height = Height; + return static_cast(ErrNo::Success); +} + +Expect +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(ErrNo::Success); +} + +Expect +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(ErrNo::Success); +} + +Expect 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 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(ErrNo::Success); +} + +Expect 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 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(ErrNo::Success); +} + +Expect 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 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(ErrNo::Success); +} + +Expect AVCodecCtxSampleRate::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->sample_rate; +} + +Expect AVCodecCtxSetSampleRate::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t SampleRate) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->sample_rate = SampleRate; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetGopSize::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t GopSize) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->gop_size = GopSize; + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect AVCodecCtxSetBQuantFactor::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float BQuantFactor) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->b_quant_factor = BQuantFactor; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetBQuantOffset::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float BQuantOffset) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->b_quant_offset = BQuantOffset; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetIQuantFactor::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float IQuantFactor) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->i_quant_factor = IQuantFactor; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetIQuantOffset::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float IQuantOffset) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->i_quant_offset = IQuantOffset; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetLumiMasking::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float LumiMasking) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->lumi_masking = LumiMasking; + return static_cast(ErrNo::Success); +} + +Expect +AVCodecCtxSetTemporalCplxMasking::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float TemporalCplxMasking) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->temporal_cplx_masking = TemporalCplxMasking; + return static_cast(ErrNo::Success); +} + +Expect +AVCodecCtxSetSpatialCplxMasking::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float SpatialCplxMasking) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->spatial_cplx_masking = SpatialCplxMasking; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetPMasking::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float PMasking) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->p_masking = PMasking; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetDarkMasking::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + float DarkMasking) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->dark_masking = DarkMasking; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetMeCmp::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t MeCmp) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->me_cmp = MeCmp; + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect AVCodecCtxSetMbCmp::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t MbCmp) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->mb_cmp = MbCmp; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetIldctCmp::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t IldctCmp) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->ildct_cmp = IldctCmp; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetDiaSize::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t DiaSize) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->dia_size = DiaSize; + return static_cast(ErrNo::Success); +} + +Expect +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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect +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(ErrNo::Success); +} + +Expect AVCodecCtxSetMeRange::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t MeRange) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->me_range = MeRange; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetMbDecision::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t MbDecision) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->mb_decision = MbDecision; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetMbLMin::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t MbLMin) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->mb_lmin = MbLMin; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetMbLMax::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t MbLMax) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->mb_lmax = MbLMax; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxIntraDcPrecision::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->intra_dc_precision; +} + +Expect +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(ErrNo::Success); +} + +Expect AVCodecCtxSetQMin::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t QMin) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->qmin = QMin; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetQMax::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t QMax) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->qmax = QMax; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetGlobalQuality::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t GlobalQuality) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->global_quality = GlobalQuality; + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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 AVCodecCtxSetColorRange::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t ColorRangeId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->color_range = static_cast(ColorRangeId); + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxColorRange::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVColorRange const ColorRange = AvCodecCtx->color_range; + return static_cast(ColorRange); +} + +Expect AVCodecCtxFrameSize::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->frame_size; +} + +Expect AVCodecCtxBitRate::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->bit_rate; +} + +Expect AVCodecCtxSetBitRate::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int64_t BitRate) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->bit_rate = BitRate; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxRcMaxRate::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->rc_max_rate; +} + +Expect 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(ErrNo::Success); +} + +Expect +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(ErrNo::Success); +} + +Expect +AVCodecCtxSetCompressionLevel::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t CompressionLevel) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->compression_level = CompressionLevel; + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect AVCodecCtxSetFlags::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t Flags) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->flags = Flags; + return static_cast(ErrNo::Success); +} + +Expect +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(ErrNo::Success); +} + +Expect AVCodecCtxSetDebug::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, int32_t Debug) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->debug = Debug; + return static_cast(ErrNo::Success); +} + +Expect 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), AVCodecId); + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxChannels::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->channels; +} + +Expect AVCodecCtxSetChannels::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Channels) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->channels = Channels; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetSkipLoopFilter::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t AVDiscardId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->skip_loop_filter = static_cast(AVDiscardId); + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetSkipFrame::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t AVDiscardId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->skip_frame = static_cast(AVDiscardId); + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetSkipIdct::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t AVDiscardId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->skip_idct = static_cast(AVDiscardId); + return static_cast(ErrNo::Success); +} + +Expect +AVCodecCtxSetErrorConcealment::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t ErrorConcealment) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->error_concealment = ErrorConcealment; + return static_cast(ErrNo::Success); +} + +Expect +AVCodecCtxSetErrorRecognition::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t ErrRecognition) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->err_recognition = ErrRecognition; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxDelay::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->delay; +} + +Expect AVCodecCtxSetSkipTop::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Value) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->skip_top = Value; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetSkipBottom::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Value) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->skip_bottom = Value; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxRefs::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->refs; +} + +Expect AVCodecCtxSetSliceFlags::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Value) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->slice_flags = Value; + return static_cast(ErrNo::Success); +} +Expect AVCodecCtxSetSliceCount::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Value) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->slice_count = Value; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxSetFieldOrder::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t Value) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->field_order = static_cast(Value); + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxColorTrc::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return static_cast(AvCodecCtx->color_trc); +} + +Expect +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 AVCodecCtxFrameNumber::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->frame_number; +} + +Expect AVCodecCtxBlockAlign::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->block_align; +} + +Expect +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(ErrNo::Success); +} + +Expect AVCodecCtxAudioServiceType::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AVAudioServiceType const AudioServiceType = AvCodecCtx->audio_service_type; + return static_cast(AudioServiceType); +} + +Expect AVCodecCtxHasBFrames::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->has_b_frames; +} + +Expect +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(ErrNo::Success); +} + +Expect AVCodecCtxActiveThreadType::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->active_thread_type; +} + +Expect AVCodecCtxSetThreadType::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t ThreadType) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->thread_type = ThreadType; + return static_cast(ErrNo::Success); +} + +Expect AVCodecCtxThreadCount::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + return AvCodecCtx->thread_count; +} + +Expect AVCodecCtxSetThreadCount::body(const Runtime::CallingFrame &, + uint32_t AvCodecCtxId, + int32_t ThreadCount) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AvCodecCtxId, AVCodecContext); + AvCodecCtx->thread_count = ThreadCount; + return static_cast(ErrNo::Success); +} + +Expect 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..ee39aa0be6bc --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avCodecContext.h @@ -0,0 +1,816 @@ +#pragma once +#include "avcodec_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +class AVCodecCtxCodecID : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxCodecID(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxCodecType : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxCodecType(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetCodecType + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetCodecType(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t CodecTypeId); +}; + +class AVCodecCtxSetTimebase + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetTimebase(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Num, int32_t Den); +}; + +class AVCodecCtxTimeBase : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxTimeBase(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t NumPtr, uint32_t DenPtr); +}; + +class AVCodecCtxWidth : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxWidth(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetWidth : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetWidth(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Width); +}; + +class AVCodecCtxHeight : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxHeight(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetHeight : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetHeight(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Height); +}; + +class AVCodecCtxSampleAspectRatio + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSampleAspectRatio(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t NumPtr, uint32_t DenPtr); +}; + +class AVCodecCtxSetSampleAspectRatio + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetSampleAspectRatio(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Num, int32_t Den); +}; + +class AVCodecCtxChannelLayout + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxChannelLayout(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetChannelLayout + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetChannelLayout(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint64_t ChannelLayoutId); +}; + +class AVCodecCtxPixFormat : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxPixFormat(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetPixFormat + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetPixFormat(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t PixFmtId); +}; + +class AVCodecCtxSampleFormat + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSampleFormat(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetSampleFormat + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetSampleFormat(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t SampleFmtId); +}; + +class AVCodecCtxSampleRate + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSampleRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetSampleRate + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetSampleRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t SampleRate); +}; + +class AVCodecCtxSetGopSize + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetGopSize(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t GopSize); +}; + +class AVCodecCtxSetMaxBFrames + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetMaxBFrames(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MaxBFrames); +}; + +class AVCodecCtxSetBQuantFactor + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetBQuantFactor(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float BQuantFactor); +}; + +class AVCodecCtxSetBQuantOffset + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetBQuantOffset(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float BQuantOffset); +}; + +class AVCodecCtxSetIQuantFactor + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetIQuantFactor(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float IQuantFactor); +}; + +class AVCodecCtxSetIQuantOffset + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetIQuantOffset(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float IQuantOffset); +}; + +class AVCodecCtxSetLumiMasking + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetLumiMasking(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float LumiMasking); +}; + +class AVCodecCtxSetTemporalCplxMasking + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetTemporalCplxMasking(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float TemporalCplxMasking); +}; + +class AVCodecCtxSetSpatialCplxMasking + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetSpatialCplxMasking(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float SpatialCplxMasking); +}; + +class AVCodecCtxSetPMasking + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetPMasking(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float PMasking); +}; + +class AVCodecCtxSetDarkMasking + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetDarkMasking(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, float DarkMasking); +}; + +class AVCodecCtxSetMeCmp : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetMeCmp(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MeCmp); +}; + +class AVCodecCtxSetMeSubCmp + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetMeSubCmp(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MeSubCmp); +}; + +class AVCodecCtxSetMbCmp : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetMbCmp(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MbCmp); +}; + +class AVCodecCtxSetIldctCmp + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetIldctCmp(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t IldctCmp); +}; + +class AVCodecCtxSetDiaSize + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetDiaSize(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t DiaSize); +}; + +class AVCodecCtxSetLastPredictorsCount + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetLastPredictorsCount(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t LastPredictorCount); +}; + +class AVCodecCtxSetMePreCmp + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetMePreCmp(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MePreCmp); +}; + +class AVCodecCtxSetPreDiaSize + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetPreDiaSize(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t PreDiaSize); +}; + +class AVCodecCtxSetMeSubpelQuality + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetMeSubpelQuality(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MeSubpelQuality); +}; + +class AVCodecCtxSetMeRange + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetMeRange(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MeRange); +}; + +class AVCodecCtxSetMbDecision + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetMbDecision(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MbDecision); +}; + +class AVCodecCtxSetMbLMin : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetMbLMin(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MbLMin); +}; + +class AVCodecCtxSetMbLMax : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetMbLMax(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t MbLMax); +}; + +class AVCodecCtxIntraDcPrecision + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxIntraDcPrecision(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetIntraDcPrecision + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetIntraDcPrecision(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t IntraDcPrecision); +}; + +class AVCodecCtxSetQMin : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetQMin(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t QMin); +}; + +class AVCodecCtxSetQMax : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetQMax(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t QMax); +}; + +class AVCodecCtxSetGlobalQuality + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetGlobalQuality(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t GlobalQuality); +}; + +class AVCodecCtxSetColorspace + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetColorspace(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ColorspaceId); +}; + +class AVCodecCtxColorspace + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxColorspace(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetColorRange + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetColorRange(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ColorRange); +}; + +class AVCodecCtxColorRange + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxColorRange(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxFrameSize : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxFrameSize(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxBitRate : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxBitRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetBitRate + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetBitRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int64_t BitRate); +}; + +class AVCodecCtxRcMaxRate : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxRcMaxRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetRcMaxRate + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetRcMaxRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int64_t RcMaxRate); +}; + +class AVCodecCtxSetBitRateTolerance + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetBitRateTolerance(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t BitRateTolerance); +}; + +class AVCodecCtxSetCompressionLevel + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetCompressionLevel(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t CompressionLevel); +}; + +class AVCodecCtxFrameRate : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxFrameRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t NumPtr, uint32_t DenPtr); +}; + +class AVCodecCtxSetFrameRate + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetFrameRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Num, int32_t Den); +}; + +class AVCodecCtxSetFlags : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetFlags(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Flags); +}; + +class AVCodecCtxSetStrictStdCompliance + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetStrictStdCompliance(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ComplianceId); +}; + +class AVCodecCtxSetDebug : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetDebug(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Debug); +}; + +class AVCodecCtxCodec : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxCodec(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t AvCodecPtr); +}; + +class AVCodecCtxChannels : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxChannels(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetChannels + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetChannels(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Channels); +}; + +class AVCodecCtxSetSkipLoopFilter + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetSkipLoopFilter(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t AVDicardId); +}; + +class AVCodecCtxSetSkipFrame + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetSkipFrame(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t AVDiscardId); +}; + +class AVCodecCtxSetSkipIdct + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetSkipIdct(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t AVDicardId); +}; + +class AVCodecCtxSetErrorConcealment + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetErrorConcealment(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ErrorConcealment); +}; + +class AVCodecCtxSetErrorRecognition + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetErrorRecognition(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ErrorRecognition); +}; + +class AVCodecCtxDelay : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxDelay(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetSkipTop + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetSkipTop(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Value); +}; + +class AVCodecCtxSetSkipBottom + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetSkipBottom(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Value); +}; + +class AVCodecCtxRefs : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxRefs(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetSliceFlags + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetSliceFlags(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Flags); +}; + +class AVCodecCtxSetSliceCount + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetSliceCount(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Value); +}; + +class AVCodecCtxSetFieldOrder + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetFieldOrder(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t Value); +}; + +class AVCodecCtxColorTrc : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxColorTrc(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxChromaSampleLocation + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxChromaSampleLocation(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxFrameNumber + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxFrameNumber(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxBlockAlign + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxBlockAlign(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetRequestSampleFmt + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetRequestSampleFmt(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t SampleFmtId); +}; + +class AVCodecCtxAudioServiceType + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxAudioServiceType(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxHasBFrames + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxHasBFrames(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetRequestChannelLayout + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetRequestChannelLayout(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint64_t ChannelLayoutId); +}; + +class AVCodecCtxActiveThreadType + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxActiveThreadType(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetThreadType + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetThreadType(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ThreadType); +}; + +class AVCodecCtxThreadCount + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxThreadCount(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecCtxSetThreadCount + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxSetThreadCount(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, int32_t ThreadCount); +}; + +class AVCodecCtxColorPrimaries + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecCtxColorPrimaries(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.cpp b/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.cpp new file mode 100644 index 000000000000..9ffbd830be31 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.cpp @@ -0,0 +1,38 @@ +#include "avCodecParameters.h" + +extern "C" { +#include "libavcodec/avcodec.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +Expect AVCodecParamCodecId::body(const Runtime::CallingFrame &, + uint32_t AvCodecParamId) { + + FFMPEG_PTR_FETCH(AvCodecParams, AvCodecParamId, AVCodecParameters); + return FFmpegUtils::CodecID::fromAVCodecID(AvCodecParams->codec_id); +} + +Expect AVCodecParamCodecType::body(const Runtime::CallingFrame &, + uint32_t AvCodecParamId) { + + FFMPEG_PTR_FETCH(AvCodecParams, AvCodecParamId, AVCodecParameters); + return FFmpegUtils::MediaType::fromMediaType(AvCodecParams->codec_type); +} + +Expect AVCodecParamSetCodecTag::body(const Runtime::CallingFrame &, + uint32_t AvCodecParamId, + uint32_t CodecTag) { + + FFMPEG_PTR_FETCH(AvCodecParams, AvCodecParamId, AVCodecParameters); + AvCodecParams->codec_tag = CodecTag; + return static_cast(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..9e37b7fa2110 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.h @@ -0,0 +1,39 @@ +#pragma once +#include "avcodec_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +class AVCodecParamCodecId : public WasmEdgeFFmpegAVCodec { +public: + AVCodecParamCodecId(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecParamId); +}; + +class AVCodecParamCodecType + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecParamCodecType(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecParamId); +}; + +class AVCodecParamSetCodecTag + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecParamSetCodecTag(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect 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..892a0395a8c2 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avPacket.cpp @@ -0,0 +1,189 @@ +#include "avPacket.h" + +extern "C" { +#include "libavcodec/packet.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +Expect 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(ErrNo::Success); +} + +Expect AVNewPacket::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int32_t Size) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return av_new_packet(AvPacket, Size); +} + +Expect 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 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(ErrNo::Success); +} + +Expect AVGrowPacket::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int32_t Size) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return av_grow_packet(AvPacket, Size); +} + +Expect 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(ErrNo::Success); +} + +Expect AVPacketStreamIndex::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->stream_index; +} + +Expect AVPacketSetStreamIndex::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, + int32_t StreamIdx) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + AvPacket->stream_index = StreamIdx; + return static_cast(ErrNo::Success); +} + +Expect AVPacketSize::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->size; +} + +Expect AVPacketFlags::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->flags; +} + +Expect AVPacketSetFlags::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int32_t Flags) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + AvPacket->flags = Flags; + return static_cast(ErrNo::Success); +} + +Expect AVPacketPos::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->pos; +} + +Expect AVPacketSetPos::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int64_t Pos) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + AvPacket->pos = Pos; + return static_cast(ErrNo::Success); +} + +Expect AVPacketDuration::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->duration; +} + +Expect AVPacketSetDuration::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, + int64_t Duration) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + AvPacket->duration = Duration; + return static_cast(ErrNo::Success); +} + +Expect AVPacketDts::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->dts; +} + +Expect AVPacketSetDts::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int64_t Dts) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + AvPacket->dts = Dts; + return static_cast(ErrNo::Success); +} + +Expect AVPacketPts::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + return AvPacket->pts; +} + +Expect AVPacketSetPts::body(const Runtime::CallingFrame &, + uint32_t AvPacketId, int64_t Pts) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + AvPacket->pts = Pts; + return static_cast(ErrNo::Success); +} + +Expect AVPacketIsDataNull::body(const Runtime::CallingFrame &, + uint32_t AvPacketId) { + + FFMPEG_PTR_FETCH(AvPacket, AvPacketId, AVPacket); + if (AvPacket->data == nullptr) + return 1; + return 0; +} + +Expect 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(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..5ed513a846c0 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avPacket.h @@ -0,0 +1,173 @@ +#pragma once +#include "avcodec_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +class AVPacketAlloc : public WasmEdgeFFmpegAVCodec { +public: + AVPacketAlloc(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvPacketPtr); +}; + +class AVNewPacket : public WasmEdgeFFmpegAVCodec { +public: + AVNewPacket(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int32_t Size); +}; + +class AVPacketRef : public WasmEdgeFFmpegAVCodec { +public: + AVPacketRef(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t DestPacketId, uint32_t SrcPacketId); +}; + +class AVPacketUnref : public WasmEdgeFFmpegAVCodec { +public: + AVPacketUnref(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVGrowPacket : public WasmEdgeFFmpegAVCodec { +public: + AVGrowPacket(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int32_t Size); +}; + +class AVShrinkPacket : public WasmEdgeFFmpegAVCodec { +public: + AVShrinkPacket(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int32_t Size); +}; + +class AVPacketStreamIndex : public WasmEdgeFFmpegAVCodec { +public: + AVPacketStreamIndex(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketSetStreamIndex + : public WasmEdgeFFmpegAVCodec { +public: + AVPacketSetStreamIndex(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int32_t StreamIdx); +}; + +class AVPacketSize : public WasmEdgeFFmpegAVCodec { +public: + AVPacketSize(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketFlags : public WasmEdgeFFmpegAVCodec { +public: + AVPacketFlags(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketSetFlags : public WasmEdgeFFmpegAVCodec { +public: + AVPacketSetFlags(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int32_t Flags); +}; + +class AVPacketPos : public WasmEdgeFFmpegAVCodec { +public: + AVPacketPos(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketSetPos : public WasmEdgeFFmpegAVCodec { +public: + AVPacketSetPos(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int64_t Pos); +}; + +class AVPacketDuration : public WasmEdgeFFmpegAVCodec { +public: + AVPacketDuration(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketSetDuration : public WasmEdgeFFmpegAVCodec { +public: + AVPacketSetDuration(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int64_t Duration); +}; + +class AVPacketDts : public WasmEdgeFFmpegAVCodec { +public: + AVPacketDts(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketSetDts : public WasmEdgeFFmpegAVCodec { +public: + AVPacketSetDts(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int64_t Dts); +}; + +class AVPacketPts : public WasmEdgeFFmpegAVCodec { +public: + AVPacketPts(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketSetPts : public WasmEdgeFFmpegAVCodec { +public: + AVPacketSetPts(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId, + int64_t Pts); +}; + +class AVPacketIsDataNull : public WasmEdgeFFmpegAVCodec { +public: + AVPacketIsDataNull(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvPacketId); +}; + +class AVPacketData : public WasmEdgeFFmpegAVCodec { +public: + AVPacketData(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect 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_base.h b/plugins/wasmedge_ffmpeg/avcodec/avcodec_base.h new file mode 100644 index 000000000000..e3365858b608 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avcodec_base.h @@ -0,0 +1,24 @@ +#pragma once + +#include "ffmpeg_env.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +template +class WasmEdgeFFmpegAVCodec : public Runtime::HostFunction { +public: + WasmEdgeFFmpegAVCodec(std::shared_ptr HostEnv) + : Runtime::HostFunction(0), Env(HostEnv) {} + +protected: + std::shared_ptr Env; +}; + +} // 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..91c0b9de0ae0 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avcodec_func.cpp @@ -0,0 +1,338 @@ +#include "avcodec_func.h" + +extern "C" { +#include "libavcodec/avcodec.h" +#include "libavformat/avformat.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +Expect 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(ErrNo::Success); +} + +Expect +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 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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 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 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(ErrNo::Success); + } + + FFMPEG_PTR_STORE(const_cast(AvCodec), AVCodecId); + return static_cast(ErrNo::Success); +} + +Expect AVCodecIsEncoder::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return av_codec_is_encoder(AvCodec); +} + +Expect AVCodecIsDecoder::body(const Runtime::CallingFrame &, + uint32_t AvCodecId) { + + FFMPEG_PTR_FETCH(AvCodec, AvCodecId, const AVCodec); + return av_codec_is_decoder(AvCodec); +} + +Expect 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 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 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 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 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(ErrNo::Success); + } + + FFMPEG_PTR_STORE(const_cast(AvCodec), AVCodecId); + return static_cast(ErrNo::Success); +} + +Expect 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 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 +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(ErrNo::Success); + } + + FFMPEG_PTR_STORE(const_cast(AvCodec), AVCodecId); + return static_cast(ErrNo::Success); +} + +Expect +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(ErrNo::Success); + } + + FFMPEG_PTR_STORE(const_cast(AvCodec), AVCodecId); + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect AVPacketMakeWritable::body(const Runtime::CallingFrame &, + uint32_t AVPacketId) { + + FFMPEG_PTR_FETCH(AvPacket, AVPacketId, AVPacket); + return av_packet_make_writable(AvPacket); +} + +Expect 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 AVCodecVersion::body(const Runtime::CallingFrame &) { + return avcodec_version(); +} + +Expect AVCodecFlushBuffers::body(const Runtime::CallingFrame &, + uint32_t AVCodecCtxId) { + + FFMPEG_PTR_FETCH(AvCodecCtx, AVCodecCtxId, AVCodecContext); + avcodec_flush_buffers(AvCodecCtx); + return static_cast(ErrNo::Success); +} + +Expect +AVCodecConfigurationLength::body(const Runtime::CallingFrame &) { + const char *Config = avcodec_configuration(); + return strlen(Config); +} + +Expect 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(ErrNo::Success); +} + +Expect AVCodecLicenseLength::body(const Runtime::CallingFrame &) { + + const char *License = avcodec_license(); + return strlen(License); +} + +Expect 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(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..3aabf3e1e6c2 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/avcodec_func.h @@ -0,0 +1,245 @@ +#pragma once +#include "avcodec_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVcodec { + +class AVCodecAllocContext3 + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecAllocContext3(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t AvCodecCtxPtr); +}; + +class AVCodecParametersFromContext + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecParametersFromContext(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecParamId, uint32_t AvCodecCtxId); +}; + +class AVCodecParametersFree + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecParametersFree(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecParamId); +}; + +class AVCodecFreeContext : public WasmEdgeFFmpegAVCodec { +public: + AVCodecFreeContext(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId); +}; + +class AVCodecParametersAlloc + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecParametersAlloc(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecParamPtr); +}; + +class AVCodecGetType : public WasmEdgeFFmpegAVCodec { +public: + AVCodecGetType(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecOpen2 : public WasmEdgeFFmpegAVCodec { +public: + AVCodecOpen2(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t AvCodecId, + uint32_t AvDictionaryId); +}; + +class AVCodecFindDecoder : public WasmEdgeFFmpegAVCodec { +public: + AVCodecFindDecoder(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t ID, + uint32_t AvCodecId); +}; + +class AVCodecIsEncoder : public WasmEdgeFFmpegAVCodec { +public: + AVCodecIsEncoder(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecIsDecoder : public WasmEdgeFFmpegAVCodec { +public: + AVCodecIsDecoder(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecClose : public WasmEdgeFFmpegAVCodec { +public: + AVCodecClose(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId); +}; + +class AVCodecParametersToContext + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecParametersToContext(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AvCodecId, + uint32_t AvCodecParamId); +}; + +class AVCodecReceiveFrame : public WasmEdgeFFmpegAVCodec { +public: + AVCodecReceiveFrame(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t FrameId); +}; + +class AVCodecSendPacket : public WasmEdgeFFmpegAVCodec { +public: + AVCodecSendPacket(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvCodecCtxId, uint32_t PacketId); +}; + +class AVCodecFindEncoder : public WasmEdgeFFmpegAVCodec { +public: + AVCodecFindEncoder(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t ID, + uint32_t AVCodecPtr); +}; + +class AVCodecReceivePacket + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecReceivePacket(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVCodecCtxId, uint32_t PacketId); +}; + +class AVCodecSendFrame : public WasmEdgeFFmpegAVCodec { +public: + AVCodecSendFrame(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVCodecCtxId, uint32_t FrameId); +}; + +class AVCodecFindDecoderByName + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecFindDecoderByName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AVCodecPtr, + uint32_t NamePtr, uint32_t NameLen); +}; + +class AVCodecFindEncoderByName + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecFindEncoderByName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AVCodecPtr, + uint32_t NamePtr, uint32_t NameLen); +}; + +class AVPacketRescaleTs : public WasmEdgeFFmpegAVCodec { +public: + AVPacketRescaleTs(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AVPacketId, + int32_t SrcNum, int32_t SrcDen, int32_t DestNum, + int32_t DestDen); +}; + +class AVPacketMakeWritable + : public WasmEdgeFFmpegAVCodec { +public: + AVPacketMakeWritable(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t AVPacketId); +}; + +class AVCodecParametersCopy + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecParametersCopy(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVFormatCtxId, uint32_t AVCodecParamId, + uint32_t StreamIdx); +}; + +class AVCodecVersion : public WasmEdgeFFmpegAVCodec { +public: + AVCodecVersion(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVCodecFlushBuffers : public WasmEdgeFFmpegAVCodec { +public: + AVCodecFlushBuffers(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVCodecCtxId); +}; + +class AVCodecConfigurationLength + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecConfigurationLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVCodecConfiguration + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecConfiguration(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class AVCodecLicenseLength + : public WasmEdgeFFmpegAVCodec { +public: + AVCodecLicenseLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVCodecLicense : public WasmEdgeFFmpegAVCodec { +public: + AVCodecLicense(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVCodec(HostEnv) {} + Expect 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..1b9047555740 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/module.cpp @@ -0,0 +1,361 @@ +#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 Env) + : ModuleInstance("wasmedge_ffmpeg_avcodec") { + + // avcodec_func.h + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_alloc_context3", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_parameters_from_context", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_parameters_free", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_free_context", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_parameters_alloc", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_get_type", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_open2", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_find_decoder", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_codec_is_encoder", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_codec_is_decoder", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_close", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_parameters_to_context", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_receive_frame", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_send_packet", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_find_encoder", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_receive_packet", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_send_frame", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_find_decoder_by_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_find_encoder_by_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_rescale_ts", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_make_writable", + std::make_unique(Env)); + addHostFunc( + "wasmedge_ffmpeg_avcodec_avcodec_parameters_copy", + std::make_unique(Env)); // TODO: Write Test. + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_version", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_flush_buffers", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_configuration_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_configuration", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_license_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_license", + std::make_unique(Env)); + + // avCodecContext Struct fields access + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_codec_id", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_codec_type", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_codec_type", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_time_base", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_time_base", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_width", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_width", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_height", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_height", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_sample_aspect_ratio", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_sample_aspect_ratio", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_channel_layout", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_channel_layout", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_pix_fmt", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_pix_fmt", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_sample_format", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_sample_format", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_sample_rate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_sample_rate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_gop_size", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_max_b_frames", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_b_quant_factor", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_b_quant_offset", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_i_quant_factor", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_i_quant_offset", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_lumi_masking", + std::make_unique(Env)); + addHostFunc( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_temporal_cplx_masking", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_spatial_cplx_masking", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_p_masking", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_dark_masking", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_cmp", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_sub_cmp", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_mb_cmp", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_ildct_cmp", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_dia_size", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_last_predictor_count", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_pre_cmp", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_pre_dia_size", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_subpel_quality", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_me_range", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_mb_decision", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_mb_lmin", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_mb_lmax", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_intra_dc_precision", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_intra_dc_precision", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_qmin", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_qmax", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_global_quality", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_colorspace", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_colorspace", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_color_range", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_color_range", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_frame_size", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_bit_rate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_bit_rate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_rc_max_rate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_rc_max_rate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_bit_rate_tolerance", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_compression_level", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_framerate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_framerate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_flags", + std::make_unique(Env)); + addHostFunc( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_strict_std_compliance", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_debug", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_codec", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_channels", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_channels", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_loop_filter", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_frame", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_idct", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_error_concealment", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_err_recognition", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_delay", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_top", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_skip_bottom", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_refs", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_slice_flags", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_slice_count", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_field_order", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_color_trc", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_chroma_sample_location", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_frame_number", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_block_align", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_request_sample_fmt", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_audio_service_type", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_has_b_frames", + std::make_unique(Env)); + addHostFunc( + "wasmedge_ffmpeg_avcodec_avcodeccontext_set_request_channel_layout", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_active_thread_type", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_thread_type", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_thread_count", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_set_thread_count", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodeccontext_color_primaries", + std::make_unique(Env)); + + // avCodec Struct fields access + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_id", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_type", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_max_lowres", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_capabilities", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_get_name_len", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_get_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_get_long_name_len", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_get_long_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_profiles", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_pix_fmts_is_null", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_pix_fmts_iter", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_supported_framerate_is_null", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_supported_framerate_iter", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_supported_samplerates_is_null", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_supported_samplerates_iter", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_channel_layouts_is_null", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_channel_layouts_iter", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_sample_fmts_is_null", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodec_sample_fmts_iter", + std::make_unique(Env)); + + // AVCodecParam Struct fields access. + addHostFunc("wasmedge_ffmpeg_avcodec_avcodecparam_codec_id", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodecparam_codec_type", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_avcodecparam_set_codec_tag", + std::make_unique(Env)); + + // AVPacket functions. + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_alloc", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_new_packet", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_ref", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_unref", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_grow_packet", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_shrink_packet", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_stream_index", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_set_stream_index", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_size", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_flags", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_set_flags", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_pos", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_set_pos", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_duration", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_set_duration", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_dts", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_set_dts", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_pts", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_set_pts", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_is_data_null", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avcodec_av_packet_data", + std::make_unique(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..7d3776d63bb3 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avcodec/module.h @@ -0,0 +1,19 @@ +#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 Env); +}; + +} // namespace AVcodec +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avdevice/avDevice_base.h b/plugins/wasmedge_ffmpeg/avdevice/avDevice_base.h new file mode 100644 index 000000000000..06096dd41a7a --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avdevice/avDevice_base.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ffmpeg_env.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVDevice { + +template +class WasmEdgeFFmpegAVDevice : public Runtime::HostFunction { +public: + WasmEdgeFFmpegAVDevice( + std::shared_ptr HostEnv) + : Runtime::HostFunction(0), Env(HostEnv) {} + +protected: + std::shared_ptr Env; +}; + +} // namespace AVDevice +} // 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..b52763021e7d --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avdevice/avDevice_func.cpp @@ -0,0 +1,124 @@ +#include "avDevice_func.h" + +extern "C" { +#include "libavdevice/avdevice.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVDevice { + +Expect AVDeviceRegisterAll::body(const Runtime::CallingFrame &) { + avdevice_register_all(); + return {}; +} + +Expect AVDeviceVersion::body(const Runtime::CallingFrame &) { + return avdevice_version(); +} + +Expect 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(av_malloc(sizeof(AVDeviceInfoList *))); + + int Res = avdevice_list_devices(AvFormatCtx, AvDeviceInfoList); + FFMPEG_PTR_STORE(AvDeviceInfoList, AVDeviceInfoListId); + return Res; +} + +Expect AVInputAudioDeviceNext::body(const Runtime::CallingFrame &) { + spdlog::error("[WasmEdge-FFmpeg] AVInputAudioDeviceNext unimplemented"sv); + // av_input_audio_device_next(); + return static_cast(ErrNo::UnImplemented); +} + +Expect AVInputVideoDeviceNext::body(const Runtime::CallingFrame &) { + spdlog::error("[WasmEdge-FFmpeg] AVInputVideoDeviceNext unimplemented"sv); + // av_input_video_device_next(); + return static_cast(ErrNo::UnImplemented); +} + +Expect AVOutputAudioDeviceNext::body(const Runtime::CallingFrame &) { + spdlog::error("[WasmEdge-FFmpeg] AVOutputAudioDeviceNext unimplemented"sv); + // av_output_audio_device_next(); + return static_cast(ErrNo::UnImplemented); +} + +Expect AVOutputVideoDeviceNext::body(const Runtime::CallingFrame &) { + spdlog::error("[WasmEdge-FFmpeg] AVOutputVideoDeviceNext unimplemented"sv); + // av_output_video_device_next(); + return static_cast(ErrNo::UnImplemented); +} + +Expect 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(ErrNo::Success); +} + +Expect AVDeviceNbDevices::body(const Runtime::CallingFrame &, + uint32_t AVDeviceInfoListId) { + + FFMPEG_PTR_FETCH(AvDeviceInfoList, AVDeviceInfoListId, AVDeviceInfoList *); + return (*AvDeviceInfoList)->nb_devices; +} + +Expect AVDeviceDefaultDevice::body(const Runtime::CallingFrame &, + uint32_t AVDeviceInfoListId) { + + FFMPEG_PTR_FETCH(AvDeviceInfoList, AVDeviceInfoListId, AVDeviceInfoList *); + return (*AvDeviceInfoList)->default_device; +} + +Expect +AVDeviceConfigurationLength::body(const Runtime::CallingFrame &) { + const char *Config = avdevice_configuration(); + return strlen(Config); +} + +Expect 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(ErrNo::Success); +} + +Expect AVDeviceLicenseLength::body(const Runtime::CallingFrame &) { + + const char *License = avdevice_license(); + return strlen(License); +} + +Expect 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(ErrNo::Success); +} + +} // namespace AVDevice +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/plugins/wasmedge_ffmpeg/avdevice/avDevice_func.h b/plugins/wasmedge_ffmpeg/avdevice/avDevice_func.h new file mode 100644 index 000000000000..92a1309b3b8b --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avdevice/avDevice_func.h @@ -0,0 +1,127 @@ +#pragma once + +#include "avDevice_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVDevice { + +class AVDeviceRegisterAll : public WasmEdgeFFmpegAVDevice { +public: + AVDeviceRegisterAll(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVDeviceVersion : public WasmEdgeFFmpegAVDevice { +public: + AVDeviceVersion(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVDeviceListDevices : public WasmEdgeFFmpegAVDevice { +public: + AVDeviceListDevices(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVFormatCtxId, uint32_t AVDeviceInfoListPtr); +}; + +class AVInputAudioDeviceNext + : public WasmEdgeFFmpegAVDevice { +public: + AVInputAudioDeviceNext(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect body(const Runtime::CallingFrame &); +}; + +class AVInputVideoDeviceNext + : public WasmEdgeFFmpegAVDevice { +public: + AVInputVideoDeviceNext(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect body(const Runtime::CallingFrame &); +}; + +class AVOutputAudioDeviceNext + : public WasmEdgeFFmpegAVDevice { +public: + AVOutputAudioDeviceNext(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect body(const Runtime::CallingFrame &); +}; + +class AVOutputVideoDeviceNext + : public WasmEdgeFFmpegAVDevice { +public: + AVOutputVideoDeviceNext(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect body(const Runtime::CallingFrame &); +}; + +class AVDeviceFreeListDevices + : public WasmEdgeFFmpegAVDevice { +public: + AVDeviceFreeListDevices(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVDeviceInfoListId); +}; + +class AVDeviceNbDevices : public WasmEdgeFFmpegAVDevice { +public: + AVDeviceNbDevices(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVDeviceInfoListId); +}; + +class AVDeviceDefaultDevice + : public WasmEdgeFFmpegAVDevice { +public: + AVDeviceDefaultDevice(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVDeviceInfoListId); +}; + +class AVDeviceConfigurationLength + : public WasmEdgeFFmpegAVDevice { +public: + AVDeviceConfigurationLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVDeviceConfiguration + : public WasmEdgeFFmpegAVDevice { +public: + AVDeviceConfiguration(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class AVDeviceLicenseLength + : public WasmEdgeFFmpegAVDevice { +public: + AVDeviceLicenseLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVDeviceLicense : public WasmEdgeFFmpegAVDevice { +public: + AVDeviceLicense(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVDevice(HostEnv) {} + Expect 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..a47312d5dd1a --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avdevice/module.cpp @@ -0,0 +1,38 @@ +#include "module.h" +#include "avDevice_func.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVDevice { + +WasmEdgeFFmpegAVDeviceModule::WasmEdgeFFmpegAVDeviceModule( + std::shared_ptr Env) + : ModuleInstance("wasmedge_ffmpeg_avdevice") { + + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_register_all", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_version", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_list_devices", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_free_list_devices", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_nb_devices", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_default_device", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_configuration_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_configuration", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_license_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avdevice_avdevice_license", + std::make_unique(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..57e291eb56be --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avdevice/module.h @@ -0,0 +1,19 @@ +#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 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..2d7fcf64c3c4 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/avFilter.cpp @@ -0,0 +1,149 @@ +#include "avFilter.h" + +extern "C" { +#include "libavfilter/avfilter.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +Expect AVFilterNameLength::body(const Runtime::CallingFrame &, + uint32_t FilterId) { + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + return strlen(Filter->name); +} + +Expect 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(ErrNo::Success); +} + +Expect AVFilterDescriptionLength::body(const Runtime::CallingFrame &, + uint32_t FilterId) { + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + return strlen(Filter->description); +} + +Expect 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(ErrNo::Success); +} + +Expect AVFilterNbInputs::body(const Runtime::CallingFrame &, + uint32_t FilterId) { + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + return Filter->nb_inputs; +} + +Expect AVFilterNbOutputs::body(const Runtime::CallingFrame &, + uint32_t FilterId) { + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + return Filter->nb_outputs; +} + +Expect AVFilterFlags::body(const Runtime::CallingFrame &, + uint32_t FilterId) { + + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + return Filter->flags; +} + +Expect 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(ErrNo::Success); + InOut->name = CName; + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect AVFilterInOutSetPadIdx::body(const Runtime::CallingFrame &, + uint32_t InOutId, int32_t PadIdx) { + + FFMPEG_PTR_FETCH(InOut, InOutId, AVFilterInOut); + InOut->pad_idx = PadIdx; + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect +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(ErrNo::Success); + FFMPEG_PTR_STORE(const_cast(FilterPad), FilterPadId); + return static_cast(ErrNo::Success); +} + +Expect +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(ErrNo::Success); + FFMPEG_PTR_STORE(const_cast(FilterPad), FilterPadId); + return static_cast(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..1dbf650f36e8 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/avFilter.h @@ -0,0 +1,120 @@ +#pragma once + +#include "avfilter_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +class AVFilterNameLength : public WasmEdgeFFmpegAVFilter { +public: + AVFilterNameLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FilterId); +}; + +class AVFilterName : public WasmEdgeFFmpegAVFilter { +public: + AVFilterName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FilterId, + uint32_t NamePtr, uint32_t NameLen); +}; + +class AVFilterDescriptionLength + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterDescriptionLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FilterId); +}; + +class AVFilterDescription : public WasmEdgeFFmpegAVFilter { +public: + AVFilterDescription(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FilterId, + uint32_t DescPtr, uint32_t DescLen); +}; + +class AVFilterNbInputs : public WasmEdgeFFmpegAVFilter { +public: + AVFilterNbInputs(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FilterId); +}; + +class AVFilterNbOutputs : public WasmEdgeFFmpegAVFilter { +public: + AVFilterNbOutputs(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FilterId); +}; + +class AVFilterFlags : public WasmEdgeFFmpegAVFilter { +public: + AVFilterFlags(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FilterId); +}; + +class AVFilterInOutSetName + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterInOutSetName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t InOutId, + uint32_t NamePtr, uint32_t NameLen); +}; + +class AVFilterInOutSetFilterCtx + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterInOutSetFilterCtx(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t InOutId, + uint32_t FilterCtxId); +}; + +class AVFilterInOutSetPadIdx + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterInOutSetPadIdx(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t InOutId, + int32_t PadIdx); +}; + +class AVFilterInOutSetNext + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterInOutSetNext(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t InOutId, + uint32_t NextInOutId); +}; + +class AVFilterGetInputsFilterPad + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterGetInputsFilterPad(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FilterId, + uint32_t FilterPadPtr); +}; + +class AVFilterGetOutputsFilterPad + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterGetOutputsFilterPad(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect 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_base.h b/plugins/wasmedge_ffmpeg/avfilter/avfilter_base.h new file mode 100644 index 000000000000..7ed333d95ea3 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/avfilter_base.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ffmpeg_env.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +template +class WasmEdgeFFmpegAVFilter : public Runtime::HostFunction { +public: + WasmEdgeFFmpegAVFilter( + std::shared_ptr HostEnv) + : Runtime::HostFunction(0), Env(HostEnv) {} + +protected: + std::shared_ptr Env; +}; + +} // 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..974a1b378ea0 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/avfilter_func.cpp @@ -0,0 +1,300 @@ +#include "avfilter_func.h" + +extern "C" { +#include "libavfilter/avfilter.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +Expect 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(ErrNo::Success); + FFMPEG_PTR_STORE(FilterGraph, FilterGraphId); + return static_cast(ErrNo::Success); +} + +Expect 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 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); + FFMPEG_PTR_STORE(FilterCtx, FilterCtxId); + return static_cast(ErrNo::Success); +} + +Expect 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 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(ErrNo::Success); +} + +Expect AVFilterVersion::body(const Runtime::CallingFrame &) { + return avfilter_version(); +} + +Expect 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(ErrNo::Success); + + FFMPEG_PTR_STORE(const_cast(Filter), FilterId); + return static_cast(ErrNo::Success); +} + +Expect +AVFilterConfigurationLength::body(const Runtime::CallingFrame &) { + + const char *Config = avfilter_configuration(); + return strlen(Config); +} + +Expect 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(ErrNo::Success); +} + +Expect AVFilterLicenseLength::body(const Runtime::CallingFrame &) { + + const char *License = avfilter_license(); + return strlen(License); +} + +Expect 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(ErrNo::Success); +} + +Expect 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 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(ErrNo::Success); + FFMPEG_PTR_STORE(InOut, InOutId); + return static_cast(ErrNo::Success); +} + +Expect 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 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(ErrNo::Success); +} + +Expect 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 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 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect AVFilterDrop::body(const Runtime::CallingFrame &, + uint32_t FilterId) { + + FFMPEG_PTR_FETCH(Filter, FilterId, struct AVFilter); + if (Filter == nullptr) + return static_cast(ErrNo::Success); + FFMPEG_PTR_DELETE(FilterId); + return static_cast(ErrNo::Success); +} + +Expect AVFilterPadDrop::body(const Runtime::CallingFrame &, + uint32_t FilterPadId) { + + FFMPEG_PTR_FETCH(FilterPad, FilterPadId, AVFilterPad); + if (FilterPad == nullptr) + return static_cast(ErrNo::Success); + FFMPEG_PTR_DELETE(FilterPadId); + return static_cast(ErrNo::Success); +} + +Expect AVFilterContextDrop::body(const Runtime::CallingFrame &, + uint32_t FilterCtxId) { + + FFMPEG_PTR_FETCH(FilterCtx, FilterCtxId, AVFilterContext); + if (FilterCtx == nullptr) + return static_cast(ErrNo::Success); + FFMPEG_PTR_DELETE(FilterCtxId); + return static_cast(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..b96914e206b8 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/avfilter_func.h @@ -0,0 +1,207 @@ +#pragma once + +#include "avfilter_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +class AVFilterGraphAlloc : public WasmEdgeFFmpegAVFilter { +public: + AVFilterGraphAlloc(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphPtr); +}; + +class AVFilterGraphConfig : public WasmEdgeFFmpegAVFilter { +public: + AVFilterGraphConfig(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId); +}; + +class AVFilterGraphFree : public WasmEdgeFFmpegAVFilter { +public: + AVFilterGraphFree(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId); +}; + +class AVFilterGraphGetFilter + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterGraphGetFilter(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterCtxPtr, uint32_t FilterGraphId, + uint32_t NamePtr, uint32_t NameSize); +}; + +class AVFilterGraphParsePtr + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterGraphParsePtr(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId, uint32_t FiltersString, + uint32_t FiltersSize, uint32_t InputsId, + uint32_t OutputsId); +}; + +class AVFilterInOutFree : public WasmEdgeFFmpegAVFilter { +public: + AVFilterInOutFree(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t InOutId); +}; + +class AVFilterVersion : public WasmEdgeFFmpegAVFilter { +public: + AVFilterVersion(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVFilterGetByName : public WasmEdgeFFmpegAVFilter { +public: + AVFilterGetByName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FilterPtr, + uint32_t StrPtr, uint32_t StrLen); +}; + +class AVFilterConfigurationLength + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterConfigurationLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVFilterConfiguration + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterConfiguration(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class AVFilterLicenseLength + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterLicenseLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVFilterLicense : public WasmEdgeFFmpegAVFilter { +public: + AVFilterLicense(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t LicensePtr, + uint32_t LicenseLen); +}; + +class AVFilterGraphCreateFilter + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterGraphCreateFilter(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVFilter { +public: + AVFilterInOutAlloc(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t InOutPtr); +}; + +class AVFilterPadGetNameLength + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterPadGetNameLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FilterPadId, + int32_t Idx); +}; + +class AVFilterPadGetName : public WasmEdgeFFmpegAVFilter { +public: + AVFilterPadGetName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FilterPadId, + int32_t Idx, uint32_t NamePtr, uint32_t NameLen); +}; + +class AVFilterPadGetType : public WasmEdgeFFmpegAVFilter { +public: + AVFilterPadGetType(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FilterPadId, + int32_t Idx); +}; + +class AVFilterGraphDumpLength + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterGraphDumpLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId); +}; + +class AVFilterGraphDump : public WasmEdgeFFmpegAVFilter { +public: + AVFilterGraphDump(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId, uint32_t GraphStrPtr, + uint32_t GraphStrLen); +}; + +class AVFilterFreeGraphStr + : public WasmEdgeFFmpegAVFilter { +public: + AVFilterFreeGraphStr(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterGraphId); +}; + +class AVFilterDrop : public WasmEdgeFFmpegAVFilter { +public: + AVFilterDrop(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FilterId); +}; + +class AVFilterPadDrop : public WasmEdgeFFmpegAVFilter { +public: + AVFilterPadDrop(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterPadId); +}; + +class AVFilterContextDrop : public WasmEdgeFFmpegAVFilter { +public: + AVFilterContextDrop(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect 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..0aed3697356e --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/buffer_source_sink.cpp @@ -0,0 +1,68 @@ +#include "buffer_source_sink.h" +extern "C" { +#include "libavfilter/buffersink.h" +#include "libavfilter/buffersrc.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +Expect 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 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 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(ErrNo::Success); +} + +Expect +AVBufferSrcGetNbFailedRequests::body(const Runtime::CallingFrame &, + uint32_t FilterContextId) { + + FFMPEG_PTR_FETCH(FilterCtx, FilterContextId, AVFilterContext); + return av_buffersrc_get_nb_failed_requests(FilterCtx); +} + +Expect 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 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..7119d5fa5ec3 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/buffer_source_sink.h @@ -0,0 +1,67 @@ +#pragma once + +#include "avfilter_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFilter { + +class AVBufferSinkGetFrame + : public WasmEdgeFFmpegAVFilter { +public: + AVBufferSinkGetFrame(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterContextId, uint32_t FrameId); +}; + +class AVBufferSinkGetSamples + : public WasmEdgeFFmpegAVFilter { +public: + AVBufferSinkGetSamples(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterContextId, uint32_t FrameId, + int32_t Samples); +}; + +class AvBufferSinkSetFrameSize + : public WasmEdgeFFmpegAVFilter { +public: + AvBufferSinkSetFrameSize(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterContextId, int32_t Value); +}; + +class AVBufferSrcGetNbFailedRequests + : public WasmEdgeFFmpegAVFilter { +public: + AVBufferSrcGetNbFailedRequests(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterContextId); +}; + +class AVBufferSrcAddFrame : public WasmEdgeFFmpegAVFilter { +public: + AVBufferSrcAddFrame(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t FilterContextId, uint32_t FrameId); +}; + +class AVBufferSrcClose : public WasmEdgeFFmpegAVFilter { +public: + AVBufferSrcClose(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFilter(HostEnv) {} + Expect 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..2c31e44f64e3 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/module.cpp @@ -0,0 +1,108 @@ +#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 Env) + : ModuleInstance("wasmedge_ffmpeg_avfilter") { + + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_alloc", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_config", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_free", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_get_filter", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_parse_ptr", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_inout_free", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_version", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_get_by_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_configuration_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_configuration", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_license_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_license", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_create_filter", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_inout_alloc", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_pad_get_name_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_pad_get_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_pad_get_type", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_dump_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_graph_dump", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_free_graph_str", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_drop", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_pad_drop", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_context_drop", + std::make_unique(Env)); + + // buffersrc.h && buffersink.h + addHostFunc("wasmedge_ffmpeg_avfilter_av_buffersink_get_frame", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_av_buffersink_get_samples", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_av_buffersink_set_frame_size", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_av_buffersrc_get_nb_failed_requests", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_av_buffersrc_add_frame", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_av_buffersrc_close", + std::make_unique(Env)); + + // avfilter.h + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_name_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_description_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_description", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_nb_inputs", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_nb_outputs", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_flags", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_inout_set_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_inout_set_filter_ctx", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_inout_set_pad_idx", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_inout_set_next", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_get_inputs_filter_pad", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avfilter_avfilter_get_outputs_filter_pad", + std::make_unique(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..2515e6ae516c --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avfilter/module.h @@ -0,0 +1,19 @@ +#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 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..1d5f5c41a31c --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avChapter.cpp @@ -0,0 +1,196 @@ +#include "avChapter.h" + +extern "C" { +#include "libavformat/avformat.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +Expect 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)->id; +} + +Expect 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(ErrNo::Success); +} + +Expect 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)->time_base; + *Num = AvRational.num; + *Den = AvRational.den; + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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)->start; +} + +Expect 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(ErrNo::Success); +} + +Expect 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)->end; +} + +Expect 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(ErrNo::Success); +} + +Expect 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(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(ErrNo::Success); +} + +Expect 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(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..bb40c0887794 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avChapter.h @@ -0,0 +1,103 @@ +#pragma once + +#include "avformat_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +class AVChapterId : public WasmEdgeFFmpegAVFormat { +public: + AVChapterId(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx); +}; + +class AVChapterSetId : public WasmEdgeFFmpegAVFormat { +public: + AVChapterSetId(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx, + int64_t ChapterId); +}; + +class AVChapterTimebase : public WasmEdgeFFmpegAVFormat { +public: + AVChapterTimebase(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t NumPtr, + uint32_t DenPtr, uint32_t AvFormatCtxId, + uint32_t ChapterIdx); +}; + +class AVChapterSetTimebase + : public WasmEdgeFFmpegAVFormat { +public: + AVChapterSetTimebase(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t Num, + int32_t Den, uint32_t AvFormatCtxId, + uint32_t ChapterIdx); +}; + +class AVChapterStart : public WasmEdgeFFmpegAVFormat { +public: + AVChapterStart(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx); +}; + +class AVChapterSetStart : public WasmEdgeFFmpegAVFormat { +public: + AVChapterSetStart(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx, + int64_t StartValue); +}; + +class AVChapterEnd : public WasmEdgeFFmpegAVFormat { +public: + AVChapterEnd(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx); +}; + +class AVChapterSetEnd : public WasmEdgeFFmpegAVFormat { +public: + AVChapterSetEnd(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx, + int64_t EndValue); +}; + +class AVChapterMetadata : public WasmEdgeFFmpegAVFormat { +public: + AVChapterMetadata(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t ChapterIdx, + uint32_t DictPtr); +}; + +class AVChapterSetMetadata + : public WasmEdgeFFmpegAVFormat { +public: + AVChapterSetMetadata(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect 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..5c0628f22ecd --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avInputOutputFormat.cpp @@ -0,0 +1,215 @@ +#include "avInputOutputFormat.h" + +extern "C" { +#include "libavformat/avformat.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +Expect 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 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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 +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(ErrNo::Success); +} + +Expect +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(ErrNo::Success); +} + +Expect 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 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect AVOutputFormatFlags::body(const Runtime::CallingFrame &, + uint32_t AVOutputFormatId) { + + FFMPEG_PTR_FETCH(AvOutputFormat, AVOutputFormatId, AVOutputFormat); + return AvOutputFormat->flags; +} + +Expect AVInputOutputFormatFree::body(const Runtime::CallingFrame &, + uint32_t AVInputOutputId) { + FFMPEG_PTR_DELETE(AVInputOutputId); + return static_cast(ErrNo::Success); +} + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/plugins/wasmedge_ffmpeg/avformat/avInputOutputFormat.h b/plugins/wasmedge_ffmpeg/avformat/avInputOutputFormat.h new file mode 100644 index 000000000000..9c815ff80a74 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avInputOutputFormat.h @@ -0,0 +1,144 @@ +#pragma once +#include "avformat_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +class AVIOFormatNameLength + : public WasmEdgeFFmpegAVFormat { +public: + AVIOFormatNameLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t AVIOFormatId, + uint32_t FormatType); +}; + +class AVInputFormatName : public WasmEdgeFFmpegAVFormat { +public: + AVInputFormatName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t NamePtr, + uint32_t NameLen); +}; + +class AVOutputFormatName : public WasmEdgeFFmpegAVFormat { +public: + AVOutputFormatName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t NamePtr, + uint32_t NameLen); +}; + +class AVIOFormatLongNameLength + : public WasmEdgeFFmpegAVFormat { +public: + AVIOFormatLongNameLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t AVIOFormatId, + uint32_t FormatType); +}; + +class AVInputFormatLongName + : public WasmEdgeFFmpegAVFormat { +public: + AVInputFormatLongName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t LongNamePtr, + uint32_t LongNameLen); +}; + +class AVOutputFormatLongName + : public WasmEdgeFFmpegAVFormat { +public: + AVOutputFormatLongName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t LongNamePtr, + uint32_t LongNameLen); +}; + +class AVIOFormatExtensionsLength + : public WasmEdgeFFmpegAVFormat { +public: + AVIOFormatExtensionsLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t AVIOFormatId, + uint32_t FormatType); +}; + +class AVInputFormatExtensions + : public WasmEdgeFFmpegAVFormat { +public: + AVInputFormatExtensions(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t Extensions, + uint32_t ExtensionsLen); +}; + +class AVOutputFormatExtensions + : public WasmEdgeFFmpegAVFormat { +public: + AVOutputFormatExtensions(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t Extensions, + uint32_t ExtensionsLen); +}; + +class AVIOFormatMimeTypeLength + : public WasmEdgeFFmpegAVFormat { +public: + AVIOFormatMimeTypeLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t AVIOFormatId, + uint32_t FormatType); +}; + +class AVInputFormatMimeType + : public WasmEdgeFFmpegAVFormat { +public: + AVInputFormatMimeType(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t MimeTypePtr, + uint32_t MimeTypeLen); +}; + +class AVOutputFormatMimeType + : public WasmEdgeFFmpegAVFormat { +public: + AVOutputFormatMimeType(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId, uint32_t MimeTypePtr, + uint32_t MimeTypeLen); +}; + +class AVOutputFormatFlags : public WasmEdgeFFmpegAVFormat { +public: + AVOutputFormatFlags(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVInputFormatId); +}; + +class AVInputOutputFormatFree + : public WasmEdgeFFmpegAVFormat { +public: + AVInputOutputFormatFree(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect 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..1eaebef6915d --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avStream.cpp @@ -0,0 +1,285 @@ +#include "avStream.h" + +extern "C" { +#include "libavformat/avformat.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +Expect 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)->id; +} + +Expect 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)->index; +} + +Expect 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))->codecpar; + FFMPEG_PTR_STORE(CodecParam, CodecParamId); + return static_cast(ErrNo::Success); +} + +Expect 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)->time_base; + *Num = AvRational.num; + *Den = AvRational.den; + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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)->duration; +} + +Expect 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)->start_time; +} + +Expect 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)->nb_frames; +} + +Expect 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)->disposition; +} + +Expect 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)->r_frame_rate; + *Num = AvRational.num; + *Den = AvRational.den; + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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)->avg_frame_rate; + *Num = AvRational.num; + *Den = AvRational.den; + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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(av_malloc(sizeof(AVDictionary *))); + + *AvDictionary = (*AvStream)->metadata; + FFMPEG_PTR_STORE(AvDictionary, DictId); + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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((*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..4a8956ceaaa1 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avStream.h @@ -0,0 +1,152 @@ +#pragma once + +#include "avformat_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +class AVStreamId : public WasmEdgeFFmpegAVFormat { +public: + AVStreamId(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamIndex : public WasmEdgeFFmpegAVFormat { +public: + AVStreamIndex(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamCodecPar : public WasmEdgeFFmpegAVFormat { +public: + AVStreamCodecPar(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx, + uint32_t CodecParameterPtr); +}; + +class AVStreamTimebase : public WasmEdgeFFmpegAVFormat { +public: + AVStreamTimebase(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t NumPtr, + uint32_t DenPtr, uint32_t AvFormatCtxId, + uint32_t StreamIdx); +}; + +class AVStreamSetTimebase : public WasmEdgeFFmpegAVFormat { +public: + AVStreamSetTimebase(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t Num, + uint32_t Den, uint32_t AvFormatCtxId, + uint32_t StreamIdx); +}; + +class AVStreamDuration : public WasmEdgeFFmpegAVFormat { +public: + AVStreamDuration(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamStartTime : public WasmEdgeFFmpegAVFormat { +public: + AVStreamStartTime(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamNbFrames : public WasmEdgeFFmpegAVFormat { +public: + AVStreamNbFrames(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamDisposition : public WasmEdgeFFmpegAVFormat { +public: + AVStreamDisposition(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamRFrameRate : public WasmEdgeFFmpegAVFormat { +public: + AVStreamRFrameRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t NumPtr, + uint32_t DenPtr, uint32_t AvFormatCtxId, + uint32_t StreamIdx); +}; + +class AVStreamSetRFrameRate + : public WasmEdgeFFmpegAVFormat { +public: + AVStreamSetRFrameRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t Num, + int32_t Den, uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamAvgFrameRate + : public WasmEdgeFFmpegAVFormat { +public: + AVStreamAvgFrameRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t NumPtr, + uint32_t DenPtr, uint32_t AvFormatCtxId, + uint32_t StreamIdx); +}; + +class AVStreamSetAvgFrameRate + : public WasmEdgeFFmpegAVFormat { +public: + AVStreamSetAvgFrameRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t Num, + int32_t Den, uint32_t AvFormatCtxId, uint32_t StreamIdx); +}; + +class AVStreamMetadata : public WasmEdgeFFmpegAVFormat { +public: + AVStreamMetadata(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx, + uint32_t DictPtr); +}; + +class AVStreamSetMetadata : public WasmEdgeFFmpegAVFormat { +public: + AVStreamSetMetadata(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t StreamIdx, + uint32_t DictId); +}; + +class AVStreamDiscard : public WasmEdgeFFmpegAVFormat { +public: + AVStreamDiscard(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect 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..5c9515f8ea75 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avformatContext.cpp @@ -0,0 +1,122 @@ +#include "avformatContext.h" + +extern "C" { +#include "libavformat/avformat.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +Expect 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), AvInputFormatId); + return static_cast(ErrNo::Success); +} + +Expect 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), + AvOutputFormatId); + return static_cast(ErrNo::Success); +} + +Expect AVFormatCtxProbeScore::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return AvFormatContext->probe_score; +} + +Expect AVFormatCtxNbStreams::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return AvFormatContext->nb_streams; +}; + +Expect AVFormatCtxBitRate::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return AvFormatContext->bit_rate; +} + +Expect AVFormatCtxDuration::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return AvFormatContext->duration; +} + +Expect AVFormatCtxNbChapters::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return AvFormatContext->nb_chapters; +} + +Expect AVFormatCtxSetNbChapters::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId, + uint32_t NbChapters) { + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + AvFormatContext->nb_chapters = NbChapters; + return static_cast(ErrNo::Success); +} + +Expect 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(av_malloc(sizeof(AVDictionary *))); + + *AvDictionary = AvFormatCtx->metadata; + FFMPEG_PTR_STORE(AvDictionary, DictId); + return static_cast(ErrNo::Success); +} + +Expect 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(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..90cd679e4987 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avformatContext.h @@ -0,0 +1,99 @@ +#pragma once + +#include "avformat_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +class AVFormatCtxIFormat : public WasmEdgeFFmpegAVFormat { +public: + AVFormatCtxIFormat(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t AvInputFormatPtr); +}; + +class AVFormatCtxOFormat : public WasmEdgeFFmpegAVFormat { +public: + AVFormatCtxOFormat(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t AvOutputFormatPtr); +}; + +class AVFormatCtxProbeScore + : public WasmEdgeFFmpegAVFormat { +public: + AVFormatCtxProbeScore(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatCtxNbStreams + : public WasmEdgeFFmpegAVFormat { +public: + AVFormatCtxNbStreams(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatCtxBitRate : public WasmEdgeFFmpegAVFormat { +public: + AVFormatCtxBitRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatCtxDuration : public WasmEdgeFFmpegAVFormat { +public: + AVFormatCtxDuration(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatCtxNbChapters + : public WasmEdgeFFmpegAVFormat { +public: + AVFormatCtxNbChapters(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatCtxSetNbChapters + : public WasmEdgeFFmpegAVFormat { +public: + AVFormatCtxSetNbChapters(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t NbChapters); +}; + +class AVFormatCtxMetadata : public WasmEdgeFFmpegAVFormat { +public: + AVFormatCtxMetadata(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t DictPtr); +}; + +class AVFormatCtxSetMetadata + : public WasmEdgeFFmpegAVFormat { +public: + AVFormatCtxSetMetadata(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect 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_base.h b/plugins/wasmedge_ffmpeg/avformat/avformat_base.h new file mode 100644 index 000000000000..28318eb2b871 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avformat_base.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ffmpeg_env.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +template +class WasmEdgeFFmpegAVFormat : public Runtime::HostFunction { +public: + WasmEdgeFFmpegAVFormat( + std::shared_ptr HostEnv) + : Runtime::HostFunction(0), Env(HostEnv) {} + +protected: + std::shared_ptr Env; +}; + +} // 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..545894db0205 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avformat_func.cpp @@ -0,0 +1,383 @@ +#include "avformat_func.h" + +extern "C" { +#include "libavcodec/packet.h" +#include "libavformat/avformat.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +Expect 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 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 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(ErrNo::Success); +} + +Expect AVReadPause::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return av_read_pause(AvFormatContext); +} + +Expect AVReadPlay::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return av_read_play(AvFormatContext); +} + +Expect 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 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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 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 AVIOClose::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + + FFMPEG_PTR_FETCH(AvFormatCtx, AvFormatCtxId, AVFormatContext); + avio_close(AvFormatCtx->pb); + return static_cast(ErrNo::Success); +} + +Expect AVFormatNetworkInit::body(const Runtime::CallingFrame &) { + return avformat_network_init(); +} + +Expect AVFormatNetworkDeInit::body(const Runtime::CallingFrame &) { + return avformat_network_deinit(); +} + +Expect 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 AVFormatWriteTrailer::body(const Runtime::CallingFrame &, + uint32_t AvFormatCtxId) { + + FFMPEG_PTR_FETCH(AvFormatContext, AvFormatCtxId, AVFormatContext); + return av_write_trailer(AvFormatContext); +} + +Expect 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 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 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 AVFormatVersion::body(const Runtime::CallingFrame &) { + return avformat_version(); +} + +Expect 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(av_mallocz(sizeof(AVChapter))); + FFMPEG_PTR_STORE(AvChapter, AvChapterId); + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::InternalError); + return static_cast(ErrNo::Success); +} + +Expect AVFreeP::body(const Runtime::CallingFrame &, + uint32_t AvChapterId) { + + FFMPEG_PTR_FETCH(AvChapter, AvChapterId, AVChapter); + av_freep(AvChapter); + FFMPEG_PTR_DELETE(AvChapterId); + return static_cast(ErrNo::Success); +} + +Expect 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 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 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 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 +AVFormatConfigurationLength::body(const Runtime::CallingFrame &) { + + const char *Config = avformat_configuration(); + return strlen(Config); +} + +Expect 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(ErrNo::Success); +} + +Expect AVFormatLicenseLength::body(const Runtime::CallingFrame &) { + + const char *License = avformat_license(); + return strlen(License); +} + +Expect 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(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..3cc44a3379ae --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/avformat_func.h @@ -0,0 +1,273 @@ +#pragma once + +#include "avformat_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVFormat { + +class AVFormatOpenInput : public WasmEdgeFFmpegAVFormat { +public: + AVFormatOpenInput(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxPtr, uint32_t UrlPtr, + uint32_t UrlSize, uint32_t AvInputFormatId, + uint32_t AvDictionaryId); +}; + +class AVFormatFindStreamInfo + : public WasmEdgeFFmpegAVFormat { +public: + AVFormatFindStreamInfo(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId, + uint32_t AvDictionaryId); +}; + +class AVFormatCloseInput : public WasmEdgeFFmpegAVFormat { +public: + AVFormatCloseInput(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVReadPause : public WasmEdgeFFmpegAVFormat { +public: + AVReadPause(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId); +}; + +class AVReadPlay : public WasmEdgeFFmpegAVFormat { +public: + AVReadPlay(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId); +}; + +class AVFormatSeekFile : public WasmEdgeFFmpegAVFormat { +public: + AVFormatSeekFile(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVFormat { +public: + AVDumpFormat(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, int32_t Idx, uint32_t UrlPtr, + uint32_t UrlSize, int32_t IsOutput); +}; + +class AVFormatFreeContext : public WasmEdgeFFmpegAVFormat { +public: + AVFormatFreeContext(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxPtr); +}; + +class AVFindBestStream : public WasmEdgeFFmpegAVFormat { +public: + AVFindBestStream(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVFormat { +public: + AVReadFrame(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId, + uint32_t PacketId); +}; + +class AVIOClose : public WasmEdgeFFmpegAVFormat { +public: + AVIOClose(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatNetworkInit : public WasmEdgeFFmpegAVFormat { +public: + AVFormatNetworkInit(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVFormatNetworkDeInit + : public WasmEdgeFFmpegAVFormat { +public: + AVFormatNetworkDeInit(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVFormatWriteHeader : public WasmEdgeFFmpegAVFormat { +public: + AVFormatWriteHeader(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t DictId); +}; + +class AVFormatWriteTrailer + : public WasmEdgeFFmpegAVFormat { +public: + AVFormatWriteTrailer(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId); +}; + +class AVFormatAllocOutputContext2 + : public WasmEdgeFFmpegAVFormat { +public: + AVFormatAllocOutputContext2(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVFormat { +public: + AVIOOpen(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvFormatCtxId, uint32_t FileNamePtr, + uint32_t FileNameLen, int32_t Flags); +}; + +class AVIOOpen2 : public WasmEdgeFFmpegAVFormat { +public: + AVIOOpen2(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVFormat { +public: + AVFormatVersion(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVChapterMallocz : public WasmEdgeFFmpegAVFormat { +public: + AVChapterMallocz(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVChapterPtr); +}; + +class AVChapterDynarrayAdd + : public WasmEdgeFFmpegAVFormat { +public: + AVChapterDynarrayAdd(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + + Expect body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId, + int32_t NbChaptersPtr, uint32_t AvChapterId); +}; + +class AVFreeP : public WasmEdgeFFmpegAVFormat { +public: + AVFreeP(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + + Expect body(const Runtime::CallingFrame &, uint32_t AvChapterId); +}; + +class AVInterleavedWriteFrame + : public WasmEdgeFFmpegAVFormat { +public: + AVInterleavedWriteFrame(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + + Expect body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId, + uint32_t AvPacketId); +}; + +class AVWriteFrame : public WasmEdgeFFmpegAVFormat { +public: + AVWriteFrame(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + + Expect body(const Runtime::CallingFrame &, uint32_t AvFormatCtxId, + uint32_t AvPacketId); +}; + +class AVFormatNewStream : public WasmEdgeFFmpegAVFormat { +public: + AVFormatNewStream(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AVFormatCtxId, uint32_t AVCodecId); +}; + +class AVGuessCodec : public WasmEdgeFFmpegAVFormat { +public: + AVGuessCodec(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVFormat { +public: + AVFormatConfigurationLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVFormatConfiguration + : public WasmEdgeFFmpegAVFormat { +public: + AVFormatConfiguration(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class AVFormatLicenseLength + : public WasmEdgeFFmpegAVFormat { +public: + AVFormatLicenseLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVFormatLicense : public WasmEdgeFFmpegAVFormat { +public: + AVFormatLicense(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVFormat(HostEnv) {} + Expect 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..0d1ec1087bc6 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/module.cpp @@ -0,0 +1,193 @@ +#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 Env) + : ModuleInstance("wasmedge_ffmpeg_avformat") { + + // avformat_func.h + addHostFunc("wasmedge_ffmpeg_avformat_avformat_open_input", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_find_stream_info", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_close_input", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_read_play", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_read_pause", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_dump_format", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_seek_file", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_free_context", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_find_best_stream", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_read_frame", // TODO: Write Test + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avio_close", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_network_init", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_network_deinit", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_write_header", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_write_trailer", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_alloc_output_context2", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avio_open", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avio_open2", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avchapter_mallocz", + std::make_unique(Env)); + addHostFunc( + "wasmedge_ffmpeg_avformat_avchapter_dynarray_add", // TODO: Write Test + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_avfreep", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_version", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_write_frame", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_interleaved_write_frame", + std::make_unique(Env)); + addHostFunc( + "wasmedge_ffmpeg_avformat_avformat_new_stream", // TODO: Write Test + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_av_guess_codec", // TODO: Write Test + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_configuration_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_configuration", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_license_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformat_license", + std::make_unique(Env)); + + // avformatContext Struct functions. + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_iformat", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_oformat", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_probescope", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_nb_streams", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_duration", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_bit_rate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_nb_chapters", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_set_nb_chapters", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_metadata", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avformatContext_set_metadata", + std::make_unique(Env)); + + // avInputFormat Struct functions. + addHostFunc("wasmedge_ffmpeg_avformat_avIOFormat_name_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avInputFormat_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avOutputFormat_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avIOFormat_long_name_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avInputFormat_long_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avOutputFormat_long_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avIOFormat_extensions_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avInputFormat_extensions", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avOutputFormat_extensions", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avIOFormat_mime_type_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avInputFormat_mime_type", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avOutputFormat_mime_type", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avOutputFormat_flags", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avInputOutputFormat_free", + std::make_unique(Env)); + + // avStream Struct Functions. + addHostFunc("wasmedge_ffmpeg_avformat_avStream_id", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_index", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_codecpar", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_timebase", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_set_timebase", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_duration", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_start_time", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_nb_frames", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_disposition", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_r_frame_rate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_set_r_frame_rate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_avg_frame_rate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_set_avg_frame_rate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_metadata", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_set_metadata", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avStream_discard", + std::make_unique(Env)); + + // avChapter Struct Functions. + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_id", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_set_id", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_timebase", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_set_timebase", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_start", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_set_start", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_end", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_set_end", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_metadata", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avformat_avChapter_set_metadata", + std::make_unique(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..4ab491ed22af --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avformat/module.h @@ -0,0 +1,19 @@ +#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 Env); +}; + +} // namespace AVFormat +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp b/plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp new file mode 100644 index 000000000000..047f309c8d36 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp @@ -0,0 +1,159 @@ +#include "avDictionary.h" + +extern "C" { +#include "libavutil/dict.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect 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(av_mallocz(sizeof(AVDictionary *))); + Res = av_dict_set(AvDict, Key.c_str(), Value.c_str(), Flags); + FFMPEG_PTR_STORE(AvDict, DictId); + } + + return Res; +} + +Expect 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(ErrNo::InternalError); + + if (*DestDictId) { + FFMPEG_PTR_FETCH(DestAvDict, *DestDictId, AVDictionary *); + Res = av_dict_copy(DestAvDict, *SrcAvDict, Flags); + } else { + AVDictionary **DestAvDict = + static_cast(av_mallocz(sizeof(AVDictionary *))); + av_dict_copy(DestAvDict, *SrcAvDict, Flags); + FFMPEG_PTR_STORE(DestAvDict, DestDictId); + } + + return Res; +} + +Expect 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(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(ErrNo::InternalError); + + *KeyLenId = strlen(DictEntry->key); + *ValueLenId = strlen(DictEntry->value); + return Curr; +} + +Expect 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(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(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 AVDictFree::body(const Runtime::CallingFrame &, + uint32_t DictId) { + + if (DictId == 0) + return static_cast(ErrNo::Success); + FFMPEG_PTR_FETCH(AvDict, DictId, AVDictionary *); + av_dict_free(AvDict); + FFMPEG_PTR_DELETE(DictId); + return static_cast(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..8d5a5ff1cc69 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avDictionary.h @@ -0,0 +1,59 @@ +#pragma once + +#include "avutil_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVDictSet : public WasmEdgeFFmpegAVUtil { +public: + AVDictSet(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVUtil { +public: + AVDictGet(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVUtil { +public: + AVDictGetKeyValue(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVUtil { +public: + AVDictCopy(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t DestDictId, + uint32_t SrcDictId, uint32_t Flags); +}; + +class AVDictFree : public WasmEdgeFFmpegAVUtil { +public: + AVDictFree(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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..414031d9305d --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avFrame.cpp @@ -0,0 +1,464 @@ +#include "avFrame.h" + +extern "C" { +#include "libavutil/frame.h" +#include "libavutil/pixfmt.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect AVFrameWidth::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->width; +} + +Expect AVFrameHeight::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->height; +} + +Expect AVFrameSetHeight::body(const Runtime::CallingFrame &, + uint32_t FrameId, uint32_t Height) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->height = Height; + return static_cast(ErrNo::Success); +} + +Expect AVFrameSetWidth::body(const Runtime::CallingFrame &, + uint32_t FrameId, uint32_t Width) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->width = Width; + return static_cast(ErrNo::Success); +} + +Expect 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(Format); + return FFmpegUtils::PixFmt::fromAVPixFmt(PixelFormat); +} + +Expect 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(ErrNo::Success); +} + +Expect AVFrameIsNull::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->data[0] == nullptr; +} + +Expect AVFrameLinesize::body(const Runtime::CallingFrame &, + uint32_t FrameId, uint32_t Idx) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->linesize[Idx]; +} + +Expect 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(ErrNo::Success); +} + +Expect 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 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(Format); + return FFmpegUtils::SampleFmt::toSampleID(SampleFormat); +} + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect AVFrameSetNbSamples::body(const Runtime::CallingFrame &, + uint32_t FrameId, int32_t Samples) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->nb_samples = Samples; + return static_cast(ErrNo::Success); +} + +Expect AVFrameNbSamples::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->nb_samples; +} + +Expect AVFrameSampleRate::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->sample_rate; +} + +Expect AVFrameSetSampleRate::body(const Runtime::CallingFrame &, + uint32_t FrameId, + int32_t SampleRate) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->sample_rate = SampleRate; + return static_cast(ErrNo::Success); +} + +Expect AVFrameChannels::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->channels; +} + +Expect AVFrameSetChannels::body(const Runtime::CallingFrame &, + uint32_t FrameId, int32_t Channels) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->channels = Channels; + return static_cast(ErrNo::Success); +} + +Expect 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 AVFrameBestEffortTimestamp::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->best_effort_timestamp; +} + +Expect 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 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(ErrNo::Success); +} + +Expect AVFrameInterlacedFrame::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->interlaced_frame; +} + +Expect AVFrameTopFieldFirst::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->top_field_first; +} + +Expect AVFramePaletteHasChanged::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->palette_has_changed; +} + +Expect 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 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(ErrNo::Success); +} + +Expect AVFrameColorRange::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AVColorRange const AvColorRange = AvFrame->color_range; + + return static_cast(AvColorRange); +} + +Expect AVFrameSetColorRange::body(const Runtime::CallingFrame &, + uint32_t FrameId, + int32_t ColorRangeId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->color_range = static_cast(ColorRangeId); + return static_cast(ErrNo::Success); +} + +Expect +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(Characteristic); +} + +Expect AVFrameSetColorTransferCharacteristic::body( + const Runtime::CallingFrame &, uint32_t FrameId, + int32_t ColorTransferCharacteristicId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->color_trc = + static_cast(ColorTransferCharacteristicId); + return static_cast(ErrNo::Success); +} + +Expect 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 AVFrameCodedPictureNumber::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->coded_picture_number; +} + +Expect AVFrameDisplayPictureNumber::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->display_picture_number; +} + +Expect AVFrameRepeatPict::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->repeat_pict; +} + +Expect AVFrameFlags::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->flags; +} + +Expect AVFrameQuality::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->quality; +} + +Expect 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(av_malloc(sizeof(AVDictionary *))); + + *AvDictionary = AvFrame->metadata; + FFMPEG_PTR_STORE(AvDictionary, DictId); + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect AVFrameKeyFrame::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->key_frame; +} + +Expect AVFramePts::body(const Runtime::CallingFrame &, + uint32_t FrameId) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + return AvFrame->pts; +} + +Expect AVFrameSetPts::body(const Runtime::CallingFrame &, + uint32_t FrameId, int64_t Pts) { + + FFMPEG_PTR_FETCH(AvFrame, FrameId, AVFrame); + AvFrame->pts = Pts; + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect +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(ErrNo::Success); +} + +Expect 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 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(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..3bceaa3ec8c5 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avFrame.h @@ -0,0 +1,404 @@ +#pragma once + +#include "avutil_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVFrameAlloc : public WasmEdgeFFmpegAVUtil { +public: + AVFrameAlloc(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FramePtr); +}; + +class AVFrameFree : public WasmEdgeFFmpegAVUtil { +public: + AVFrameFree(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameWidth : public WasmEdgeFFmpegAVUtil { +public: + AVFrameWidth(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameHeight : public WasmEdgeFFmpegAVUtil { +public: + AVFrameHeight(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetWidth : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetWidth(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t Width); +}; + +class AVFrameSetHeight : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetHeight(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t Height); +}; + +class AVFrameVideoFormat : public WasmEdgeFFmpegAVUtil { +public: + AVFrameVideoFormat(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetVideoFormat + : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetVideoFormat(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t AvPixFormatId); +}; + +class AVFrameIsNull : public WasmEdgeFFmpegAVUtil { +public: + AVFrameIsNull(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameLinesize : public WasmEdgeFFmpegAVUtil { +public: + AVFrameLinesize(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t Idx); +}; + +class AVFrameData : public WasmEdgeFFmpegAVUtil { +public: + AVFrameData(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t FrameBufPtr, uint32_t FrameBufLen, + uint32_t Index); +}; + +class AVFrameGetBuffer : public WasmEdgeFFmpegAVUtil { +public: + AVFrameGetBuffer(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t Align); +}; + +class AVFrameAudioFormat : public WasmEdgeFFmpegAVUtil { +public: + AVFrameAudioFormat(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetAudioFormat + : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetAudioFormat(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t SampleFormatId); +}; + +class AVFrameSetChannelLayout + : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetChannelLayout(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint64_t ChannelLayoutID); +}; + +class AVFrameSetNbSamples : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetNbSamples(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t Samples); +}; + +class AVFrameNbSamples : public WasmEdgeFFmpegAVUtil { +public: + AVFrameNbSamples(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSampleRate : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSampleRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetSampleRate : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetSampleRate(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t SampleRate); +}; + +class AVFrameChannels : public WasmEdgeFFmpegAVUtil { +public: + AVFrameChannels(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetChannels : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetChannels(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t Channels); +}; + +class AVFrameChannelLayout : public WasmEdgeFFmpegAVUtil { +public: + AVFrameChannelLayout(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameBestEffortTimestamp + : public WasmEdgeFFmpegAVUtil { +public: + AVFrameBestEffortTimestamp(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFramePictType : public WasmEdgeFFmpegAVUtil { +public: + AVFramePictType(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetPictType : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetPictType(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t PictureId); +}; + +class AVFrameInterlacedFrame + : public WasmEdgeFFmpegAVUtil { +public: + AVFrameInterlacedFrame(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameTopFieldFirst : public WasmEdgeFFmpegAVUtil { +public: + AVFrameTopFieldFirst(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFramePaletteHasChanged + : public WasmEdgeFFmpegAVUtil { +public: + AVFramePaletteHasChanged(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameColorSpace : public WasmEdgeFFmpegAVUtil { +public: + AVFrameColorSpace(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetColorSpace : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetColorSpace(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t ColorSpaceId); +}; + +class AVFrameColorRange : public WasmEdgeFFmpegAVUtil { +public: + AVFrameColorRange(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetColorRange : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetColorRange(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t ColorRangeId); +}; + +// color_transfer_characteristic + +class AVFrameColorTransferCharacteristic + : public WasmEdgeFFmpegAVUtil { +public: + AVFrameColorTransferCharacteristic(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetColorTransferCharacteristic + : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetColorTransferCharacteristic( + std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int32_t ColorTransferCharacteristicId); +}; + +class AVFrameChromaLocation + : public WasmEdgeFFmpegAVUtil { +public: + AVFrameChromaLocation(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameCodedPictureNumber + : public WasmEdgeFFmpegAVUtil { +public: + AVFrameCodedPictureNumber(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameDisplayPictureNumber + : public WasmEdgeFFmpegAVUtil { +public: + AVFrameDisplayPictureNumber(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameRepeatPict : public WasmEdgeFFmpegAVUtil { +public: + AVFrameRepeatPict(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameFlags : public WasmEdgeFFmpegAVUtil { +public: + AVFrameFlags(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameQuality : public WasmEdgeFFmpegAVUtil { +public: + AVFrameQuality(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameMetadata : public WasmEdgeFFmpegAVUtil { +public: + AVFrameMetadata(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t DictPtr); +}; + +class AVFrameSetMetadata : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetMetadata(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t DictId); +}; + +class AVFrameKeyFrame : public WasmEdgeFFmpegAVUtil { +public: + AVFrameKeyFrame(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFramePts : public WasmEdgeFFmpegAVUtil { +public: + AVFramePts(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetPts : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetPts(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + int64_t Pts); +}; + +class AVFrameCopy : public WasmEdgeFFmpegAVUtil { +public: + AVFrameCopy(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t DestFrameId, + uint32_t SrcFrameId); +}; + +class AVFrameCopyProps : public WasmEdgeFFmpegAVUtil { +public: + AVFrameCopyProps(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t DestFrameId, + uint32_t SrcFrameId); +}; + +class AVFrameSampleAspectRatio + : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSampleAspectRatio(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId, + uint32_t NumPtr, uint32_t DenPtr); +}; + +class AVFrameColorPrimaries + : public WasmEdgeFFmpegAVUtil { +public: + AVFrameColorPrimaries(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t FrameId); +}; + +class AVFrameSetColorPrimaries + : public WasmEdgeFFmpegAVUtil { +public: + AVFrameSetColorPrimaries(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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..8fbe81fd801f --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avRational.cpp @@ -0,0 +1,169 @@ +#include "avRational.h" + +extern "C" { +#include "libavutil/rational.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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 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 AVQ2d::body(const Runtime::CallingFrame &, int32_t ANum, + int32_t ADen) { + + AVRational const A = av_make_q(ANum, ADen); + return av_q2d(A); +} + +Expect 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(ErrNo::Success); +} + +Expect AVQ2IntFloat::body(const Runtime::CallingFrame &, int32_t ANum, + int32_t ADen) { + + AVRational const A = av_make_q(ANum, ADen); + return av_q2intfloat(A); +} + +Expect 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(ErrNo::Success); +} + +Expect 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..b158e6636df2 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avRational.h @@ -0,0 +1,107 @@ +#pragma once +#include "avutil_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVAddQ : public WasmEdgeFFmpegAVUtil { +public: + AVAddQ(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVUtil { +public: + AVSubQ(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVUtil { +public: + AVMulQ(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVUtil { +public: + AVDivQ(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVUtil { +public: + AVCmpQ(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, int32_t BNum, int32_t BDen); +}; + +class AVNearerQ : public WasmEdgeFFmpegAVUtil { +public: + AVNearerQ(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVUtil { +public: + AVQ2d(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen); +}; + +class AVD2Q : public WasmEdgeFFmpegAVUtil { +public: + AVD2Q(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, double_t D, + int32_t Max, uint32_t ANumPtr, uint32_t ADenPtr); +}; + +class AVQ2IntFloat : public WasmEdgeFFmpegAVUtil { +public: + AVQ2IntFloat(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen); +}; + +class AVInvQ : public WasmEdgeFFmpegAVUtil { +public: + AVInvQ(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t ANum, + int32_t ADen, uint32_t BNumPtr, uint32_t BDenPtr); +}; + +class AVReduce : public WasmEdgeFFmpegAVUtil { +public: + AVReduce(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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..1ebbb03a1920 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avTime.cpp @@ -0,0 +1,32 @@ +#include "avTime.h" + +extern "C" { +#include "libavutil/time.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect AVGetTime::body(const Runtime::CallingFrame &) { + return av_gettime(); +} + +Expect AVGetTimeRelative::body(const Runtime::CallingFrame &) { + return av_gettime_relative(); +} + +Expect +AVGetTimeRelativeIsMonotonic::body(const Runtime::CallingFrame &) { + return av_gettime_relative_is_monotonic(); +} + +Expect 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..803e404a29b5 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avTime.h @@ -0,0 +1,42 @@ +#pragma once +#include "avutil_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVGetTime : public WasmEdgeFFmpegAVUtil { +public: + AVGetTime(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVGetTimeRelative : public WasmEdgeFFmpegAVUtil { +public: + AVGetTimeRelative(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVGetTimeRelativeIsMonotonic + : public WasmEdgeFFmpegAVUtil { +public: + AVGetTimeRelativeIsMonotonic(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVUSleep : public WasmEdgeFFmpegAVUtil { +public: + AVUSleep(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t USec); +}; + +} // namespace AVUtil +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/avutil/avutil_base.h b/plugins/wasmedge_ffmpeg/avutil/avutil_base.h new file mode 100644 index 000000000000..dcf352837b0a --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avutil_base.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ffmpeg_env.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +template +class WasmEdgeFFmpegAVUtil : public Runtime::HostFunction { +public: + WasmEdgeFFmpegAVUtil( + std::shared_ptr HostEnv) + : Runtime::HostFunction(0), Env(HostEnv) {} + +protected: + std::shared_ptr Env; +}; + +} // 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..a1f20e4fc7ef --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avutil_func.cpp @@ -0,0 +1,142 @@ +#include "avutil_func.h" + +extern "C" { +#include "libavutil/avutil.h" +#include "libavutil/time.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect AVLogSetLevel::body(const Runtime::CallingFrame &, + int32_t LogLevelId) { + av_log_set_level(LogLevelId); + return {}; +} + +Expect AVLogGetLevel::body(const Runtime::CallingFrame &) { + return av_log_get_level(); +} + +Expect AVLogGetFlags::body(const Runtime::CallingFrame &) { + return av_log_get_flags(); +} + +Expect AVLogSetFlags::body(const Runtime::CallingFrame &, + int32_t FlagId) { + av_log_set_flags(FlagId); + return {}; +} + +Expect 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 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 AVUtilVersion::body(const Runtime::CallingFrame &) { + return avutil_version(); +} + +Expect +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 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 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(ErrNo::Success); +} + +Expect AVGetChannelLayoutMask::body(const Runtime::CallingFrame &, + uint64_t ChannelLayoutId) { + + uint64_t const ChannelLayout = + FFmpegUtils::ChannelLayout::fromChannelLayoutID(ChannelLayoutId); + return ChannelLayout; +} + +Expect AVGetDefaultChannelLayout::body(const Runtime::CallingFrame &, + int32_t Number) { + uint64_t const ChannelLayout = av_get_default_channel_layout(Number); + return FFmpegUtils::ChannelLayout::intoChannelLayoutID(ChannelLayout); +} + +Expect AVUtilConfigurationLength::body(const Runtime::CallingFrame &) { + const char *Config = avutil_configuration(); + return strlen(Config); +} + +Expect 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(ErrNo::Success); +} + +Expect AVUtilLicenseLength::body(const Runtime::CallingFrame &) { + + const char *License = avutil_license(); + return strlen(License); +} + +Expect 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(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..1529e94fd51b --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/avutil_func.h @@ -0,0 +1,208 @@ +#pragma once +#include "avutil_base.h" + +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVLogSetLevel : public WasmEdgeFFmpegAVUtil { +public: + AVLogSetLevel(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t LogLevelId); +}; + +class AVLogGetLevel : public WasmEdgeFFmpegAVUtil { +public: + AVLogGetLevel(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVLogSetFlags : public WasmEdgeFFmpegAVUtil { +public: + AVLogSetFlags(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t FlagsId); +}; + +class AVLogGetFlags : public WasmEdgeFFmpegAVUtil { +public: + AVLogGetFlags(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +// Option funcs. +class AVOptSetBin : public WasmEdgeFFmpegAVUtil { +public: + AVOptSetBin(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSet : public WasmEdgeFFmpegAVUtil { +public: + AVOptSet(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetInt : public WasmEdgeFFmpegAVUtil { +public: + AVOptSetInt(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetDouble : public WasmEdgeFFmpegAVUtil { +public: + AVOptSetDouble(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetQ : public WasmEdgeFFmpegAVUtil { +public: + AVOptSetQ(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetImageSize : public WasmEdgeFFmpegAVUtil { +public: + AVOptSetImageSize(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetPixelFmt : public WasmEdgeFFmpegAVUtil { +public: + AVOptSetPixelFmt(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetSampleFmt : public WasmEdgeFFmpegAVUtil { +public: + AVOptSetSampleFmt(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVOptSetChannelLayout + : public WasmEdgeFFmpegAVUtil { +public: + AVOptSetChannelLayout(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVRescaleQ : public WasmEdgeFFmpegAVUtil { +public: + AVRescaleQ(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int64_t A, + int32_t BNum, int32_t BDen, int32_t CNum, int32_t CDen); +}; + +class AVRescaleQRnd : public WasmEdgeFFmpegAVUtil { +public: + AVRescaleQRnd(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVUtil { +public: + AVUtilVersion(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &); +}; + +class AVGetChannelLayoutNbChannels + : public WasmEdgeFFmpegAVUtil { +public: + AVGetChannelLayoutNbChannels(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint64_t ChannelLayoutId); +}; + +class AVGetChannelLayoutNameLen + : public WasmEdgeFFmpegAVUtil { +public: + AVGetChannelLayoutNameLen(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint64_t ChannelLayoutId); +}; + +class AVGetChannelLayoutName + : public WasmEdgeFFmpegAVUtil { +public: + AVGetChannelLayoutName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint64_t ChannelLayoutId, uint32_t NamePtr, + uint32_t NameLen); +}; + +class AVGetChannelLayoutMask + : public WasmEdgeFFmpegAVUtil { +public: + AVGetChannelLayoutMask(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint64_t ChannelLayoutId); +}; + +class AVGetDefaultChannelLayout + : public WasmEdgeFFmpegAVUtil { +public: + AVGetDefaultChannelLayout(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + int32_t ChannelLayoutId); +}; + +class AVUtilConfigurationLength + : public WasmEdgeFFmpegAVUtil { +public: + AVUtilConfigurationLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVUtilConfiguration : public WasmEdgeFFmpegAVUtil { +public: + AVUtilConfiguration(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class AVUtilLicenseLength : public WasmEdgeFFmpegAVUtil { +public: + AVUtilLicenseLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class AVUtilLicense : public WasmEdgeFFmpegAVUtil { +public: + AVUtilLicense(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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..d918ece516f8 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/error.cpp @@ -0,0 +1,39 @@ +#include "error.h" + +extern "C" { +#include "libavutil/error.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect 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(Error.c_str()), BufLen); +} + +Expect AVUtilAVError::body(const Runtime::CallingFrame &, + int32_t ErrNum) { + return AVERROR(ErrNum); +} + +Expect 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..a813715127d5 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/error.h @@ -0,0 +1,36 @@ +#pragma once + +#include "avutil_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVUtilAVStrError : public WasmEdgeFFmpegAVUtil { +public: + AVUtilAVStrError(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t ErrNum, + uint32_t ErrBuf, uint32_t BufLen); +}; + +class AVUtilAVError : public WasmEdgeFFmpegAVUtil { +public: + AVUtilAVError(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t ErrNum); +}; + +class AVUtilAVUNError : public WasmEdgeFFmpegAVUtil { +public: + AVUtilAVUNError(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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..12588050b259 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/module.cpp @@ -0,0 +1,263 @@ +#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 Env) + : ModuleInstance("wasmedge_ffmpeg_avutil") { + + // error.h + addHostFunc("wasmedge_ffmpeg_avutil_av_strerror", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_AVERROR", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_AVUNERROR", + std::make_unique(Env)); + + // rational.h + addHostFunc("wasmedge_ffmpeg_avutil_av_add_q", std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_sub_q", std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_mul_q", std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_div_q", std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_d2q", std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_q2d", std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_inv_q", std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_q2intfloat", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_nearer_q", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_cmp_q", std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_reduce", + std::make_unique(Env)); + + // frame.h + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_alloc", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_free", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_width", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_height", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_width", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_height", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_video_format", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_video_format", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_isnull", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_linesize", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_data", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_get_buffer", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_audio_format", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_audio_format", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_nb_samples", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_channel_layout", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_nb_samples", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_sample_rate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_sample_rate", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_channels", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_channels", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_channel_layout", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_best_effort_timestamp", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_pict_type", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_pict_type", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_interlaced_frame", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_top_field_first", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_palette_has_changed", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_colorspace", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_colorspace", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_color_range", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_color_range", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_color_trc", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_color_trc", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_chroma_location", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_coded_picture_number", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_display_picture_number", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_repeat_pict", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_flags", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_quality", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_metadata", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_metadata", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_key_frame", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_pts", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_pts", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_copy", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_copy_props", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_sample_aspect_ratio", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_set_color_primaries", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_frame_color_primaries", + std::make_unique(Env)); + + // pixfmt.h (Even AvPixFmtDesc is in this file) + addHostFunc("wasmedge_ffmpeg_avutil_avpixfmtdescriptor_nb_components", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avpixfmtdescriptor_log2_chromaw", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avpixfmtdescriptor_log2_chromah", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_transfer_name_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_transfer_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_range_name_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_range_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_space_name_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_space_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_primaries_name_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_color_primaries_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_pix_format_name_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_pix_format_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_pix_format_mask", + std::make_unique(Env)); + + // samplefmt.h + addHostFunc("wasmedge_ffmpeg_avutil_av_get_packed_sample_fmt", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_planar_sample_fmt", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_sample_fmt_is_planar", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_bytes_per_sample", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_sample_fmt", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_samples_get_buffer_size", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_samples_alloc_array_and_samples", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_sample_fmt_name_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_sample_fmt_name", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_sample_fmt_mask", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_freep", + std::make_unique(Env)); + + // dict.h + addHostFunc("wasmedge_ffmpeg_avutil_av_dict_set", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_dict_get", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_dict_get_key_value", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_dict_copy", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_dict_free", + std::make_unique(Env)); + + // avutil_func.h + addHostFunc("wasmedge_ffmpeg_avutil_av_log_set_level", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_log_get_level", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_log_set_flags", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_log_get_flags", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_rescale_q", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_rescale_q_rnd", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_channel_layout_nb_channels", + std::make_unique(Env)); + addHostFunc( + "wasmedge_ffmpeg_avutil_av_get_channel_layout_name_len", // TODO: Write + std::make_unique(Env)); + addHostFunc( + "wasmedge_ffmpeg_avutil_av_get_channel_layout_name", // TODO: Write Test + std::make_unique(Env)); + addHostFunc( + "wasmedge_ffmpeg_avutil_av_get_channel_layout_mask", // TODO: Write Test + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_get_default_channel_layout", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avutil_version", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avutil_configuration_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avutil_configuration", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avutil_license_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_avutil_license", + std::make_unique(Env)); + + // time.h + addHostFunc("wasmedge_ffmpeg_avutil_av_gettime", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_gettime_relative", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_gettime_relative_is_monotonic", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_avutil_av_usleep", + std::make_unique(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..ebd35dba98ed --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/module.h @@ -0,0 +1,19 @@ +#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 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..9d5b55c2e36b --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/pixfmt.cpp @@ -0,0 +1,174 @@ +#include "pixfmt.h" +extern "C" { +#include "libavutil/pixdesc.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect +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 +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 +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 AVColorRangeNameLength::body(const Runtime::CallingFrame &, + int32_t RangeId) { + + AVColorRange const ColorRange = static_cast(RangeId); + const char *Name = av_color_range_name(ColorRange); + return strlen(Name); +} + +Expect 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(RangeId); + const char *RangeName = av_color_range_name(ColorRange); + std::copy_n(RangeName, RangeLength, RangeNameBuf.data()); + return static_cast(ErrNo::Success); +} + +Expect AVColorTransferNameLength::body(const Runtime::CallingFrame &, + int32_t TransferId) { + + AVColorTransferCharacteristic const Characteristic = + static_cast(TransferId); + const char *Name = av_color_transfer_name(Characteristic); + return strlen(Name); +} + +Expect 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(TransferId); + const char *TransferName = av_color_transfer_name(Characteristic); + std::copy_n(TransferName, TransferLength, TransferNameBuf.data()); + return static_cast(ErrNo::Success); +} + +Expect AVColorSpaceNameLength::body(const Runtime::CallingFrame &, + int32_t ColorSpaceId) { + + AVColorSpace const ColorSpace = static_cast(ColorSpaceId); + const char *Name = av_color_space_name(ColorSpace); + return strlen(Name); +} + +Expect 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(ColorSpaceId); + const char *ColorSpaceName = av_color_space_name(ColorSpace); + std::copy_n(ColorSpaceName, ColorSpaceLen, ColorSpaceBuf.data()); + return static_cast(ErrNo::Success); +} + +Expect 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 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(ErrNo::Success); +} + +Expect 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 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(ErrNo::Success); +} + +Expect AVPixelFormatMask::body(const Runtime::CallingFrame &, + uint32_t PixFormatId) { + AVPixelFormat const PixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(PixFormatId); + return static_cast(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..51126aa6178f --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/pixfmt.h @@ -0,0 +1,132 @@ +#pragma once +#include "avutil_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AvPixFmtDescriptorNbComponents + : public WasmEdgeFFmpegAVUtil { +public: + AvPixFmtDescriptorNbComponents(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId); +}; + +class AvPixFmtDescriptorLog2ChromaW + : public WasmEdgeFFmpegAVUtil { +public: + AvPixFmtDescriptorLog2ChromaW(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId); +}; + +class AvPixFmtDescriptorLog2ChromaH + : public WasmEdgeFFmpegAVUtil { +public: + AvPixFmtDescriptorLog2ChromaH(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId); +}; + +class AVColorRangeNameLength + : public WasmEdgeFFmpegAVUtil { +public: + AVColorRangeNameLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t RangeId); +}; + +class AVColorRangeName : public WasmEdgeFFmpegAVUtil { +public: + AVColorRangeName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t RangeId, + uint32_t RangeName, uint32_t RangeLength); +}; + +class AVColorTransferNameLength + : public WasmEdgeFFmpegAVUtil { +public: + AVColorTransferNameLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t TransferId); +}; + +class AVColorTransferName : public WasmEdgeFFmpegAVUtil { +public: + AVColorTransferName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t TransferId, + uint32_t TransferNamePtr, uint32_t TransferLength); +}; + +class AVColorSpaceNameLength + : public WasmEdgeFFmpegAVUtil { +public: + AVColorSpaceNameLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + int32_t ColorSpaceId); +}; + +class AVColorSpaceName : public WasmEdgeFFmpegAVUtil { +public: + AVColorSpaceName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t ColorSpaceId, + uint32_t ColorSpaceNamePtr, uint32_t ColorSpaceLen); +}; + +class AVColorPrimariesNameLength + : public WasmEdgeFFmpegAVUtil { +public: + AVColorPrimariesNameLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + int32_t ColorPrimariesId); +}; + +class AVColorPrimariesName : public WasmEdgeFFmpegAVUtil { +public: + AVColorPrimariesName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + int32_t ColorPrimariesId, uint32_t ColorPrimariesNamePtr, + uint32_t ColorPrimariesLen); +}; + +class AVPixelFormatNameLength + : public WasmEdgeFFmpegAVUtil { +public: + AVPixelFormatNameLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t AvPixFormatId); +}; + +class AVPixelFormatName : public WasmEdgeFFmpegAVUtil { +public: + AVPixelFormatName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t PixFormatId, + uint32_t PixFormatNamePtr, uint32_t PixFormatNameLen); +}; + +class AVPixelFormatMask : public WasmEdgeFFmpegAVUtil { +public: + AVPixelFormatMask(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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..f38914e6dde7 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/samplefmt.cpp @@ -0,0 +1,134 @@ +#include "samplefmt.h" +extern "C" { +#include "libavutil/samplefmt.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +Expect 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 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 AVSampleFmtIsPlanar::body(const Runtime::CallingFrame &, + uint32_t SampleFormatId) { + AVSampleFormat const AvSampleFormat = + FFmpegUtils::SampleFmt::fromSampleID(SampleFormatId); + return av_sample_fmt_is_planar(AvSampleFormat); +} + +Expect AVGetBytesPerSample::body(const Runtime::CallingFrame &, + uint32_t SampleFormatId) { + AVSampleFormat const AvSampleFormat = + FFmpegUtils::SampleFmt::fromSampleID(SampleFormatId); + return av_get_bytes_per_sample(AvSampleFormat); +} + +Expect 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 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 +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 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 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(ErrNo::Success); +} + +Expect AVGetSampleFmtMask::body(const Runtime::CallingFrame &, + uint32_t SampleFmtId) { + + AVSampleFormat const SampleFmt = + FFmpegUtils::SampleFmt::fromSampleID(SampleFmtId); + return static_cast(SampleFmt); +} + +Expect 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(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..a61907793379 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/avutil/samplefmt.h @@ -0,0 +1,105 @@ +#pragma once +#include "avutil_base.h" +#include "runtime/callingframe.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace AVUtil { + +class AVGetPlanarSampleFmt : public WasmEdgeFFmpegAVUtil { +public: + AVGetPlanarSampleFmt(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SampleFormatId); +}; + +class AVGetPackedSampleFmt : public WasmEdgeFFmpegAVUtil { +public: + AVGetPackedSampleFmt(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SampleFormatId); +}; + +class AVSampleFmtIsPlanar : public WasmEdgeFFmpegAVUtil { +public: + AVSampleFmtIsPlanar(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SampleFormatId); +}; + +class AVGetBytesPerSample : public WasmEdgeFFmpegAVUtil { +public: + AVGetBytesPerSample(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SampleFormatId); +}; + +class AVGetSampleFmt : public WasmEdgeFFmpegAVUtil { +public: + AVGetSampleFmt(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t Str, + uint32_t StrLen); +}; + +class AVSamplesGetBufferSize + : public WasmEdgeFFmpegAVUtil { +public: + AVSamplesGetBufferSize(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, int32_t NbChannels, + int32_t NbSamples, uint32_t SampleFormatId, + int32_t Align); +}; + +class AVSamplesAllocArrayAndSamples + : public WasmEdgeFFmpegAVUtil { +public: + AVSamplesAllocArrayAndSamples(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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 WasmEdgeFFmpegAVUtil { +public: + AVGetSampleFmtNameLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SampleFmtId); +}; + +class AVGetSampleFmtName : public WasmEdgeFFmpegAVUtil { +public: + AVGetSampleFmtName(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t SampleFmtId, + uint32_t SampleFmtNamePtr, uint32_t SampleFmtNameLen); +}; + +class AVGetSampleFmtMask : public WasmEdgeFFmpegAVUtil { +public: + AVGetSampleFmtMask(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SampleFmtId); +}; + +class AVFreep : public WasmEdgeFFmpegAVUtil { +public: + AVFreep(std::shared_ptr HostEnv) + : WasmEdgeFFmpegAVUtil(HostEnv) {} + Expect 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..748f59879fd5 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/bindings.h @@ -0,0 +1,4425 @@ +#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 \ No newline at end of file diff --git a/plugins/wasmedge_ffmpeg/ffmpeg_env.cpp b/plugins/wasmedge_ffmpeg/ffmpeg_env.cpp new file mode 100644 index 000000000000..f2705c4aed30 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/ffmpeg_env.cpp @@ -0,0 +1,112 @@ +#include "ffmpeg_env.h" +#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" + +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 * +createSWScale(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new WasmEdgeFFmpeg::SWScale::WasmEdgeFFmpegSWScaleModule( + WasmEdgeFFmpeg::WasmEdgeFFmpegEnv::getInstance()); +} + +Runtime::Instance::ModuleInstance * +createSWResample(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + return new WasmEdgeFFmpeg::SWResample::WasmEdgeFFmpegSWResampleModule( + 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::Instance = + std::make_shared(); + +std::shared_mutex WasmEdgeFFmpeg::WasmEdgeFFmpegEnv::Mutex; +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/plugins/wasmedge_ffmpeg/ffmpeg_env.h b/plugins/wasmedge_ffmpeg/ffmpeg_env.h new file mode 100644 index 000000000000..e584fc5dbe8a --- /dev/null +++ b/plugins/wasmedge_ffmpeg/ffmpeg_env.h @@ -0,0 +1,110 @@ +#pragma once + +#include "bindings.h" +#include "plugin/plugin.h" + +#include "vector" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +class WasmEdgeFFmpegEnv { +public: + // Singleton + static std::shared_ptr getInstance() noexcept { + std::unique_lock Lock(Mutex); + std::shared_ptr 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 FfmpegPtrMap; + static std::weak_ptr 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(ErrNo::MissingMemory); \ + } + +#define FFMPEG_PTR_FETCH(StructPtr, FFmpegStructId, Type) \ + Type *StructPtr = nullptr; \ + if (FFmpegStructId != 0) \ + StructPtr = static_cast(Env.get()->fetchData(FFmpegStructId)); + +#define MEM_SPAN_CHECK(OutSpan, MemInst, Type, BufPtr, BufLen, Message) \ + auto OutSpan = MemInst->getSpan(BufPtr, BufLen); \ + if (unlikely(OutSpan.size() != BufLen)) { \ + spdlog::error("[WasmEdge-FFmpeg] "sv Message); \ + return static_cast(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(Offset); \ + if (unlikely(OutPtr == nullptr)) { \ + spdlog::error("[WasmEdge-FFmpeg] "sv Message); \ + return static_cast(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 \ No newline at end of file diff --git a/plugins/wasmedge_ffmpeg/swresample/module.cpp b/plugins/wasmedge_ffmpeg/swresample/module.cpp new file mode 100644 index 000000000000..00d617db3f3f --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swresample/module.cpp @@ -0,0 +1,40 @@ +#include "module.h" +#include "swresample_func.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWResample { + +WasmEdgeFFmpegSWResampleModule::WasmEdgeFFmpegSWResampleModule( + std::shared_ptr Env) + : ModuleInstance("wasmedge_ffmpeg_swresample") { + + addHostFunc("wasmedge_ffmpeg_swresample_swresample_version", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swr_get_delay", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swr_init", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swr_alloc_set_opts", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_av_opt_set_dict", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swr_convert_frame", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swr_free", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swresample_configuration_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swresample_configuration", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swresample_license_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swresample_swresample_license", + std::make_unique(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..a47d966bd876 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swresample/module.h @@ -0,0 +1,20 @@ +#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 Env); +}; + +} // namespace SWResample +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/swresample/swresample_base.h b/plugins/wasmedge_ffmpeg/swresample/swresample_base.h new file mode 100644 index 000000000000..574dcd20c2ed --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swresample/swresample_base.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ffmpeg_env.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWResample { + +template +class WasmEdgeFFmpegSWResample : public Runtime::HostFunction { +public: + WasmEdgeFFmpegSWResample( + std::shared_ptr HostEnv) + : Runtime::HostFunction(0), Env(HostEnv) {} + +protected: + std::shared_ptr 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..a28e75200fe6 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swresample/swresample_func.cpp @@ -0,0 +1,126 @@ +#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 SWResampleVersion::body(const Runtime::CallingFrame &) { + return swresample_version(); +} + +Expect SWRGetDelay::body(const Runtime::CallingFrame &, + uint32_t SWRContextId, int64_t Base) { + + FFMPEG_PTR_FETCH(SWRContext, SWRContextId, SwrContext); + return swr_get_delay(SWRContext, Base); +} + +Expect SWRInit::body(const Runtime::CallingFrame &, + uint32_t SWRContextId) { + + FFMPEG_PTR_FETCH(SWRContext, SWRContextId, SwrContext); + return swr_init(SWRContext); +} + +Expect +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(ErrNo::Success); +} + +Expect 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 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 SWRFree::body(const Runtime::CallingFrame &, + uint32_t SWRContextId) { + FFMPEG_PTR_FETCH(SWRContext, SWRContextId, SwrContext); + swr_close(SWRContext); + FFMPEG_PTR_DELETE(SWRContextId); + return static_cast(ErrNo::Success); +} + +Expect +SWResampleConfigurationLength::body(const Runtime::CallingFrame &) { + const char *Config = swresample_configuration(); + return strlen(Config); +} + +Expect +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(ErrNo::Success); +} + +Expect SWResampleLicenseLength::body(const Runtime::CallingFrame &) { + + const char *License = swresample_license(); + return strlen(License); +} + +Expect 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(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..b8dd8d7fc599 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swresample/swresample_func.h @@ -0,0 +1,107 @@ +#pragma once + +#include "ffmpeg_env.h" +#include "runtime/callingframe.h" +#include "swresample_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWResample { + +class SWResampleVersion : public WasmEdgeFFmpegSWResample { +public: + SWResampleVersion(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWResample(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class SWRGetDelay : public WasmEdgeFFmpegSWResample { +public: + SWRGetDelay(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWResample(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SWRContextId, int64_t Base); +}; + +class SWRInit : public WasmEdgeFFmpegSWResample { +public: + SWRInit(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWResample(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SWRContextId); +}; + +class SWRAllocSetOpts : public WasmEdgeFFmpegSWResample { +public: + SWRAllocSetOpts(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWResample(HostEnv) {} + Expect 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 WasmEdgeFFmpegSWResample { +public: + AVOptSetDict(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWResample(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SWRContextId, uint32_t DictId); +}; + +class SWRConvertFrame : public WasmEdgeFFmpegSWResample { +public: + SWRConvertFrame(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWResample(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SWRContextId, uint32_t FrameOutputId, + uint32_t FrameInputId); +}; + +class SWRFree : public WasmEdgeFFmpegSWResample { +public: + SWRFree(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWResample(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SWRContextId); +}; + +class SWResampleConfigurationLength + : public WasmEdgeFFmpegSWResample { +public: + SWResampleConfigurationLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWResample(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class SWResampleConfiguration + : public WasmEdgeFFmpegSWResample { +public: + SWResampleConfiguration(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWResample(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class SWResampleLicenseLength + : public WasmEdgeFFmpegSWResample { +public: + SWResampleLicenseLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWResample(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class SWResampleLicense : public WasmEdgeFFmpegSWResample { +public: + SWResampleLicense(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWResample(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t LicensePtr, + uint32_t LicenseLen); +}; + +} // namespace SWResample +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/plugins/wasmedge_ffmpeg/swscale/module.cpp b/plugins/wasmedge_ffmpeg/swscale/module.cpp new file mode 100644 index 000000000000..f33cadd47b41 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swscale/module.cpp @@ -0,0 +1,74 @@ +#include "module.h" +#include "swscale_func.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWScale { + +WasmEdgeFFmpegSWScaleModule::WasmEdgeFFmpegSWScaleModule( + std::shared_ptr Env) + : ModuleInstance("wasmedge_ffmpeg_swscale") { + + addHostFunc("wasmedge_ffmpeg_swscale_swscale_version", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_swscale_configuration_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_swscale_configuration", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_swscale_license_length", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_swscale_license", + std::make_unique(Env)); + + // SwsContext + addHostFunc("wasmedge_ffmpeg_swscale_sws_getContext", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_freeContext", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_scale", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getCachedContext", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_isSupportedInput", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_isSupportedOutput", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_isSupportedEndiannessConversion", + std::make_unique(Env)); + + // SwsFilter + addHostFunc("wasmedge_ffmpeg_swscale_sws_getDefaultFilter", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getLumaH", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getLumaV", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getChromaH", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getChromaV", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_freeFilter", + std::make_unique(Env)); + + // SwsVector + addHostFunc("wasmedge_ffmpeg_swscale_sws_allocVec", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getGaussianVec", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_scaleVec", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_normalizeVec", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getCoeffVecLength", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_getCoeff", + std::make_unique(Env)); + addHostFunc("wasmedge_ffmpeg_swscale_sws_freeVec", + std::make_unique(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..bc53ee2f48cb --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swscale/module.h @@ -0,0 +1,19 @@ +#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 Env); +}; + +} // namespace SWScale +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/plugins/wasmedge_ffmpeg/swscale/swscale_base.h b/plugins/wasmedge_ffmpeg/swscale/swscale_base.h new file mode 100644 index 000000000000..32dc9cf1119f --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swscale/swscale_base.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ffmpeg_env.h" +#include "runtime/hostfunc.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWScale { + +template +class WasmEdgeFFmpegSWScale : public Runtime::HostFunction { +public: + WasmEdgeFFmpegSWScale( + std::shared_ptr HostEnv) + : Runtime::HostFunction(0), Env(HostEnv) {} + +protected: + std::shared_ptr 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..7b12660766ab --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swscale/swscale_func.cpp @@ -0,0 +1,298 @@ +#include "swscale_func.h" + +extern "C" { +#include "libavutil/frame.h" +#include "libswscale/swscale.h" +} + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWScale { + +Expect +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(ErrNo::InternalError); + FFMPEG_PTR_STORE(SwsCtx, SwsCtxId); + return static_cast(ErrNo::Success); +} + +Expect SwsFreeContext::body(const Runtime::CallingFrame &, + uint32_t SwsCtxId) { + + FFMPEG_PTR_FETCH(SwsCtx, SwsCtxId, SwsContext) + sws_freeContext(SwsCtx); + FFMPEG_PTR_DELETE(SwsCtxId); + return static_cast(ErrNo::Success); +} + +Expect 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 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(ErrNo::InternalError); + + FFMPEG_PTR_STORE(SwsCachedCtx, SwsCachedCtxId); + return static_cast(ErrNo::Success); +} + +Expect SwsIsSupportedInput::body(const Runtime::CallingFrame &, + uint32_t PixFormatId) { + AVPixelFormat const PixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(PixFormatId); + return sws_isSupportedInput(PixelFormat); +} + +Expect SwsIsSupportedOutput::body(const Runtime::CallingFrame &, + uint32_t PixFormatId) { + AVPixelFormat const PixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(PixFormatId); + return sws_isSupportedOutput(PixelFormat); +} + +Expect +SwsIsSupportedEndiannessConversion::body(const Runtime::CallingFrame &, + uint32_t PixFormatId) { + AVPixelFormat const PixelFormat = + FFmpegUtils::PixFmt::intoAVPixFmt(PixFormatId); + return sws_isSupportedEndiannessConversion(PixelFormat); +} + +Expect 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(ErrNo::InternalError); + FFMPEG_PTR_STORE(Filter, SwsFilterId); + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect SwsFreeFilter::body(const Runtime::CallingFrame &, + uint32_t SwsFilterId) { + + FFMPEG_PTR_FETCH(Filter, SwsFilterId, SwsFilter); + sws_freeFilter(Filter); + FFMPEG_PTR_DELETE(SwsFilterId); + return static_cast(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect 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(ErrNo::Success); +} + +Expect SwsScaleVec::body(const Runtime::CallingFrame &, + uint32_t SwsVectorId, double Scalar) { + + FFMPEG_PTR_FETCH(Vector, SwsVectorId, SwsVector); + sws_scaleVec(Vector, Scalar); + return static_cast(ErrNo::Success); +} + +Expect SwsNormalizeVec::body(const Runtime::CallingFrame &, + uint32_t SwsVectorId, double Height) { + + FFMPEG_PTR_FETCH(Vector, SwsVectorId, SwsVector); + sws_normalizeVec(Vector, Height); + return static_cast(ErrNo::Success); +} + +Expect 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 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(ErrNo::Success); +} + +Expect SwsFreeVec::body(const Runtime::CallingFrame &, + uint32_t SwsVectorId) { + + FFMPEG_PTR_FETCH(Vector, SwsVectorId, SwsVector); + sws_freeVec(Vector); + FFMPEG_PTR_DELETE(SwsVectorId); + return static_cast(ErrNo::Success); +} + +Expect SwscaleVersion::body(const Runtime::CallingFrame &) { + return swscale_version(); +} + +Expect +SwscaleConfigurationLength::body(const Runtime::CallingFrame &) { + const char *Config = swscale_configuration(); + return strlen(Config); +} + +Expect 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(ErrNo::Success); +} + +Expect SwscaleLicenseLength::body(const Runtime::CallingFrame &) { + + const char *License = swscale_license(); + return strlen(License); +} + +Expect 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(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..dfb7ffbf6be4 --- /dev/null +++ b/plugins/wasmedge_ffmpeg/swscale/swscale_func.h @@ -0,0 +1,226 @@ +#pragma once + +#include "runtime/callingframe.h" +#include "swscale_base.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +namespace SWScale { + +class SwsGetContext : public WasmEdgeFFmpegSWScale { +public: + SwsGetContext(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect 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 WasmEdgeFFmpegSWScale { +public: + SwsFreeContext(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t SwsCtxId); +}; + +class SwsScale : public WasmEdgeFFmpegSWScale { +public: + SwsScale(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t SwsCtxId, + uint32_t InputFrameId, int32_t SrcSliceY, + int32_t SrcSliceH, uint32_t OutputFrameId); +}; + +class SwsGetCachedContext : public WasmEdgeFFmpegSWScale { +public: + SwsGetCachedContext(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect 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 WasmEdgeFFmpegSWScale { +public: + SwsIsSupportedInput(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId); +}; + +class SwsIsSupportedOutput + : public WasmEdgeFFmpegSWScale { +public: + SwsIsSupportedOutput(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId); +}; + +class SwsIsSupportedEndiannessConversion + : public WasmEdgeFFmpegSWScale { +public: + SwsIsSupportedEndiannessConversion(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t PixFormatId); +}; + +class SwsGetDefaultFilter : public WasmEdgeFFmpegSWScale { +public: + SwsGetDefaultFilter(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect 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 WasmEdgeFFmpegSWScale { +public: + SwsGetLumaH(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t SwsFilterId, + uint32_t SwsVectorPtr); +}; + +class SwsGetLumaV : public WasmEdgeFFmpegSWScale { +public: + SwsGetLumaV(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t SwsFilterId, + uint32_t SwsVectorPtr); +}; + +class SwsGetChromaH : public WasmEdgeFFmpegSWScale { +public: + SwsGetChromaH(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t SwsFilterId, + uint32_t SwsVectorPtr); +}; + +class SwsGetChromaV : public WasmEdgeFFmpegSWScale { +public: + SwsGetChromaV(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t SwsFilterId, + uint32_t SwsVectorPtr); +}; + +class SwsFreeFilter : public WasmEdgeFFmpegSWScale { +public: + SwsFreeFilter(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SwsFilterId); +}; + +class SwsAllocVec : public WasmEdgeFFmpegSWScale { +public: + SwsAllocVec(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SwsVectorPtr, int32_t Length); +}; + +class SwsGetGaussianVec : public WasmEdgeFFmpegSWScale { +public: + SwsGetGaussianVec(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SwsVectorPtr, double Variance, double Quality); +}; + +class SwsScaleVec : public WasmEdgeFFmpegSWScale { +public: + SwsScaleVec(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t SwsVectorId, + double Scalar); +}; + +class SwsNormalizeVec : public WasmEdgeFFmpegSWScale { +public: + SwsNormalizeVec(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t SwsVectorId, + double Height); +}; + +class SwsGetCoeffVecLength + : public WasmEdgeFFmpegSWScale { +public: + SwsGetCoeffVecLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t SwsVectorId); +}; + +class SwsGetCoeff : public WasmEdgeFFmpegSWScale { +public: + SwsGetCoeff(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t SwsVectorId, + uint32_t CoeffBuf, uint32_t Len); +}; + +class SwsFreeVec : public WasmEdgeFFmpegSWScale { +public: + SwsFreeVec(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, + uint32_t SwsVectorId); +}; + +class SwscaleVersion : public WasmEdgeFFmpegSWScale { +public: + SwscaleVersion(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class SwscaleConfigurationLength + : public WasmEdgeFFmpegSWScale { +public: + SwscaleConfigurationLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class SwscaleConfiguration + : public WasmEdgeFFmpegSWScale { +public: + SwscaleConfiguration(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame, uint32_t ConfigPtr, + uint32_t ConfigLen); +}; + +class SwscaleLicenseLength + : public WasmEdgeFFmpegSWScale { +public: + SwscaleLicenseLength(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect body(const Runtime::CallingFrame &Frame); +}; + +class SwscaleLicense : public WasmEdgeFFmpegSWScale { +public: + SwscaleLicense(std::shared_ptr HostEnv) + : WasmEdgeFFmpegSWScale(HostEnv) {} + Expect 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/image_env.cpp b/plugins/wasmedge_image/image_env.cpp index 022787ca2b17..a1f104aea5c8 100644 --- a/plugins/wasmedge_image/image_env.cpp +++ b/plugins/wasmedge_image/image_env.cpp @@ -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..b2b59c2c61da 100644 --- a/plugins/wasmedge_image/image_env.h +++ b/plugins/wasmedge_image/image_env.h @@ -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..0088ebffe72e 100644 --- a/plugins/wasmedge_image/image_func.cpp +++ b/plugins/wasmedge_image/image_func.cpp @@ -3,8 +3,8 @@ #include "image_func.h" -#include "common/log.h" #include "common/span.h" +#include "common/spdlog.h" #include #include diff --git a/plugins/wasmedge_opencvmini/opencvmini_env.cpp b/plugins/wasmedge_opencvmini/opencvmini_env.cpp index c205d7f4c8f5..d5211492ae16 100644 --- a/plugins/wasmedge_opencvmini/opencvmini_env.cpp +++ b/plugins/wasmedge_opencvmini/opencvmini_env.cpp @@ -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..f2e606cb99d5 100644 --- a/plugins/wasmedge_opencvmini/opencvmini_env.h +++ b/plugins/wasmedge_opencvmini/opencvmini_env.h @@ -16,8 +16,6 @@ class WasmEdgeOpenCVMiniEnvironment { public: WasmEdgeOpenCVMiniEnvironment() noexcept; - static Plugin::PluginRegister Register; - std::map MatPool; Expect getMat(uint32_t MatKey) { diff --git a/plugins/wasmedge_process/processenv.cpp b/plugins/wasmedge_process/processenv.cpp index 8c769a336426..32a318f79496 100644 --- a/plugins/wasmedge_process/processenv.cpp +++ b/plugins/wasmedge_process/processenv.cpp @@ -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..a7dc11616174 100644 --- a/plugins/wasmedge_process/processenv.h +++ b/plugins/wasmedge_process/processenv.h @@ -46,7 +46,6 @@ class WasmEdgeProcessEnvironment { static PO::List AllowCmd; static PO::Option AllowCmdAll; - static Plugin::PluginRegister Register; }; } // namespace Host diff --git a/plugins/wasmedge_rustls/CMakeLists.txt b/plugins/wasmedge_rustls/CMakeLists.txt index 56069740f2ea..739aea924d21 100644 --- a/plugins/wasmedge_rustls/CMakeLists.txt +++ b/plugins/wasmedge_rustls/CMakeLists.txt @@ -6,14 +6,14 @@ else() set(TARGET_DIR "release") endif() -set(RS_SO ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_DIR}/libwasmedge_rustls${CMAKE_SHARED_LIBRARY_SUFFIX}) +set(RS_SO ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}wasmedge_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} + COMMAND ${CMAKE_COMMAND} -E env WASMEDGE_LIB_DIR=${WASMEDGE_LIB_DIR} CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR} -- ${CARGO_CMD} + COMMAND ${CMAKE_COMMAND} -E copy ${RS_SO} ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E rm -rf ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS wasmedge_shared ) diff --git a/plugins/wasmedge_tensorflow/tensorflow_env.cpp b/plugins/wasmedge_tensorflow/tensorflow_env.cpp index 9a672863758f..04fb55072746 100644 --- a/plugins/wasmedge_tensorflow/tensorflow_env.cpp +++ b/plugins/wasmedge_tensorflow/tensorflow_env.cpp @@ -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..46160dcb6918 100644 --- a/plugins/wasmedge_tensorflow/tensorflow_env.h +++ b/plugins/wasmedge_tensorflow/tensorflow_env.h @@ -117,8 +117,6 @@ struct TFEnv { } } - static Plugin::PluginRegister Register; - private: std::unordered_set RecycledIdx; std::vector TFContext; diff --git a/plugins/wasmedge_tensorflow/tensorflow_func.cpp b/plugins/wasmedge_tensorflow/tensorflow_func.cpp index eed2b4fc64ec..6b4ba440facf 100644 --- a/plugins/wasmedge_tensorflow/tensorflow_func.cpp +++ b/plugins/wasmedge_tensorflow/tensorflow_func.cpp @@ -3,8 +3,8 @@ #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_tensorflowlite/tensorflowlite_env.cpp b/plugins/wasmedge_tensorflowlite/tensorflowlite_env.cpp index 47a3e037e760..a6d194eaf078 100644 --- a/plugins/wasmedge_tensorflowlite/tensorflowlite_env.cpp +++ b/plugins/wasmedge_tensorflowlite/tensorflowlite_env.cpp @@ -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..188ab9c2d837 100644 --- a/plugins/wasmedge_tensorflowlite/tensorflowlite_env.h +++ b/plugins/wasmedge_tensorflowlite/tensorflowlite_env.h @@ -63,8 +63,6 @@ struct TFLiteEnv { } } - static Plugin::PluginRegister Register; - private: std::unordered_set RecycledIdx; std::vector TFLiteContext; diff --git a/plugins/wasmedge_tensorflowlite/tensorflowlite_func.cpp b/plugins/wasmedge_tensorflowlite/tensorflowlite_func.cpp index 18af8a1bf892..0976dd13aa28 100644 --- a/plugins/wasmedge_tensorflowlite/tensorflowlite_func.cpp +++ b/plugins/wasmedge_tensorflowlite/tensorflowlite_func.cpp @@ -3,8 +3,8 @@ #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_zlib/CMakeLists.txt b/plugins/wasmedge_zlib/CMakeLists.txt index 30fa7d733d40..f12889bfb276 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 -# 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,13 +27,13 @@ if(WASMEDGE_LINK_PLUGINS_STATIC) target_link_libraries(wasmedgePluginWasmEdgeZlib PRIVATE wasmedgeCAPI - zlib + z ) else() target_link_libraries(wasmedgePluginWasmEdgeZlib PRIVATE wasmedge_shared - zlib + z ) endif() diff --git a/plugins/wasmedge_zlib/zlibenv.cpp b/plugins/wasmedge_zlib/zlibenv.cpp index 45654a288e4b..f00a9ef75afa 100644 --- a/plugins/wasmedge_zlib/zlibenv.cpp +++ b/plugins/wasmedge_zlib/zlibenv.cpp @@ -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..190025cdbe0e 100644 --- a/plugins/wasmedge_zlib/zlibenv.h +++ b/plugins/wasmedge_zlib/zlibenv.h @@ -91,9 +91,6 @@ class WasmEdgeZlibEnvironment { std::unordered_map> ZStreamMap; std::map, std::greater> GZFileMap; std::unordered_map GZHeaderMap; - - /// Initial Configurations - static Plugin::PluginRegister Register; }; } // namespace Host diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 73405ee189fb..fd701cb9bd3c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -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 release-1.11.0 + 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 + $<$:-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 + $<$:-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/CMakeLists.txt b/test/aot/CMakeLists.txt index b49c48042a7d..a272b5e1c3e8 100644 --- a/test/aot/CMakeLists.txt +++ b/test/aot/CMakeLists.txt @@ -1,22 +1,6 @@ # 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 -) - wasmedge_add_executable(wasmedgeAOTCacheTests AOTCacheTest.cpp ) diff --git a/test/api/APIUnitTest.cpp b/test/api/APIUnitTest.cpp index 289671cc7475..9a3b365276db 100644 --- a/test/api/APIUnitTest.cpp +++ b/test/api/APIUnitTest.cpp @@ -19,6 +19,8 @@ #include "system/winapi.h" #endif +using namespace std::literals; + namespace { std::vector TestWasm = { @@ -91,86 +93,90 @@ std::vector TestWasm = { 0xd, 0x2, 0x0, 0x4, 0x67, 0x2d, 0x6d, 0x69, 0x1, 0x4, 0x67, 0x2d, 0x63, 0x66}; std::vector 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 FibonacciWasm = { 0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x6, 0x1, @@ -459,7 +465,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(WASMEDGE_VERSION_MAJOR), WasmEdge_VersionGetMajor()); EXPECT_EQ(static_cast(WASMEDGE_VERSION_MINOR), @@ -811,7 +818,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 +832,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 +950,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 +999,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 +1039,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 +1053,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 +1188,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 +1408,7 @@ TEST(APICoreTest, Loader) { WasmEdge_ErrCode_WrongVMWorkflow, WasmEdge_LoaderParseFromBuffer(nullptr, nullptr, Buf.data(), static_cast(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 +1771,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 +1859,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 +1882,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 +1913,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 +1932,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 +1946,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); @@ -3289,17 +3374,15 @@ TEST(APICoreTest, VM) { EXPECT_EQ(WasmEdge_VMListRegisteredModule(VM, nullptr, 20), 16U); 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(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(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 +3582,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 +3680,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 +3696,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 +3708,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 +3721,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 +3735,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/CMakeLists.txt b/test/api/CMakeLists.txt index 6e92b3c1641a..e694eb0e3753 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 -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..81377e80ad20 100644 --- a/test/api/helper.cpp +++ b/test/api/helper.cpp @@ -23,9 +23,9 @@ 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}; WasmEdge_ConfigureContext *createConf(const Configure &Conf) { auto *Cxt = WasmEdge_ConfigureCreate(); diff --git a/test/api/hostfunc_c.c b/test/api/hostfunc_c.c index 769345bf53ef..d9055b91adcf 100644 --- a/test/api/hostfunc_c.c +++ b/test/api/hostfunc_c.c @@ -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/executor/ExecutorTest.cpp b/test/executor/ExecutorTest.cpp index 4597e6977af1..cbf20048cd99 100644 --- a/test/executor/ExecutorTest.cpp +++ b/test/executor/ExecutorTest.cpp @@ -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/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/host/socket/wasi_socket.cpp b/test/host/socket/wasi_socket.cpp index 8e10f8fd11b8..0a29d5e5f76b 100644 --- a/test/host/socket/wasi_socket.cpp +++ b/test/host/socket/wasi_socket.cpp @@ -9,12 +9,12 @@ #include "system/winapi.h" #include #include +#include #include #include #include #include #include -#include #if !WASMEDGE_OS_WINDOWS #include diff --git a/test/host/wasi/wasi.cpp b/test/host/wasi/wasi.cpp index e57d5c547b2f..8b6414d27de0 100644 --- a/test/host/wasi/wasi.cpp +++ b/test/host/wasi/wasi.cpp @@ -223,7 +223,7 @@ 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}; auto Duration = duration_cast(FiletimeDuration{Temp.QuadPart} - diff --git a/test/llvm/CMakeLists.txt b/test/llvm/CMakeLists.txt new file mode 100644 index 000000000000..d1033cd9af4e --- /dev/null +++ b/test/llvm/CMakeLists.txt @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2022 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..0a1948a10d4b 100644 --- a/test/aot/AOTcoreTest.cpp +++ b/test/llvm/LLVMcoreTest.cpp @@ -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 {}; class CustomWasmCoreTest : public testing::TestWithParam {}; +class JITCoreTest : public testing::TestWithParam {}; 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 Data; std::unique_ptr 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{SOPath}; }); }; T.onModule = [&VM, &Compile](const std::string &ModName, const std::string &Filename) -> Expect { @@ -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 Data; std::unique_ptr 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{SOPath}; }); }; T.onModule = [&VM, &Compile](const std::string &ModName, const std::string &Filename) -> Expect { @@ -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 { + 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 { + return VM.loadWasm(Filename); + }; + T.onValidate = [&VM](const std::string &Filename) -> Expect { + return VM.loadWasm(Filename).and_then([&VM]() { return VM.validate(); }); + }; + T.onInstantiate = [&VM](const std::string &Filename) -> Expect { + 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 &Params, + const std::vector &ParamTypes) + -> Expect>> { + 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> { + // 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 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/descriptionTest.cpp b/test/loader/descriptionTest.cpp index 981ed19a2dc0..7f6b855f11ee 100644 --- a/test/loader/descriptionTest.cpp +++ b/test/loader/descriptionTest.cpp @@ -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/filemgrTest.cpp b/test/loader/filemgrTest.cpp index 35923a917550..31555427208f 100644 --- a/test/loader/filemgrTest.cpp +++ b/test/loader/filemgrTest.cpp @@ -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 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 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 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 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 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({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({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 ReadByte; ASSERT_TRUE(Mgr.setCode(std::vector{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> ReadBytes; ASSERT_TRUE(Mgr.setCode(std::vector{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 ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector{ 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 ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector{ 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 ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector{ 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 ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector{ 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 ReadStr; ASSERT_TRUE(Mgr.setCode(std::vector{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 ReadNum; ASSERT_TRUE( Mgr.setCode(std::vector{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 ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector{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 ReadNum; ASSERT_TRUE( Mgr.setCode(std::vector{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 ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector{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 ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector{ 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 ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector{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 ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector{ 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 ReadNum; ASSERT_TRUE(Mgr.setCode(std::vector{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 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 PeekByte; + ASSERT_TRUE(Mgr.setCode(std::vector{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 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 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 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({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({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/serializeInstructionTest.cpp b/test/loader/serializeInstructionTest.cpp index ab19f4c46d35..2c9133abbd32 100644 --- a/test/loader/serializeInstructionTest.cpp +++ b/test/loader/serializeInstructionTest.cpp @@ -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/mixcall/CMakeLists.txt b/test/mixcall/CMakeLists.txt index 9b2c37314498..25ecc95ebcb4 100644 --- a/test/mixcall/CMakeLists.txt +++ b/test/mixcall/CMakeLists.txt @@ -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..a79adf1fa5c1 100644 --- a/test/mixcall/mixcallTest.cpp +++ b/test/mixcall/mixcallTest.cpp @@ -1,7 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2019-2022 Second State INC -#include "aot/compiler.h" #include "common/configure.h" #include "common/errinfo.h" #include "common/filesystem.h" @@ -9,6 +8,8 @@ #include "runtime/instance/module.h" #include "validator/validator.h" #include "vm/vm.h" +#include "llvm/codegen.h" +#include "llvm/compiler.h" #include #include @@ -111,20 +112,24 @@ 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 Data; + std::unique_ptr 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..eeb1950b3212 100644 --- a/test/plugins/CMakeLists.txt +++ b/test/plugins/CMakeLists.txt @@ -1,14 +1,18 @@ # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: 2019-2022 Second State INC +if(WASMEDGE_PLUGIN_FFMPEG) + add_subdirectory(wasmedge_ffmpeg) +endif() + if(WASMEDGE_PLUGIN_PROCESS) - if (CMAKE_SYSTEM_NAME MATCHES "Linux") + if(CMAKE_SYSTEM_NAME MATCHES "Linux") add_subdirectory(wasmedge_process) endif() endif() if(WASMEDGE_PLUGIN_ZLIB) - add_subdirectory(wasmedge_zlib) + add_subdirectory(wasmedge_zlib) endif() if(WASMEDGE_PLUGIN_WASI_NN_BACKEND) @@ -57,6 +61,4 @@ if(WASMEDGE_PLUGIN_RUSTLS) add_subdirectory(wasmedge_rustls) endif() -if(CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Darwin") - add_subdirectory(unittest) -endif() +add_subdirectory(unittest) diff --git a/test/plugins/unittest/CMakeLists.txt b/test/plugins/unittest/CMakeLists.txt index 4631c0b44e35..d1614c068caf 100644 --- a/test/plugins/unittest/CMakeLists.txt +++ b/test/plugins/unittest/CMakeLists.txt @@ -2,15 +2,22 @@ # SPDX-FileCopyrightText: 2019-2022 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..70eb27bd13ac 100644 --- a/test/plugins/unittest/testplugin.c +++ b/test/plugins/unittest/testplugin.c @@ -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..581dfb5f26da 100644 --- a/test/plugins/unittest/testplugin.cpp +++ b/test/plugins/unittest/testplugin.cpp @@ -19,12 +19,16 @@ PO::Option WasmEdgePluginTestEnv::CmdName(PO::Description("Test for input name."sv), PO::DefaultValue(std::string(""))); +PO::Option + 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,26 @@ 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, + /* 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..b6bdbd34e3b1 100644 --- a/test/plugins/unittest/testplugin.h +++ b/test/plugins/unittest/testplugin.h @@ -20,7 +20,7 @@ class WasmEdgePluginTestEnv { static PO::List CmdArgs; static PO::Option CmdName; - static Plugin::PluginRegister Register; + static PO::Option CmdOpt; }; template @@ -63,6 +63,16 @@ class WasmEdgePluginTestFuncArgLen } }; +class WasmEdgePluginTestFuncOpt + : public WasmEdgePluginTestFunc { +public: + WasmEdgePluginTestFuncOpt(WasmEdgePluginTestEnv &HostEnv) + : WasmEdgePluginTestFunc(HostEnv) {} + Expect body(const Runtime::CallingFrame &) { + return static_cast(Env.CmdOpt.value()); + } +}; + class WasmEdgePluginTestFuncNameSize : public WasmEdgePluginTestFunc { public: @@ -80,6 +90,7 @@ class WasmEdgePluginTestModule : public Runtime::Instance::ModuleInstance { addHostFunc("add", std::make_unique(Env)); addHostFunc("sub", std::make_unique(Env)); addHostFunc("arg_len", std::make_unique(Env)); + addHostFunc("opt", std::make_unique(Env)); addHostFunc("name_size", std::make_unique(Env)); } diff --git a/test/plugins/unittest/unittest_c.cpp b/test/plugins/unittest/unittest_c.cpp index 19f229932345..5397c9ca35c4 100644 --- a/test/plugins/unittest/unittest_c.cpp +++ b/test/plugins/unittest/unittest_c.cpp @@ -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..81af0d5ebfd0 100644 --- a/test/plugins/unittest/unittest_cpp.cpp +++ b/test/plugins/unittest/unittest_cpp.cpp @@ -18,7 +18,8 @@ namespace { 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 = @@ -32,7 +33,8 @@ WasmEdge::Runtime::Instance::ModuleInstance *createModuleC() { 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,6 +42,7 @@ WasmEdge::Runtime::Instance::ModuleInstance *createModuleCPP() { Parser.set_raw_value("name"sv, std::string("test_name")); Parser.set_raw_value>( "arg"sv, std::vector({"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(); @@ -83,6 +86,18 @@ TEST(wasmedgePluginTests, CPP_Run) { EXPECT_TRUE(HostFuncInst2.run(CallFrame, {}, RetVal)); EXPECT_EQ(RetVal[0].get(), 9); + // Get the function "opt". + auto *FuncInst3 = TestModCPP->findFuncExports("opt"); + EXPECT_NE(FuncInst3, nullptr); + EXPECT_TRUE(FuncInst3->isHostFunction()); + auto &HostFuncInst3 = + dynamic_cast( + FuncInst3->getHostFunc()); + + // Test: Run function successfully. + EXPECT_TRUE(HostFuncInst3.run(CallFrame, {}, RetVal)); + EXPECT_EQ(RetVal[0].get(), 1); + delete TestModCPP; // Create the wasmedge_plugintest_c_module module instance. @@ -98,10 +113,11 @@ TEST(wasmedgePluginTests, CPP_Module) { auto *TestModCPP = dynamic_cast( createModuleCPP()); ASSERT_FALSE(TestModCPP == nullptr); - EXPECT_EQ(TestModCPP->getFuncExportNum(), 4U); + 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; diff --git a/test/plugins/wasi_crypto/helper.h b/test/plugins/wasi_crypto/helper.h index beb1a33988f4..9feefc443fc2 100644 --- a/test/plugins/wasi_crypto/helper.h +++ b/test/plugins/wasi_crypto/helper.h @@ -63,8 +63,8 @@ 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)) { diff --git a/test/plugins/wasi_logging/wasi_logging.cpp b/test/plugins/wasi_logging/wasi_logging.cpp index d1c36c021541..471b72975d01 100644 --- a/test/plugins/wasi_logging/wasi_logging.cpp +++ b/test/plugins/wasi_logging/wasi_logging.cpp @@ -1,12 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2019-2024 Second State INC + +#include "func.h" +#include "module.h" + #include "common/defines.h" #include "runtime/instance/module.h" -#include "wasi_logging/func.h" -#include "wasi_logging/module.h" #include -#include #include #include + +#include #include namespace { @@ -14,8 +19,8 @@ namespace { WasmEdge::Runtime::Instance::ModuleInstance *createModule() { using namespace std::literals::string_view_literals; WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( - "../../../plugins/wasi_logging/" - "libwasmedgePluginWasiLogging" WASMEDGE_LIB_EXTENSION)); + "../../../plugins/wasi_logging/" WASMEDGE_LIB_PREFIX + "wasmedgePluginWasiLogging" WASMEDGE_LIB_EXTENSION)); 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(); @@ -56,7 +61,7 @@ TEST(WasiLoggingTests, func_log) { // Clear the memory[0, 32]. fillMemContent(MemInst, 0, 32); // Set strings in memory - fillMemContent(MemInst, 0, std::string("CxtStr")); + fillMemContent(MemInst, 0, std::string("stdout")); fillMemContent(MemInst, 8, std::string("stderr")); fillMemContent(MemInst, 16, std::string("MsgStr")); @@ -65,7 +70,7 @@ TEST(WasiLoggingTests, func_log) { EXPECT_NE(FuncInst, nullptr); EXPECT_TRUE(FuncInst->isHostFunction()); auto &HostFuncInst = - dynamic_cast(FuncInst->getHostFunc()); + dynamic_cast(FuncInst->getHostFunc()); // Show All Level EXPECT_TRUE(HostFuncInst.run( @@ -99,7 +104,6 @@ TEST(WasiLoggingTests, func_log) { std::initializer_list{ UINT32_C(5), UINT32_C(0), UINT32_C(6), UINT32_C(16), UINT32_C(6)}, {})); - EXPECT_FALSE(WasiLoggingMod->getEnv().isCxtStrStderr); // Stderr Context EXPECT_TRUE(HostFuncInst.run( @@ -107,7 +111,6 @@ TEST(WasiLoggingTests, func_log) { std::initializer_list{ UINT32_C(0), UINT32_C(8), UINT32_C(6), UINT32_C(16), UINT32_C(6)}, {})); - EXPECT_TRUE(WasiLoggingMod->getEnv().isCxtStrStderr); // UnKnown Level EXPECT_FALSE(HostFuncInst.run( @@ -115,7 +118,6 @@ TEST(WasiLoggingTests, func_log) { std::initializer_list{ UINT32_C(6), UINT32_C(0), UINT32_C(6), UINT32_C(16), UINT32_C(6)}, {})); - EXPECT_FALSE(WasiLoggingMod->getEnv().isCxtStrStderr); delete WasiLoggingMod; } diff --git a/test/plugins/wasi_nn/CMakeLists.txt b/test/plugins/wasi_nn/CMakeLists.txt index fe68a8faeed9..8674aaf1e152 100644 --- a/test/plugins/wasi_nn/CMakeLists.txt +++ b/test/plugins/wasi_nn/CMakeLists.txt @@ -5,64 +5,70 @@ 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(MSVC) + target_compile_options(wasiNNTests PUBLIC + /wd4067 # unexpected tokens following preprocessor directive - expected a newline + ) endif() else() # Add the other backend test files fetching here. @@ -107,4 +113,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..e8ccdeaf1496 100644 --- a/test/plugins/wasi_nn/wasi_nn.cpp +++ b/test/plugins/wasi_nn/wasi_nn.cpp @@ -24,9 +24,9 @@ namespace { WasmEdge::Runtime::Instance::ModuleInstance * 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); @@ -41,15 +41,14 @@ createModule(std::string_view NNRPCURI = "") { } inline std::vector 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 Buf(static_cast(Fin.tellg())); + std::vector Buf(static_cast(Fin.tellg())); Fin.seekg(0, std::ios::beg); if (!Fin.read(reinterpret_cast(Buf.data()), - static_cast(Buf.size()))) { + static_cast(Buf.size()))) { return {}; } Fin.close(); @@ -58,7 +57,7 @@ inline std::vector readEntireFile(const std::string &Path) { template void writeBinaries(WasmEdge::Runtime::Instance::MemoryInstance &MemInst, - std::vector Binaries, uint32_t Ptr) noexcept { + WasmEdge::Span Binaries, uint32_t Ptr) noexcept { std::copy(Binaries.begin(), Binaries.end(), MemInst.getPointer(Ptr)); } @@ -75,6 +74,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 std::vector classSort(WasmEdge::Span Array) { std::vector Indices(Array.size()); @@ -86,6 +88,7 @@ std::vector classSort(WasmEdge::Span Array) { }); return Indices; } +#endif } // namespace #endif @@ -194,9 +197,10 @@ 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(XmlRead.size()), BuilderPtr); + writeFatPointer(MemInst, StorePtr + static_cast(XmlRead.size()), + static_cast(WeightRead.size()), BuilderPtr); { EXPECT_TRUE(HostFuncLoad.run( CallFrame, @@ -209,8 +213,10 @@ 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(XmlRead.size()), + BuilderPtr); + writeFatPointer(MemInst, OutBoundPtr, + static_cast(WeightRead.size()), BuilderPtr); { EXPECT_TRUE(HostFuncLoad.run( CallFrame, @@ -223,9 +229,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(XmlRead.size()), BuilderPtr); + writeFatPointer(MemInst, StorePtr + static_cast(XmlRead.size()), + static_cast(WeightRead.size()), BuilderPtr); writeBinaries(MemInst, XmlRead, StorePtr); writeBinaries(MemInst, WeightRead, StorePtr + XmlRead.size()); StorePtr += (XmlRead.size() + WeightRead.size()); @@ -326,10 +333,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(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast(TensorDim.size()) * 4, + static_cast(TensorData.size()), BuilderPtr); writeBinaries(MemInst, TensorDim, StorePtr); writeBinaries(MemInst, TensorData, StorePtr + TensorDim.size() * 4); @@ -375,10 +384,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(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(2), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast(TensorDim.size()) * 4, + static_cast(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, @@ -391,10 +402,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(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast(TensorDim.size()) * 4, + static_cast(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, @@ -598,7 +611,8 @@ TEST(WasiNNTest, PyTorchBackend) { } // Test: load -- Torch model bin ptr out of bounds. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, OutBoundPtr, WeightRead.size(), BuilderPtr); + writeFatPointer(MemInst, OutBoundPtr, + static_cast(WeightRead.size()), BuilderPtr); { EXPECT_TRUE(HostFuncLoad.run(CallFrame, std::initializer_list{ @@ -612,7 +626,8 @@ TEST(WasiNNTest, PyTorchBackend) { // Test: load -- wrong builders' length. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, StorePtr, WeightRead.size(), BuilderPtr); + writeFatPointer(MemInst, StorePtr, static_cast(WeightRead.size()), + BuilderPtr); writeBinaries(MemInst, WeightRead, StorePtr); StorePtr += WeightRead.size(); { @@ -717,10 +732,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(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast(TensorDim.size()) * 4, + static_cast(TensorData.size()), BuilderPtr); writeBinaries(MemInst, TensorDim, StorePtr); writeBinaries(MemInst, TensorData, StorePtr + TensorDim.size() * 4); @@ -739,10 +756,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(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(2), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast(TensorDim.size()) * 4, + static_cast(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, @@ -755,10 +774,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(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast(TensorDim.size()) * 4, + static_cast(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, @@ -966,7 +987,8 @@ TEST(WasiNNTest, TFLiteBackend) { } // Test: load -- model bin ptr out of bounds. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, OutBoundPtr, WeightRead.size(), BuilderPtr); + writeFatPointer(MemInst, OutBoundPtr, + static_cast(WeightRead.size()), BuilderPtr); { EXPECT_TRUE( HostFuncLoad.run(CallFrame, @@ -981,7 +1003,8 @@ TEST(WasiNNTest, TFLiteBackend) { // Test: load -- wrong builders' length. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, StorePtr, WeightRead.size(), BuilderPtr); + writeFatPointer(MemInst, StorePtr, static_cast(WeightRead.size()), + BuilderPtr); writeBinaries(MemInst, WeightRead, StorePtr); StorePtr += WeightRead.size(); { @@ -1089,10 +1112,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(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast(TensorDim.size()) * 4, + static_cast(TensorData.size()), BuilderPtr); writeBinaries(MemInst, TensorDim, StorePtr); writeBinaries(MemInst, TensorData, StorePtr + TensorDim.size() * 4); @@ -1111,11 +1136,13 @@ TEST(WasiNNTest, TFLiteBackend) { // Test: set_input -- set input successfully. BuilderPtr = SetInputEntryPtr; - writeFatPointer(MemInst, StorePtr, TensorDim.size(), BuilderPtr); + writeFatPointer(MemInst, StorePtr, static_cast(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(TensorDim.size()) * 4, + static_cast(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, @@ -1318,7 +1345,8 @@ TEST(WasiNNTest, GGMLBackend) { // Test: load -- GGML model bin ptr out of bounds. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, OutBoundPtr, WeightRead.size(), BuilderPtr); + writeFatPointer(MemInst, OutBoundPtr, + static_cast(WeightRead.size()), BuilderPtr); { EXPECT_TRUE(HostFuncLoad.run(CallFrame, std::initializer_list{ @@ -1332,9 +1360,10 @@ TEST(WasiNNTest, GGMLBackend) { // Test: load -- wrong metadata encoding when builders length > 1. BuilderPtr = LoadEntryPtr; - writeFatPointer(MemInst, StorePtr, WeightRead.size(), BuilderPtr); + writeFatPointer(MemInst, StorePtr, static_cast(WeightRead.size()), + BuilderPtr); writeBinaries(MemInst, WeightRead, StorePtr); - StorePtr += WeightRead.size(); + StorePtr += static_cast(WeightRead.size()); { EXPECT_TRUE(HostFuncLoad.run(CallFrame, std::initializer_list{ @@ -1383,12 +1412,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(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast(TensorDim.size()) * 4, + static_cast(TensorData.size()), BuilderPtr); writeBinaries(MemInst, TensorDim, StorePtr); - writeBinaries(MemInst, TensorData, StorePtr + TensorDim.size() * 4); + writeBinaries(MemInst, TensorData, + StorePtr + + static_cast(TensorDim.size()) * 4); // Test: set_input -- context id exceeds. { @@ -1403,10 +1436,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(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast(TensorDim.size()) * 4, + static_cast(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, @@ -1415,7 +1450,7 @@ TEST(WasiNNTest, GGMLBackend) { Errno)); EXPECT_EQ(Errno[0].get(), static_cast(ErrNo::Success)); } - StorePtr += (TensorDim.size() * 4 + TensorData.size()); + StorePtr += static_cast(TensorDim.size() * 4 + TensorData.size()); // GGML WASI-NN compute tests. // Test: compute -- context id exceeds. @@ -1525,6 +1560,13 @@ TEST(WasiNNTest, GGMLBackendWithRPC) { EXPECT_TRUE(FuncInst->isHostFunction()); auto &HostFuncLoadByName = dynamic_cast(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( + FuncInst->getHostFunc()); // Get the function "init_execution_context". FuncInst = NNMod->findFuncExports("init_execution_context"); EXPECT_NE(FuncInst, nullptr); @@ -1565,6 +1607,26 @@ TEST(WasiNNTest, GGMLBackendWithRPC) { BuilderPtr += 4; } + // Test: load_by_name_with_config -- load successfully. + { + std::string Name = "default"; + std::string Config = "{}"; + std::vector NameVec(Name.begin(), Name.end()); + std::vector ConfigVec(Config.begin(), Config.end()); + uint32_t ConfigPtr = LoadEntryPtr + NameVec.size(); + writeBinaries(MemInst, NameVec, LoadEntryPtr); + writeBinaries(MemInst, ConfigVec, ConfigPtr); + EXPECT_TRUE(HostFuncLoadByNameWithConfig.run( + CallFrame, + std::initializer_list{ + LoadEntryPtr, static_cast(NameVec.size()), ConfigPtr, + static_cast(ConfigVec.size()), BuilderPtr}, + Errno)); + EXPECT_EQ(Errno[0].get(), static_cast(ErrNo::Success)); + EXPECT_EQ(*MemInst.getPointer(BuilderPtr), 0); + BuilderPtr += 4; + } + // GGML WASI-NN init_execution_context tests. // Test: init_execution_context -- graph id invalid. { @@ -1588,10 +1650,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(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast(TensorDim.size()) * 4, + static_cast(TensorData.size()), BuilderPtr); writeBinaries(MemInst, TensorDim, StorePtr); writeBinaries(MemInst, TensorData, StorePtr + TensorDim.size() * 4); @@ -1607,10 +1671,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(TensorDim.size()), BuilderPtr); + writeUInt32(MemInst, UINT32_C(1), BuilderPtr); + writeFatPointer(MemInst, + StorePtr + static_cast(TensorDim.size()) * 4, + static_cast(TensorData.size()), BuilderPtr); { EXPECT_TRUE( HostFuncSetInput.run(CallFrame, diff --git a/test/plugins/wasm_bpf/simple_map_test.cpp b/test/plugins/wasm_bpf/simple_map_test.cpp index 9a86892cc795..51ef2f5a5400 100644 --- a/test/plugins/wasm_bpf/simple_map_test.cpp +++ b/test/plugins/wasm_bpf/simple_map_test.cpp @@ -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..ac3899342c6c 100644 --- a/test/plugins/wasm_bpf/simple_ringbuf_test.cpp +++ b/test/plugins/wasm_bpf/simple_ringbuf_test.cpp @@ -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( - &moduleInst, std::make_unique()); + moduleInst.addHostFunc("__polling_callback_hostfunc"sv, + std::make_unique()); + auto *callbackFuncInst = + moduleInst.findFuncExports("__polling_callback_hostfunc"); // Create a function table, and fill the callback function into it auto funcTableInst = std::make_unique( WasmEdge::AST::TableType(WasmEdge::TypeCode::FuncRef, 1)); ASSERT_TRUE(funcTableInst->setRefs( - std::initializer_list{callbackFuncInst.get()}, - 0, 0, 1)); + std::initializer_list{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..3e5dbd0ee2fc 100644 --- a/test/plugins/wasm_bpf/wasm_bpf.cpp +++ b/test/plugins/wasm_bpf/wasm_bpf.cpp @@ -31,9 +31,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(); @@ -279,16 +279,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( - &moduleInst, std::make_unique()); + moduleInst.addHostFunc("__polling_callback_hostfunc"sv, + std::make_unique()); + auto *callbackFuncInst = + moduleInst.findFuncExports("__polling_callback_hostfunc"); // Create a function table, and fill the callback function into it auto funcTableInst = std::make_unique( WasmEdge::AST::TableType(WasmEdge::TypeCode::FuncRef, 1)); EXPECT_TRUE(funcTableInst->setRefs( - std::initializer_list{callbackFuncInst.get()}, - 0, 0, 1)); + std::initializer_list{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/wasmedge_ffmpeg/CMakeLists.txt b/test/plugins/wasmedge_ffmpeg/CMakeLists.txt new file mode 100644 index 000000000000..c35e0bc421ae --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/CMakeLists.txt @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2019-2022 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 + + swscale/swscale_func.cpp + + swresample/swresample_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 + $ + $ + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(wasmedgeFFmpegTests + PRIVATE + wasmedgePluginWasmEdgeFFmpeg + ${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..6eb3a3d4ebab --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avcodec/avCodec.cpp @@ -0,0 +1,365 @@ +#include "avcodec/avCodec.h" +#include "avcodec/module.h" +#include "utils.h" + +#include + +// 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( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecId"sv); + { + EXPECT_TRUE(HostFuncAVCodecID.run( + CallFrame, std::initializer_list{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get(), 27); // H264 + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_type"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecType = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecType"sv); + { + EXPECT_TRUE(HostFuncAVCodecType.run( + CallFrame, std::initializer_list{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get(), + 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( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecMaxLowres"sv); + { + EXPECT_TRUE(HostFuncAVCodecMaxLowres.run( + CallFrame, std::initializer_list{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecId}, + Result)); + EXPECT_TRUE(Result[0].get() > 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{AVCodecId}, + Result)); + Length = Result[0].get(); + 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( + FuncInst->getHostFunc()); + + // Fill the Memory with 0. + fillMemContent(MemInst, StringPtr, Length); + spdlog::info("Testing AVCodecGetName"sv); + { + EXPECT_TRUE( + HostFuncAVCodecGetName.run(CallFrame, + std::initializer_list{ + AVCodecId, StringPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecId}, + Result)); + Length = Result[0].get(); + 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{AVCodecId, StringPtr, + Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_profiles"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecProfiles = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecProfiles"sv); + { + EXPECT_TRUE(HostFuncAVCodecProfiles.run( + CallFrame, std::initializer_list{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecId, Idx}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecId, 1, NumeratorPtr, + DenominatorPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecId, 0}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecId, 0}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecId, 0}, + Result)); + EXPECT_EQ(Result[0].get(), 0); + } +} +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/test/plugins/wasmedge_ffmpeg/avcodec/avCodecCtx.cpp b/test/plugins/wasmedge_ffmpeg/avcodec/avCodecCtx.cpp new file mode 100644 index 000000000000..b89128f8971f --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avcodec/avCodecCtx.cpp @@ -0,0 +1,1657 @@ +#include "avcodec/avCodecContext.h" +#include "avcodec/module.h" +#include "utils.h" + +#include + +// 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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, CodecType}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, Num, Den}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, NumPtr, + DenPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, Dimension}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_width"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxWidth = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxWidth.run( + CallFrame, std::initializer_list{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, Dimension}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_height"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxHeight = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxHeight.run( + CallFrame, std::initializer_list{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, Num, Den}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, NumPtr, + DenPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, + ChannelLayoutId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, PixFormatId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, SampleFmtId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, SampleRate}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, GopSize}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, MaxBFrames}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, BQuantFactor}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, BQuantOffset}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, IQuantFactor}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, IQuantOffset}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, LumiMasking}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, + TemporialCplxMasking}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, + SpatialCplxMasking}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, PMasking}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, DarkMasking}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, MeCmp}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, MeSubCmp}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, MbCmp}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, IldctCmp}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, DiaSize}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, + LastPredictorCount}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, MePreCmp}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, PreDiaSize}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, + MeSubpelQuality}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, SetMeRange}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, MbDecision}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, MbLMin}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, MbLMax}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, + IntraDcPrecision}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, QMin}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, QMax}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, + GlobalQuality}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, ColorspaceId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, ColorRangeId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, BitRate}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, RcMaxRate}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, + BitRateTolerance}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, + CompressionLevel}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, Num, Den}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, NumPtr, + DenPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, Flags}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, ComplianceId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, Debug}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_codec"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxCodec = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxCodec.run( + CallFrame, + std::initializer_list{AVCodecCtxId, AVCodecPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, Channels}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, DiscardId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, DiscardId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, DiscardId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, + ErrorConcealment}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, + ErrorRecognition}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_delay"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxDelay = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxDelay.run( + CallFrame, std::initializer_list{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, Value}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, Value}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_avcodeccontext_refs"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecCtxRefs = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVCodecCtxRefs.run( + CallFrame, std::initializer_list{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, Value}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, Value}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, Value}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + ASSERT_TRUE(Result[0].get() > 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{AVCodecCtxId}, + Result)); + ASSERT_TRUE(Result[0].get() >= 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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId, SampleFmtId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + ASSERT_TRUE(Result[0].get() >= 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{AVCodecCtxId}, + Result)); + ASSERT_TRUE(Result[0].get() > 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{AVCodecCtxId, + ChannelLayoutId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + ASSERT_TRUE(Result[0].get() >= 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{AVCodecCtxId, ThreadType}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, ThreadCount}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecCtxId}, + Result)); + ASSERT_TRUE(Result[0].get() >= 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..1217914e73e5 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avcodec/avCodecParameters.cpp @@ -0,0 +1,75 @@ +#include "avcodec/avCodecParameters.h" +#include "avcodec/module.h" +#include "utils.h" + +#include + +// 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{AVCodecParamId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecParamId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{AVCodecParamId, 20}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } +} +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/test/plugins/wasmedge_ffmpeg/avcodec/avPacket.cpp b/test/plugins/wasmedge_ffmpeg/avcodec/avPacket.cpp new file mode 100644 index 000000000000..4d7348a36565 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avcodec/avPacket.cpp @@ -0,0 +1,368 @@ +#include "avcodec/avPacket.h" +#include "avcodec/module.h" +#include "utils.h" + +#include + +// 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( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketAlloc.run( + CallFrame, std::initializer_list{PacketPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVPacketAlloc.run( + CallFrame, std::initializer_list{PacketPtr2}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + FuncInst->getHostFunc()); + + { + uint32_t Size = 40; + EXPECT_TRUE(HostFuncAVNewPacket.run( + CallFrame, std::initializer_list{PacketId, Size}, + Result)); + EXPECT_EQ(Result[0].get(), 0); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_grow_packet"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVGrowPacket = + dynamic_cast( + FuncInst->getHostFunc()); + + { + uint32_t Size = 40; + EXPECT_TRUE(HostFuncAVGrowPacket.run( + CallFrame, std::initializer_list{PacketId, Size}, + Result)); + EXPECT_EQ(Result[0].get(), 0); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_shrink_packet"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVShrinkPacket = + dynamic_cast( + FuncInst->getHostFunc()); + + { + uint32_t Size = 40; + EXPECT_TRUE(HostFuncAVShrinkPacket.run( + CallFrame, std::initializer_list{PacketId, Size}, + Result)); + EXPECT_EQ(Result[0].get(), 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{PacketId, StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{PacketId}, + Result)); + EXPECT_EQ(Result[0].get(), 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( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketSize.run( + CallFrame, std::initializer_list{PacketId}, + Result)); + Size = Result[0].get(); + 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( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketSetFlags.run( + CallFrame, std::initializer_list{PacketId, Flags}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_flags"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketFlags = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketFlags.run( + CallFrame, std::initializer_list{PacketId}, + Result)); + EXPECT_EQ(Result[0].get(), 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( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketSetPos.run( + CallFrame, std::initializer_list{PacketId, Pos}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_pos"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketPos = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketPos.run( + CallFrame, std::initializer_list{PacketId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{PacketId, Duration}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_duration"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketDuration = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketDuration.run( + CallFrame, std::initializer_list{PacketId}, + Result)); + EXPECT_EQ(Result[0].get(), 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( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketSetDts.run( + CallFrame, std::initializer_list{PacketId, Dts}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_dts"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketDts = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketDts.run( + CallFrame, std::initializer_list{PacketId}, + Result)); + EXPECT_EQ(Result[0].get(), 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( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketSetPts.run( + CallFrame, std::initializer_list{PacketId, Pts}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_pts"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketPts = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketPts.run( + CallFrame, std::initializer_list{PacketId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{PacketId}, + Result)); + EXPECT_EQ(Result[0].get(), 0); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_data"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVPacketData = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketData.run( + CallFrame, + std::initializer_list{PacketId, DataPtr, Size}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_ref"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVPacketRef = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketRef.run( + CallFrame, + std::initializer_list{PacketId2, PacketId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_av_packet_unref"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVPacketUnref = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVPacketUnref.run( + CallFrame, std::initializer_list{PacketId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } +} +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file 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..d5fcc6b02577 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avcodec/avcodec_func.cpp @@ -0,0 +1,574 @@ +#include "avcodec/avcodec_func.h" +#include "avcodec/module.h" + +#include "utils.h" +#include + +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{0, CodecCtxPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{CodecParamPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVCodecParametersAlloc.run( + CallFrame, std::initializer_list{CodecParamPtr2}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecParamId, + AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_get_type"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecGetType = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecGetType"sv); + { + EXPECT_TRUE(HostFuncAVCodecGetType.run( + CallFrame, std::initializer_list{ID}, Result)); + EXPECT_EQ(Result[0].get(), 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{ID, CodecDecoderPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{ID, CodecEncoderPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + 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{ + AVCodecCtxId, AVCodecEncoderId, 0}, + Result)); + EXPECT_EQ(Result[0].get(), -22); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_av_codec_is_encoder"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecIsEncoder = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecIsEncoder"sv); + { + EXPECT_TRUE(HostFuncAVCodecIsEncoder.run( + CallFrame, + std::initializer_list{AVCodecEncoderId}, Result)); + EXPECT_EQ(Result[0].get(), 1); + } + + FuncInst = AVCodecMod->findFuncExports( + "wasmedge_ffmpeg_avcodec_av_codec_is_decoder"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecIsDecoder = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecIsDecoder"sv); + { + EXPECT_TRUE(HostFuncAVCodecIsDecoder.run( + CallFrame, + std::initializer_list{AVCodecDecoderId}, Result)); + EXPECT_EQ(Result[0].get(), 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{CodecDecoderPtr, + CodecNamePtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{CodecEncoderPtr, + CodecNamePtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId, + AVCodecParamId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{}, Result)); + // EXPECT_EQ(Result[0].get(), + // static_cast(ErrNo::Success)); + // } + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_version"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecVersion = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecVersion"sv); + { + EXPECT_TRUE(HostFuncAVCodecVersion.run( + CallFrame, std::initializer_list{}, Result)); + EXPECT_TRUE(Result[0].get() > 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{}, Result)); + Length = Result[0].get(); + 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{StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{}, Result)); + + Length = Result[0].get(); + EXPECT_TRUE(Length > 0); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_license"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecLicense = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecLicense"sv); + { + EXPECT_TRUE(HostFuncAVCodecLicense.run( + CallFrame, std::initializer_list{StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AVCodecParamId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + 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{CodecCtxId, FrameId}, + Result)); + EXPECT_EQ(Result[0].get(), -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{CodecCtxId, PacketId}, + Result)); + EXPECT_EQ(Result[0].get(), -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{CodecCtxId, PacketId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{CodecCtxId, FrameId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{PacketId, SrcNum, SrcDen, + DestNum, DestDen}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{PacketId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{CodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_close"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVCodecClose = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVCodecClose"sv); + { + EXPECT_TRUE(HostFuncAVCodecClose.run( + CallFrame, std::initializer_list{CodecCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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..589301641e5a --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avfilter/avfilter.cpp @@ -0,0 +1,287 @@ +#include "avfilter/avFilter.h" +#include "avfilter//avfilter_func.h" +#include "avfilter/module.h" +#include "utils.h" + +#include + +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{FilterPtr, InputNamePtr, + Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{FilterId}, + Result)); + Length = Result[0].get(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = + AVFilterMod->findFuncExports("wasmedge_ffmpeg_avfilter_avfilter_name"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterName = + dynamic_cast( + FuncInst->getHostFunc()); + + fillMemContent(MemInst, StrPtr, Length); + { + EXPECT_TRUE(HostFuncAVFilterName.run( + CallFrame, + std::initializer_list{FilterId, StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{FilterId}, + Result)); + + Length = Result[0].get(); + 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{FilterId, StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{FilterId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{FilterId}, + Result)); + EXPECT_EQ(Result[0].get(), 1); + } + + FuncInst = + AVFilterMod->findFuncExports("wasmedge_ffmpeg_avfilter_avfilter_flags"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterFlags = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterFlags.run( + CallFrame, std::initializer_list{FilterId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{FilterId, + InputFilterPadPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{FilterId, + OutputFilterPadPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{OutputFilterPadId, 0}, + Result)); + Length = Result[0].get(); + 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{OutputFilterPadId, Idx, + StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{OutputFilterPadId, Idx}, + Result)); + EXPECT_EQ(Result[0].get(), 1); // Audio + } + + FuncInst = AVFilterMod->findFuncExports( + "wasmedge_ffmpeg_avfilter_avfilter_pad_drop"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterPadDrop = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterPadDrop.run( + CallFrame, + std::initializer_list{OutputFilterPadId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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..7a6675feb69d --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avfilter/avfilter_func.cpp @@ -0,0 +1,682 @@ +#include "avfilter//avfilter_func.h" +#include "avfilter/avFilter.h" +#include "avfilter/buffer_source_sink.h" +#include "avfilter/module.h" +#include "utils.h" + +#include + +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{FilterGraphPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{FilterPtr, InputNamePtr, + Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + Length = OutputName.length(); + EXPECT_TRUE(HostFuncAVFilterGetByName.run( + CallFrame, + std::initializer_list{Filter2Ptr, OutputNamePtr, + Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{ + InputFilterCtxPtr, FilterId, InputFilterNamePtr, NameLen, ArgsPtr, + ArgsLen, FilterGraphId}, + Result)); + ASSERT_TRUE(Result[0].get() >= 0); + writeUInt32(MemInst, 0, InputFilterCtxPtr); // Setting InputFilterCtx to 0 + + NameLen = OutputFilterName.length(); + EXPECT_TRUE(HostFuncAVFilterGraphCreateFilter.run( + CallFrame, + std::initializer_list{ + OutputFilterCtxPtr, Filter2Id, OutputFilterNamePtr, NameLen, 0, 0, + FilterGraphId}, + Result)); + ASSERT_TRUE(Result[0].get() >= 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{InputInOutPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVFilterInOutAlloc.run( + CallFrame, std::initializer_list{OutputInOutPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{ + OutputFilterCtxPtr, FilterGraphId, OutputFilterNamePtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + Length = InputFilterName.length(); + EXPECT_TRUE(HostFuncAVFilterGraphGetFilter.run( + CallFrame, + std::initializer_list{ + InputFilterCtxPtr, FilterGraphId, InputFilterNamePtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{OutputInOutId, + InputFilterNamePtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + Length = OutputFilterName.length(); + EXPECT_TRUE(HostFuncAVFilterInOutSetName.run( + CallFrame, + std::initializer_list{ + InputInOutId, OutputFilterNamePtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{OutputInOutId, + InputFilterCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVFilterInOutSetFilterCtx.run( + CallFrame, + std::initializer_list{InputInOutId, + OutputFilterCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{OutputInOutId, 0}, Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVFilterInOutSetPadIdx.run( + CallFrame, std::initializer_list{InputInOutId, 0}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{OutputInOutId, 0}, Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVFilterInOutSetNext.run( + CallFrame, std::initializer_list{InputInOutId, 0}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{ + FilterGraphId, SpecPtr, Length, InputInOutId, OutputInOutId}, + Result)); + ASSERT_TRUE(Result[0].get() >= 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{FilterGraphId}, + Result)); + ASSERT_TRUE(Result[0].get() >= 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{FilterGraphId}, + Result)); + GraphStrLen = Result[0].get(); + 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{FilterGraphId, StrPtr, + GraphStrLen}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{InputInOutId}, Result)); + // EXPECT_EQ(Result[0].get(), + // static_cast(ErrNo::Success)); + // + // EXPECT_TRUE(HostFuncAVFilterInOutFree.run( + // CallFrame, + // std::initializer_list{OutputInOutId}, + // Result)); + // EXPECT_EQ(Result[0].get(), + // static_cast(ErrNo::Success)); + // } + + FuncInst = + AVFilterMod->findFuncExports("wasmedge_ffmpeg_avfilter_avfilter_version"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterVersion = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterVersion.run( + CallFrame, std::initializer_list{}, Result)); + ASSERT_TRUE(Result[0].get() > 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{}, Result)); + Length = Result[0].get(); + 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{StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{}, Result)); + Length = Result[0].get(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = + AVFilterMod->findFuncExports("wasmedge_ffmpeg_avfilter_avfilter_license"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterLicense = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterLicense.run( + CallFrame, std::initializer_list{StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{InputFilterCtxId}, Result)); + EXPECT_EQ(Result[0].get(), 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{InputFilterCtxId, FrameId}, + Result)); + ASSERT_TRUE(Result[0].get()); + } + + // 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{InputFilterCtxPtr, Pts, + // Flags}, + // Result)); + // EXPECT_EQ(Result[0].get(), + // static_cast(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{OutputFilterCtxId, FrameId}, + Result)); + ASSERT_TRUE(Result[0].get()); + } + + 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{OutputFilterCtxId, FrameId, + 20}, + Result)); + ASSERT_TRUE(Result[0].get()); + } + + 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{OutputFilterCtxId, 30}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{FilterGraphId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVFilterMod->findFuncExports("wasmedge_ffmpeg_avfilter_avfilter_drop"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + + auto &HostFuncAVFilterDrop = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVFilterDrop.run( + CallFrame, std::initializer_list{FilterId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{InputFilterCtxId}, Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVFilterContextDrop.run( + CallFrame, + std::initializer_list{OutputFilterCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{FilterGraphId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + // ================================================================== + // End Clean Memory + // ================================================================== +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/test/plugins/wasmedge_ffmpeg/avformat/avChapter.cpp b/test/plugins/wasmedge_ffmpeg/avformat/avChapter.cpp new file mode 100644 index 000000000000..94dd8c63258c --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avformat/avChapter.cpp @@ -0,0 +1,220 @@ +#include "avformat/avChapter.h" +#include "avformat/module.h" +#include "utils.h" + +#include + +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( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVChapterId.run( + CallFrame, + std::initializer_list{FormatCtxId, ChapterIdx}, + Result)); + EXPECT_TRUE(Result[0].get() >= 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{NumPtr, DenPtr, FormatCtxId, + ChapterIdx}, + Result)); + EXPECT_TRUE(Result[0].get() >= 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( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVChapterStart.run( + CallFrame, + std::initializer_list{FormatCtxId, ChapterIdx}, + Result)); + EXPECT_TRUE(Result[0].get() >= 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avChapter_end"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVChapterEnd = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVChapterEnd.run( + CallFrame, + std::initializer_list{FormatCtxId, ChapterIdx}, + Result)); + EXPECT_TRUE(Result[0].get() >= 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{FormatCtxId, ChapterIdx, + DictionaryPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + FuncInst->getHostFunc()); + + { + int64_t ChapterId = 10000; + EXPECT_TRUE( + HostFuncAVChapterSetId.run(CallFrame, + std::initializer_list{ + FormatCtxId, ChapterIdx, ChapterId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + // Verify Set Data + EXPECT_TRUE(HostFuncAVChapterId.run( + CallFrame, + std::initializer_list{FormatCtxId, ChapterIdx}, + Result)); + EXPECT_EQ(Result[0].get(), 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{Num, Den, FormatCtxId, + ChapterIdx}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + // Verify Set Data + EXPECT_TRUE(HostFuncAVChapterTimebase.run( + CallFrame, + std::initializer_list{NumPtr, DenPtr, FormatCtxId, + ChapterIdx}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{FormatCtxId, ChapterIdx, + StartValue}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + // Verify Set Data + EXPECT_TRUE(HostFuncAVChapterStart.run( + CallFrame, + std::initializer_list{FormatCtxId, ChapterIdx}, + Result)); + EXPECT_EQ(Result[0].get(), StartValue); + } + + FuncInst = AVFormatMod->findFuncExports( + "wasmedge_ffmpeg_avformat_avChapter_set_end"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVChapterSetEnd = + dynamic_cast( + FuncInst->getHostFunc()); + + { + int64_t EndValue = 99999; + EXPECT_TRUE( + HostFuncAVChapterSetEnd.run(CallFrame, + std::initializer_list{ + FormatCtxId, ChapterIdx, EndValue}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + // Verify Set Data + EXPECT_TRUE(HostFuncAVChapterEnd.run( + CallFrame, + std::initializer_list{FormatCtxId, ChapterIdx}, + Result)); + EXPECT_EQ(Result[0].get(), EndValue); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/test/plugins/wasmedge_ffmpeg/avformat/avInputOutputContext.cpp b/test/plugins/wasmedge_ffmpeg/avformat/avInputOutputContext.cpp new file mode 100644 index 000000000000..3a575551e539 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avformat/avInputOutputContext.cpp @@ -0,0 +1,207 @@ +#include "avformat/avInputOutputFormat.h" +#include "avformat/avformatContext.h" +#include "avformat/module.h" +#include "utils.h" + +#include + +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{FormatCtxId, + InputFormatPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{InputFormatId, 0}, Result)); + Length = Result[0].get(); + 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{InputFormatId, StrBuf, + Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{InputFormatId, 0}, Result)); + + Length = Result[0].get(); + 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{InputFormatId, StrBuf, + Length}, + Result)); + + EXPECT_EQ(Result[0].get(), static_cast(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{InputFormatId, 0}, Result)); + + Length = Result[0].get(); + 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{InputFormatId, StrBuf, + Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{InputFormatId, 0}, Result)); + + Length = Result[0].get(); + 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{InputFormatId, StrBuf, + Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{InputFormatId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/test/plugins/wasmedge_ffmpeg/avformat/avStream.cpp b/test/plugins/wasmedge_ffmpeg/avformat/avStream.cpp new file mode 100644 index 000000000000..1fc2dadc46df --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avformat/avStream.cpp @@ -0,0 +1,303 @@ +#include "avformat/avStream.h" +#include "avformat/module.h" +#include "utils.h" + +#include + +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( + FuncInst->getHostFunc()); + + uint32_t AvFormatCtxId = readUInt32(MemInst, FormatCtxPtr); + { + EXPECT_TRUE(HostFuncAVStreamId.run( + CallFrame, + std::initializer_list{AvFormatCtxId, StreamIdx}, + Result)); + EXPECT_TRUE(Result[0].get() >= 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avStream_index"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamIndex = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncAVStreamIndex.run( + CallFrame, + std::initializer_list{FormatCtxId, StreamIdx}, + Result)); + EXPECT_TRUE(Result[0].get() >= 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{FormatCtxId, StreamIdx, + CodecParameterPtr}, + Result)); + EXPECT_TRUE(Result[0].get() >= 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{Num, Den, FormatCtxId, + StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVStreamTimebase.run( + CallFrame, + std::initializer_list{NumPtr, DenPtr, FormatCtxId, + StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{FormatCtxId, StreamIdx}, + Result)); + EXPECT_TRUE(Result[0].get() >= 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{FormatCtxId, StreamIdx}, + Result)); + EXPECT_TRUE(Result[0].get() >= 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{FormatCtxId, StreamIdx}, + Result)); + EXPECT_TRUE(Result[0].get() >= 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{FormatCtxId, StreamIdx}, + Result)); + EXPECT_TRUE(Result[0].get() >= 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{Num, Den, FormatCtxId, + StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVStreamRFrameRate.run( + CallFrame, + std::initializer_list{NumPtr, DenPtr, FormatCtxId, + StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{Num, Den, FormatCtxId, + StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVStreamAvgFrameRate.run( + CallFrame, + std::initializer_list{NumPtr, DenPtr, FormatCtxId, + StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{FormatCtxId, StreamIdx, + DictPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + uint32_t DictId = readUInt32(MemInst, DictPtr); + EXPECT_TRUE(HostFuncAVStreamSetMetadata.run( + CallFrame, + std::initializer_list{FormatCtxId, StreamIdx, + DictId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avStream_discard"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVStreamDiscard = + dynamic_cast( + FuncInst->getHostFunc()); + { + EXPECT_TRUE(HostFuncAVStreamDiscard.run( + CallFrame, + std::initializer_list{FormatCtxId, StreamIdx}, + Result)); + EXPECT_EQ(Result[0].get(), 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..ede24ec5c42d --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avformat/avformatContext.cpp @@ -0,0 +1,184 @@ +#include "avformat/avformatContext.h" +#include "avformat/module.h" +#include "utils.h" + +#include + +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{FormatCtxId, + InputFormatPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{FormatCtxId, + OutputFormatPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{FormatCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{FormatCtxId}, + Result)); + EXPECT_TRUE(Result[0].get() > 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{FormatCtxId}, + Result)); + EXPECT_TRUE(Result[0].get() >= 0 || Result[0].get() < 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{FormatCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{FormatCtxId, NbChapters}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + EXPECT_TRUE(HostFuncAVFormatCtxNbChapters.run( + CallFrame, std::initializer_list{FormatCtxId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{FormatCtxId, DicPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + EXPECT_TRUE(readUInt32(MemInst, DicPtr) > 0); + + uint32_t DictId = readUInt32(MemInst, DicPtr); + EXPECT_TRUE(HostFuncAVFormatCtxSetMetadata.run( + CallFrame, + std::initializer_list{FormatCtxId, DictId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file 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..c2fc4fee7e43 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avformat/avformat_func.cpp @@ -0,0 +1,588 @@ +#include "avformat/avformat_func.h" +#include "avformat/module.h" +#include "utils.h" + +#include + +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{ + FormatCtxPtr, UrlStart, UrlSize, UINT32_C(0), DictId}, + Result)); + EXPECT_TRUE(Result[0].get() >= 0); + EXPECT_TRUE(readUInt32(MemInst, FormatCtxPtr) > 0); + + // No AVDict, No AVInputFormat + EXPECT_TRUE(HostFuncAVFormatOpenInput.run( + CallFrame, + std::initializer_list{ + FormatCtxPtr, UrlStart, UrlSize, UINT32_C(0), UINT32_C(0)}, + Result)); + EXPECT_TRUE(Result[0].get() >= 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{FormatCtxId, UINT32_C(0)}, + Result)); + EXPECT_TRUE(Result[0].get() >= 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_av_dump_format"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatAVDumpFormat = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVDumpFormat"sv); + { + EXPECT_TRUE(HostFuncAVFormatAVDumpFormat.run( + CallFrame, + std::initializer_list{ + FormatCtxId, 0, UINT32_C(100), UINT32_C(30), 0}, + Result)); + EXPECT_EQ(Result[0].get(), 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{ + FormatCtxId, UINT32_C(0), INT32_C(-1), INT32_C(-1), 0, 0}, + Result)); + EXPECT_TRUE(Result[0].get() >= 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_av_read_frame"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVReadFrame = + dynamic_cast( + 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{FormatCtxId, PacketId}, + Result)); + EXPECT_EQ(Result[0].get(), 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{}, Result)); + + EXPECT_EQ(Result[0].get(), static_cast(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{FormatCtxId, StreamIdx, + MinTs, Ts, MaxTs, Flags}, + Result)); + EXPECT_EQ(Result[0].get(), 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_av_read_play"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatAVReadPlay = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVReadPlay"sv); + { + // Try a network Fetch. + EXPECT_TRUE(HostFuncAVFormatAVReadPlay.run( + CallFrame, std::initializer_list{FormatCtxId}, + Result)); + EXPECT_TRUE(Result[0].get() < 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_av_read_pause"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatAVReadPause = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVReadPause"sv); + { + // Try a network Fetch. + EXPECT_TRUE(HostFuncAVFormatAVReadPause.run( + CallFrame, std::initializer_list{FormatCtxId}, + Result)); + EXPECT_TRUE(Result[0].get() < 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{}, Result)); + + EXPECT_EQ(Result[0].get(), static_cast(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{FormatCtxId}, + Result)); + EXPECT_TRUE(Result[0].get() >= 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{FormatCtxId}, + Result)); + EXPECT_TRUE(Result[0].get() >= 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avformat_version"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatVersion = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatVersion"sv); + { + EXPECT_TRUE(HostFuncAVFormatVersion.run( + CallFrame, std::initializer_list{}, Result)); + + EXPECT_TRUE(Result[0].get() >= 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{}, Result)); + Length = Result[0].get(); + 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{StrPtr, Length}, + Result)); + + EXPECT_TRUE(Result[0].get() >= 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{}, Result)); + + Length = Result[0].get(); + EXPECT_TRUE(Length > 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avformat_license"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatLicense = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFormatLicense"sv); + { + EXPECT_TRUE(HostFuncAVFormatLicense.run( + CallFrame, std::initializer_list{StrPtr, Length}, + Result)); + + EXPECT_TRUE(Result[0].get() >= 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, std::string("mp4")); + fillMemContent(MemInst, FileStart, std::string("test.mp4")); + + 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{ + FormatCtxPtr, 0, FormatStart, FormatLen, FileStart, FileLen}, + Result)); + EXPECT_TRUE(Result[0].get() >= 0); + + EXPECT_TRUE(HostFuncAVFormatAllocOutputContext2.run( + CallFrame, + std::initializer_list{ + FormatCtxPtr, readUInt32(MemInst, FormatCtxPtr), FormatStart, + FormatLen, FileStart, FileLen}, + Result)); + EXPECT_TRUE(Result[0].get() >= 0); + + EXPECT_TRUE(HostFuncAVFormatAllocOutputContext2.run( + CallFrame, + std::initializer_list{FormatCtxPtr, 0, 0, 0, + FileStart, FileLen}, + Result)); + EXPECT_TRUE(Result[0].get() >= 0); + } + + FuncInst = AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avio_open"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVIOOpen = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVIOOpen"sv); + { + uint32_t AvFormatCtxId = readUInt32(MemInst, FormatCtxPtr); + EXPECT_TRUE( + HostFuncAVIOOpen.run(CallFrame, + std::initializer_list{ + AvFormatCtxId, FileStart, FileLen, 2}, + Result)); + EXPECT_TRUE(Result[0].get() >= 0); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avio_open2"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVIOOpen2 = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVIOOpen2"sv); + { + uint32_t FormatCtxId = readUInt32(MemInst, FormatCtxPtr); + EXPECT_TRUE(HostFuncAVIOOpen2.run( + CallFrame, + std::initializer_list{FormatCtxId, FileStart, + FileLen, 2, 0, DictId}, + Result)); + EXPECT_TRUE(Result[0].get() >= 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{FormatCtxId, + // EmptyStrPtr, 0, + // FilePtr, 32, + // EmptyStrPtr, 0, + // MediaTypeId}, + // Result)); + // EXPECT_EQ(Result[0].get(), 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{FormatCtxId, DictId}, + Result)); + EXPECT_EQ(Result[0].get(), -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{FormatCtxId}, + // Result)); + // EXPECT_EQ(Result[0].get(), -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{ChapterPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{AvFormatCtxId, + // UINT32_C(0), + // AvChapterId}, + // Result)); + // EXPECT_EQ(Result[0].get(), + // static_cast(ErrNo::Success)); + // } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_avformat_avfreep"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVFormatAVFreep = + dynamic_cast( + FuncInst->getHostFunc()); + + spdlog::info("Testing AVFreeP"sv); + { + uint32_t ChapterId = readUInt32(MemInst, ChapterPtr); + EXPECT_TRUE(HostFuncAVFormatAVFreep.run( + CallFrame, std::initializer_list{ChapterId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVFormatMod->findFuncExports("wasmedge_ffmpeg_avformat_av_write_frame"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVWriteFrame = + dynamic_cast( + 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{FormatCtxId, FrameId}, + Result)); + EXPECT_EQ(Result[0].get(), -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{FormatCtxId, FrameId}, + Result)); + EXPECT_EQ(Result[0].get(), -22); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/test/plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp b/test/plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp new file mode 100644 index 000000000000..cb4ad790ba01 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avDictionary.cpp @@ -0,0 +1,151 @@ +#include "avutil/avDictionary.h" +#include "avutil/module.h" +#include "utils.h" + +#include + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVDictionary) { + + 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( + FuncInst->getHostFunc()); + + // Fill 0 in WasmMemory. + fillMemContent(MemInst, KeyStart, KeyLen + ValueLen); + fillMemContent(MemInst, KeyStart, std::string("KEY")); + fillMemContent(MemInst, ValueStart, std::string("VALUE")); + + // 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{ + DictPtr, KeyStart, KeyLen, ValueStart, ValueLen, Flags}, + Result)); + EXPECT_TRUE(Result[0].get() >= 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( + FuncInst->getHostFunc()); + + { + uint32_t DestDictPtr = UINT32_C(80); + uint32_t SrcDictId = readUInt32(MemInst, DictPtr); + EXPECT_TRUE( + HostFuncAVDictCopy.run(CallFrame, + std::initializer_list{ + DestDictPtr, SrcDictId, Flags}, + Result)); + ASSERT_TRUE(Result[0].get() >= 0); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_dict_get"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVDictGet = + dynamic_cast( + 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{DictId, KeyStart, KeyLen, + PrevDictEntryIdx, Flags, + KeyLenPtr, ValueLenPtr}, + Result)); + EXPECT_TRUE(Result[0].get() == 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{ + NullDictId, KeyStart, KeyLen, PrevDictEntryIdx, Flags, KeyLenPtr, + ValueLenPtr}, + Result)); + EXPECT_EQ(Result[0].get(), + static_cast(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( + 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{ + DictId, KeyStart, KeyLen, ValueBufPtr, ValueLen, KeyBufPtr, + UINT32_C(3), PrevDictEntryIdx, Flags}, + Result)); + EXPECT_EQ(Result[0].get(), 1); + // Verify String. Read String from MemInst + + // Pass a Null Dict and testing. + EXPECT_TRUE(HostFuncAVDictGetKeyValue.run( + CallFrame, + std::initializer_list{ + NullDictId, KeyStart, KeyLen, ValueBufPtr, ValueLen, KeyBufPtr, + UINT32_C(3), PrevDictEntryIdx, Flags}, + Result)); + EXPECT_EQ(Result[0].get(), + static_cast(ErrNo::InternalError)); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_dict_free"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVDictFree = + dynamic_cast( + FuncInst->getHostFunc()); + + { + uint32_t DictId = readUInt32(MemInst, DictPtr); + EXPECT_TRUE(HostFuncAVDictFree.run( + CallFrame, std::initializer_list{DictId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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..454d38a2b336 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avError.cpp @@ -0,0 +1,65 @@ +#include "avutil/error.h" +#include "avutil/module.h" +#include "utils.h" + +#include + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVError) { + + 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, std::string("Test Error")); + + auto *FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_strerror"); + auto &HostFuncAVUtilAVStrError = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVUtilAVStrError.run( + CallFrame, std::initializer_list{}, Result); + + EXPECT_EQ(Result[0].get(), 0); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_AVERROR"); + auto &HostFuncAVUtilAVError = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVUtilAVError.run( + CallFrame, std::initializer_list{ErrNum}, Result); + + EXPECT_EQ(Result[0].get(), + ErrNum * -1); // Returns Negative, convert to Positive + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_AVUNERROR"); + auto &HostFuncAVUtilAVUNError = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVUtilAVUNError.run( + CallFrame, std::initializer_list{ErrNum}, Result); + + EXPECT_EQ(Result[0].get(), + ErrNum * -1); // Returns Negative, convert to Positive + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/test/plugins/wasmedge_ffmpeg/avutil/avFrame.cpp b/test/plugins/wasmedge_ffmpeg/avutil/avFrame.cpp new file mode 100644 index 000000000000..3f4c62699111 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avFrame.cpp @@ -0,0 +1,781 @@ +#include "avutil/avFrame.h" +#include "avutil/module.h" +#include "utils.h" + +#include + +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( + FuncInst->getHostFunc()); + + uint32_t EmptyFramePtr = UINT32_C(64); + + { + HostFuncAVFrameAlloc.run( + CallFrame, std::initializer_list{EmptyFramePtr}, + Result); + + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + EXPECT_TRUE(readUInt32(MemInst, EmptyFramePtr) > 0); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_free"); + auto &HostFuncAVFrameFree = + dynamic_cast( + FuncInst->getHostFunc()); + + { + uint32_t EmptyFrameId = readUInt32(MemInst, EmptyFramePtr); + HostFuncAVFrameFree.run( + CallFrame, std::initializer_list{EmptyFrameId}, + Result); + + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_width"); + auto &HostFuncAVFrameWidth = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameWidth.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + + EXPECT_EQ(Result[0].get(), 1920); // Width + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_height"); + auto &HostFuncAVFrameHeight = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameHeight.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + + EXPECT_EQ(Result[0].get(), 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{AVFrameId}, + Result); + + EXPECT_EQ(Result[0].get(), 1); // Video Format + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_isnull"); + auto &HostFuncAVFrameIsNull = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameIsNull.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + + EXPECT_EQ(Result[0].get(), 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_linesize"); + auto &HostFuncAVFrameLinesize = + dynamic_cast( + FuncInst->getHostFunc()); + + int32_t Stride = 0; + uint32_t Idx = 0; + { + HostFuncAVFrameLinesize.run( + CallFrame, std::initializer_list{AVFrameId, Idx}, + Result); + + Stride = Result[0].get(); + EXPECT_EQ(Stride, 1920); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_get_buffer"); + auto &HostFuncAVFrameGetBuffer = + dynamic_cast( + FuncInst->getHostFunc()); + { + // For video, it is 32. + int32_t Align = 32; + HostFuncAVFrameGetBuffer.run( + CallFrame, + std::initializer_list{AVFrameId, Align}, Result); + + EXPECT_EQ(Result[0].get(), 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{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_pict_type"); + auto &HostFuncAVFramePictType = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVFramePictType.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId}, + Result); + EXPECT_TRUE(Result[0].get() == 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{AVFrameId}, + Result); + EXPECT_TRUE(Result[0].get() == 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{AVFrameId}, + Result); + EXPECT_TRUE(Result[0].get() == 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_colorspace"); + auto &HostFuncAVFrameColorspace = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameColorspace.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 2); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_color_range"); + auto &HostFuncAVFrameColorRange = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameColorRange.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_repeat_pict"); + auto &HostAVFrameRepeatPict = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostAVFrameRepeatPict.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_flags"); + auto &HostAVFrameFlags = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostAVFrameFlags.run(CallFrame, + std::initializer_list{AVFrameId}, + Result); + EXPECT_TRUE(Result[0].get() != 1 << 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_quality"); + auto &HostAVFrameQuality = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostAVFrameQuality.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_metadata"); + auto &HostAVFrameMetadata = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostAVFrameMetadata.run( + CallFrame, + std::initializer_list{AVFrameId, DictPtr}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId, DictId}, Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_key_frame"); + auto &HostAVFrameKeyFrame = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostAVFrameKeyFrame.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 1); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_pts"); + auto &HostAVFramePts = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostAVFramePts.run(CallFrame, + std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 0); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_copy"); + auto &HostAVFrameCopy = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostAVFrameCopy.run( + CallFrame, + std::initializer_list{AVFrame2Id, AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_copy_props"); + auto &HostAVFrameCopyProps = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostAVFrameCopyProps.run( + CallFrame, + std::initializer_list{AVFrame2Id, AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_set_width"); + auto &HostFuncAVFrameSetWidth = + dynamic_cast( + FuncInst->getHostFunc()); + + { + int32_t Width = 100; + HostFuncAVFrameSetWidth.run( + CallFrame, + std::initializer_list{AVFrameId, Width}, Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + HostFuncAVFrameWidth.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), Width); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_set_height"); + auto &HostFuncAVFrameSetHeight = + dynamic_cast( + FuncInst->getHostFunc()); + + int32_t Height = 100; + { + HostFuncAVFrameSetHeight.run( + CallFrame, + std::initializer_list{AVFrameId, Height}, Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + HostFuncAVFrameHeight.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), Height); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_data"); + auto &HostFuncAVFrameData = + dynamic_cast( + FuncInst->getHostFunc()); + + { + int32_t Size = 1; // Just reading One byte data for test. + fillMemContent(MemInst, BufPtr, Size); + HostFuncAVFrameData.run(CallFrame, + std::initializer_list{ + AVFrameId, BufPtr, Size, Idx}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(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{AVFrameId, PixFormatId}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + HostFuncAVFrameVideoFormat.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId, PictureId}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + HostFuncAVFramePictType.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId, ColorSpaceId}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + HostFuncAVFrameColorspace.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId, ColorRangeId}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + HostFuncAVFrameColorRange.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), ColorRangeId); + } + + FuncInst = AVUtilMod->findFuncExports( + "wasmedge_ffmpeg_avutil_av_frame_set_color_trc"); + auto &HostFuncAVFrameSetColorTransferCharacteristic = + dynamic_cast( + FuncInst->getHostFunc()); + + { + int32_t ColorTrcId = 5; // GAMMA28 + HostFuncAVFrameSetColorTransferCharacteristic.run( + CallFrame, + std::initializer_list{AVFrameId, ColorTrcId}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + HostAVFrameColorTransferCharacteristic.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), ColorTrcId); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_set_pts"); + auto &HostFuncAVFrameSetPts = + dynamic_cast( + FuncInst->getHostFunc()); + + { + int64_t Pts = 10; + HostFuncAVFrameSetPts.run( + CallFrame, std::initializer_list{AVFrameId, Pts}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + + HostAVFramePts.run(CallFrame, + std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId, NumPtr, DenPtr}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(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{AVFrameId, + ColorPrimariesId}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(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{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId, SampleFormatId}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(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{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId, NbSamples}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_nb_samples"); + auto &HostFuncAVFrameNbSamples = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameNbSamples.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId, SampleRate}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_sample_rate"); + auto &HostFuncAVFrameSampleRate = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameSampleRate.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId, Channels}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_frame_channels"); + auto &HostFuncAVFrameChannels = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVFrameChannels.run( + CallFrame, std::initializer_list{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), 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{AVFrameId, ChannelLayout}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(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{AVFrameId}, + Result); + EXPECT_EQ(Result[0].get(), ChannelLayout); + } + + // ========================================================================== + // AVFrame Audio Funcs. + // ========================================================================== +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/test/plugins/wasmedge_ffmpeg/avutil/avPixfmt.cpp b/test/plugins/wasmedge_ffmpeg/avutil/avPixfmt.cpp new file mode 100644 index 000000000000..afef37c12e33 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avPixfmt.cpp @@ -0,0 +1,244 @@ +#include "avutil/module.h" +#include "avutil/pixfmt.h" +#include "utils.h" + +#include + +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{PixFmtId}, + Result); + + EXPECT_EQ(Result[0].get(), 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{1}, Result); + + EXPECT_TRUE(Result[0].get() >= 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{PixFmtId}, + Result); + + EXPECT_TRUE(Result[0].get() >= 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{TransferCharacteristicId}, + Result); + Length = Result[0].get(); + 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{TransferCharacteristicId, + NamePtr, Length}, + Result); + + EXPECT_EQ(Result[0].get(), static_cast(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{ColorRangeId}, + Result); + + Length = Result[0].get(); + 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( + FuncInst->getHostFunc()); + + { + HostFuncAVColorRangeName.run(CallFrame, + std::initializer_list{ + ColorRangeId, NamePtr, Length}, + Result); + + EXPECT_EQ(Result[0].get(), static_cast(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{ColorSpaceId}, + Result); + + Length = Result[0].get(); + 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( + FuncInst->getHostFunc()); + + { + HostFuncAVColorSpaceName.run(CallFrame, + std::initializer_list{ + ColorSpaceId, NamePtr, Length}, + Result); + + EXPECT_EQ(Result[0].get(), static_cast(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{ColorPrimariesId}, Result); + + Length = Result[0].get(); + 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{ColorPrimariesId, NamePtr, + Length}, + Result); + + EXPECT_EQ(Result[0].get(), static_cast(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{PixFmtId}, + Result); + + Length = Result[0].get(); + 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( + FuncInst->getHostFunc()); + + { + HostFuncAVPixFormatName.run( + CallFrame, + std::initializer_list{PixFmtId, NamePtr, Length}, + Result); + + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_pix_format_mask"); + auto &HostFuncAVPixFormatMask = + dynamic_cast( + FuncInst->getHostFunc()); + + { + uint32_t PixId = 3; // AV_PIX_FMT_RGB24: + HostFuncAVPixFormatMask.run( + CallFrame, std::initializer_list{PixId}, Result); + + EXPECT_EQ(Result[0].get(), + 2); // Verify Mask. Position of Pix in Enum. + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/test/plugins/wasmedge_ffmpeg/avutil/avRational.cpp b/test/plugins/wasmedge_ffmpeg/avutil/avRational.cpp new file mode 100644 index 000000000000..250c0fec936b --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avRational.cpp @@ -0,0 +1,313 @@ +#include "avutil/avRational.h" +#include "avutil/module.h" +#include "utils.h" + +#include + +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( + 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{ + ANum, ADen, BNum, BDen, NumPtr, DenPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + 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{ + ANum, ADen, BNum, BDen, NumPtr, DenPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + 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{ + ANum, ADen, BNum, BDen, NumPtr, DenPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + 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{ + ANum, ADen, BNum, BDen, NumPtr, DenPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + 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{D, Max, NumPtr, DenPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + 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{ANum, ADen}, + Result)); + EXPECT_EQ(Result[0].get(), 0.5); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_inv_q"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncInvQ = + dynamic_cast( + 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{ANum, ADen, NumPtr, DenPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + FuncInst->getHostFunc()); + + { + int32_t ANum = 1; + int32_t ADen = 5; + + EXPECT_TRUE(HostFuncAVQ2IntFloat.run( + CallFrame, std::initializer_list{ANum, ADen}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(1045220557)); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_nearer_q"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVNearerQ = + dynamic_cast( + 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{ + ANum, ADen, BNum, BDen, CNum, CDen}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(1)); + + ANum = -1; + + // C nearer to A + EXPECT_TRUE( + HostFuncAVNearerQ.run(CallFrame, + std::initializer_list{ + ANum, ADen, BNum, BDen, CNum, CDen}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(-1)); + + ANum = 0; + ADen = 0; + + // Both are at same distance + EXPECT_TRUE( + HostFuncAVNearerQ.run(CallFrame, + std::initializer_list{ + ANum, ADen, BNum, BDen, CNum, CDen}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(0)); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_cmp_q"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVCmpQ = + dynamic_cast( + 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{ANum, ADen, BNum, BDen}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(-1)); + + ANum = 2; + ADen = 1; + BNum = 1; + BDen = 2; + // A > B + EXPECT_TRUE(HostFuncAVCmpQ.run( + CallFrame, + std::initializer_list{ANum, ADen, BNum, BDen}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(1)); + + ANum = 2; + ADen = 1; + BNum = 2; + BDen = 1; + // A == B + EXPECT_TRUE(HostFuncAVCmpQ.run( + CallFrame, + std::initializer_list{ANum, ADen, BNum, BDen}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(0)); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_reduce"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVReduce = + dynamic_cast( + FuncInst->getHostFunc()); + + { + int64_t ANum = 1; + int64_t ADen = 2; + int64_t Max = 3; + EXPECT_TRUE( + HostFuncAVReduce.run(CallFrame, + std::initializer_list{ + NumPtr, DenPtr, ANum, ADen, Max}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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..c4f13e049368 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avSampleFmt.cpp @@ -0,0 +1,201 @@ +#include "avutil/module.h" +#include "avutil/samplefmt.h" +#include "utils.h" + +#include + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { + +TEST_F(FFmpegTest, AVSampleFmt) { + + 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{SampleFmtId}, + Result); + + EXPECT_EQ(Result[0].get(), 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{SampleFmtId}, + Result); + + EXPECT_EQ(Result[0].get(), 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{SampleFmtId}, + Result); + + EXPECT_EQ(Result[0].get(), 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{SampleFmtId}, + Result); + + EXPECT_TRUE(Result[0].get() >= 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_get_sample_fmt"); + auto &HostFuncAVGetSampleFmt = + dynamic_cast( + FuncInst->getHostFunc()); + + uint32_t SampleFmtStart = 100; + uint32_t SampleFmtSize = 2; + fillMemContent(MemInst, SampleFmtSize, SampleFmtSize); + + fillMemContent(MemInst, SampleFmtStart, std::string("u8")); + { + HostFuncAVGetSampleFmt.run(CallFrame, + std::initializer_list{ + SampleFmtStart, SampleFmtSize}, + Result); + + EXPECT_EQ(Result[0].get(), 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{NbChannels, NbSamples, + SampleFmtId, Align}, + Result); + + BufSize = Result[0].get(); + 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{ + BufferPtr, LinesizePtr, NbChannels, NbSamples, SampleFmtId, Align}, + Result); + + EXPECT_TRUE(Result[0].get() >= 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{SampleFmtId}, + Result); + + Length = Result[0].get(); + 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{ + SampleFmtId, NamePtr, Length}, + Result); + + EXPECT_EQ(Result[0].get(), static_cast(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{SampleId}, + Result); + + EXPECT_EQ(Result[0].get(), 1); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_freep"); + auto &HostFuncAVFreep = + dynamic_cast( + FuncInst->getHostFunc()); + + { + uint32_t BufferId = readUInt32(MemInst, BufferPtr); + HostFuncAVFreep.run(CallFrame, + std::initializer_list{BufferId}, + Result); + + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file 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..c6431ece35a7 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/avutil/avutil_func.cpp @@ -0,0 +1,261 @@ +#include "avutil/avutil_func.h" +#include "avutil/avTime.h" +#include "avutil/module.h" +#include "utils.h" + +#include + +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( + FuncInst->getHostFunc()); + + int32_t LogLvlId = 32; + { + HostFuncAVLogSetLevel.run( + CallFrame, std::initializer_list{LogLvlId}, + Result); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_log_get_level"); + auto &HostFuncAVLogGetLevel = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVLogGetLevel.run( + CallFrame, std::initializer_list{}, Result); + EXPECT_EQ(Result[0].get(), LogLvlId); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_log_set_flags"); + auto &HostFuncAVLogSetFlags = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVLogSetFlags.run( + CallFrame, std::initializer_list{1}, Result); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_log_get_flags"); + auto &HostFuncAVLogGetFlags = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVLogGetFlags.run( + CallFrame, std::initializer_list{1}, Result); + + EXPECT_EQ(Result[0].get(), 32); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_rescale_q"); + auto &HostFuncAVRescaleQ = + dynamic_cast( + 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{A, BNum, BDen, CNum, CDen}, + Result); + + EXPECT_TRUE(Result[0].get() > 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_rescale_q_rnd"); + auto &HostFuncAVRescaleQRnd = + dynamic_cast( + FuncInst->getHostFunc()); + + { + int32_t RoundingId = 2; + HostFuncAVRescaleQRnd.run(CallFrame, + std::initializer_list{ + A, BNum, BDen, CNum, CDen, RoundingId}, + Result); + + EXPECT_TRUE(Result[0].get() > 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_avutil_version"); + auto &HostFuncAVUtilVersion = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVUtilVersion.run( + CallFrame, std::initializer_list{}, Result); + + EXPECT_TRUE(Result[0].get() > 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{ChannelId}, + Result); + EXPECT_TRUE(Result[0].get() > 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{ChannelId}, + Result); + EXPECT_TRUE(Result[0].get() > 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{}, Result); + + Length = Result[0].get(); + 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{NamePtr, Length}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(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{}, Result); + + Length = Result[0].get(); + EXPECT_TRUE(Length > 0); + } + + // Fill NamePtr with 0. + fillMemContent(MemInst, NamePtr, Length); + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_avutil_license"); + auto &HostFuncAVUtilLicense = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVUtilLicense.run( + CallFrame, std::initializer_list{NamePtr, Length}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } +} + +TEST_F(FFmpegTest, AVTime) { + + ASSERT_TRUE(AVUtilMod != nullptr); + + auto *FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_gettime"); + auto &HostFuncAVGetTime = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVGetTime.run( + CallFrame, std::initializer_list{}, Result); + + EXPECT_TRUE(Result[0].get() > 0); + } + + FuncInst = + AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_gettime_relative"); + auto &HostFuncAVGetTimeRelative = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVGetTimeRelative.run( + CallFrame, std::initializer_list{}, Result); + + EXPECT_TRUE(Result[0].get() > 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{}, Result); + + EXPECT_EQ(Result[0].get(), 1); + } + + FuncInst = AVUtilMod->findFuncExports("wasmedge_ffmpeg_avutil_av_usleep"); + auto &HostFuncAVUSleep = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncAVUSleep.run( + CallFrame, std::initializer_list{1000}, Result); + + EXPECT_EQ(Result[0].get(), 0); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file diff --git a/test/plugins/wasmedge_ffmpeg/main.cpp b/test/plugins/wasmedge_ffmpeg/main.cpp new file mode 100644 index 000000000000..852694a07a86 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/main.cpp @@ -0,0 +1,6 @@ +#include + +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..c5879355923b --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/swresample/swresample_func.cpp @@ -0,0 +1,255 @@ +#include "swresample/swresample_func.h" +#include "swresample/module.h" + +#include "utils.h" +#include + +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() > 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{ + SWResamplePtr, SWRCtxId, OutChLayoutId, OutSampleFmtId, + OutSampleRate, InChLayoutId, InSampleFmtId, SampleRate, LogOffset}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{ + SWResamplePtr, SWRCtxId, OutChLayoutId, OutSampleFmtId, + OutSampleRate, InChLayoutId, InSampleFmtId, SampleRate, LogOffset}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncSwrFree.run( + CallFrame, std::initializer_list{SwrId}, Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + SWResampleMod->findFuncExports("wasmedge_ffmpeg_swresample_swr_init"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwrInit = + dynamic_cast( + FuncInst->getHostFunc()); + + { + SwrId = readUInt32(MemInst, SWResamplePtr); + EXPECT_TRUE(HostFuncSwrInit.run( + CallFrame, std::initializer_list{SwrId}, Result)); + ASSERT_TRUE(Result[0].get() >= 0); + } + + FuncInst = SWResampleMod->findFuncExports( + "wasmedge_ffmpeg_swresample_av_opt_set_dict"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncAVOptSetDict = + dynamic_cast( + FuncInst->getHostFunc()); + + { + uint32_t EmptyDictId = 0; + SwrId = readUInt32(MemInst, SWResamplePtr); + EXPECT_TRUE(HostFuncAVOptSetDict.run( + CallFrame, + std::initializer_list{SwrId, EmptyDictId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + { + SwrId = readUInt32(MemInst, SWResamplePtr); + EXPECT_TRUE(HostFuncAVOptSetDict.run( + CallFrame, std::initializer_list{SwrId, DictId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{SwrId, Frame2Id, FrameId}, + Result)); + ASSERT_TRUE(Result[0].get()); + } + + FuncInst = SWResampleMod->findFuncExports( + "wasmedge_ffmpeg_swresample_swr_get_delay"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwrGetDelay = + dynamic_cast( + FuncInst->getHostFunc()); + + { + SwrId = readUInt32(MemInst, SWResamplePtr); + EXPECT_TRUE(HostFuncSwrGetDelay.run( + CallFrame, std::initializer_list{SwrId, 1}, + Result)); + EXPECT_EQ(Result[0].get(), 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{}, Result)); + Length = Result[0].get(); + 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{StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{}, Result)); + + Length = Result[0].get(); + 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{StrPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } +} + +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge \ No newline at end of file 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..cfe4b38c06a1 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/swscale/swscale_func.cpp @@ -0,0 +1,540 @@ +#include "swscale/swscale_func.h" +#include "swscale/module.h" + +#include "utils.h" +#include + +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( + 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{ + SWScalePtr, SrcWidth, SrcHeight, YUV420PId, DestWidth, DestHeight, + RGB24Id, Flags, SrcFilterId, DestFilterId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE( + HostFuncSwsScale.run(CallFrame, + std::initializer_list{ + SWSScaleId, FrameId, 20, 40, Frame2Id}, + Result)); + EXPECT_EQ(Result[0].get(), -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{ + SWCachedScalePtr, SWSScaleId, SrcWidth, SrcHeight, YUV420PId, + DestWidth, DestHeight, RGB24Id, Flags, SrcFilterId, DestFilterId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{RGB24Id}, + Result)); + ASSERT_TRUE(Result[0].get() > 0); + + // AV_PIX_FMT_XVMC is not supported Pixel Format + EXPECT_TRUE(HostFuncSwsIsSupportedInput.run( + CallFrame, std::initializer_list{XVMCId}, + Result)); + ASSERT_TRUE(Result[0].get() == 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{RGB24Id}, + Result)); + ASSERT_TRUE(Result[0].get() > 0); + + // AV_PIX_FMT_XVMC is not supported Pixel Format + EXPECT_TRUE(HostFuncSwsIsSupportedOutput.run( + CallFrame, std::initializer_list{XVMCId}, + Result)); + ASSERT_TRUE(Result[0].get() == 0); + } + + FuncInst = SWScaleMod->findFuncExports( + "wasmedge_ffmpeg_swscale_sws_isSupportedEndiannessConversion"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsIsSupportedEndiannessConversion = + dynamic_cast( + FuncInst->getHostFunc()); + + { + // AV_PIX_FMT_XVMC is not supported Pixel Format for + EXPECT_TRUE(HostFuncSwsIsSupportedEndiannessConversion.run( + CallFrame, std::initializer_list{XVMCId}, + Result)); + ASSERT_TRUE(Result[0].get() == 0); + } + + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_freeContext"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsFreeContext = + dynamic_cast( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncSwsFreeContext.run( + CallFrame, std::initializer_list{SWSScaleId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + { + uint32_t InvalidDestWidth = -200; + uint32_t InvalidDestHeight = -200; + uint32_t SWScalePtrInvalid = UINT32_C(80); + EXPECT_TRUE(HostFuncSwsGetContext.run( + CallFrame, + std::initializer_list{ + SWScalePtrInvalid, SrcWidth, SrcHeight, YUV420PId, InvalidDestWidth, + InvalidDestHeight, RGB24Id, Flags, SrcFilterId, DestFilterId}, + Result)); + EXPECT_EQ(Result[0].get(), + static_cast(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{ + SwsFilterPtr, LumaGBlur, ChromaGBlur, LumaSharpen, ChromaSharpen, + ChromaHShift, ChromaVShift, Verbose}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + FuncInst->getHostFunc()); + + uint32_t SwsVectorPtr = UINT32_C(20); + { + EXPECT_TRUE(HostFuncSwsGetLumaH.run( + CallFrame, + std::initializer_list{FilterId, SwsVectorPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + FuncInst->getHostFunc()); + + { + writeUInt32(MemInst, UINT32_C(0), SwsVectorPtr); + EXPECT_TRUE(HostFuncSwsGetLumaV.run( + CallFrame, + std::initializer_list{FilterId, SwsVectorPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncSwsGetChromaH.run( + CallFrame, + std::initializer_list{FilterId, SwsVectorPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncSwsGetChromaV.run( + CallFrame, + std::initializer_list{FilterId, SwsVectorPtr}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + FuncInst->getHostFunc()); + + { + EXPECT_TRUE(HostFuncSwsFreeFilter.run( + CallFrame, std::initializer_list{FilterId}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + FuncInst->getHostFunc()); + + { + writeUInt32(MemInst, UINT32_C(0), SwsVectorPtr); + int32_t Length = 20; + EXPECT_TRUE(HostFuncSwsAllocVec.run( + CallFrame, + std::initializer_list{SwsVectorPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{SwsVectorPtr, Variance, + Quality}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(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( + FuncInst->getHostFunc()); + + { + uint32_t SwsVecId = readUInt32(MemInst, SwsVectorPtr); + double Scalar = 20.35; + EXPECT_TRUE(HostFuncSwsScaleVec.run( + CallFrame, + std::initializer_list{SwsVecId, Scalar}, Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_normalizeVec"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsNormalizeVec = + dynamic_cast( + FuncInst->getHostFunc()); + + { + uint32_t SwsVecId = readUInt32(MemInst, SwsVectorPtr); + double Height = 4.3; + EXPECT_TRUE(HostFuncSwsNormalizeVec.run( + CallFrame, + std::initializer_list{SwsVecId, Height}, Result)); + EXPECT_EQ(Result[0].get(), static_cast(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{SwsVecId}, + Result)); + Length = Result[0].get(); + ASSERT_TRUE(Length > 0); + } + + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_getCoeff"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsGetCoeff = + dynamic_cast( + FuncInst->getHostFunc()); + + fillMemContent(MemInst, CoeffPtr, Length); + { + uint32_t SwsVecId = readUInt32(MemInst, SwsVectorPtr); + EXPECT_TRUE(HostFuncSwsGetCoeff.run( + CallFrame, + std::initializer_list{SwsVecId, CoeffPtr, Length}, + Result)); + EXPECT_EQ(Result[0].get(), static_cast(ErrNo::Success)); + } + + FuncInst = SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_sws_freeVec"); + EXPECT_NE(FuncInst, nullptr); + EXPECT_TRUE(FuncInst->isHostFunction()); + auto &HostFuncSwsFreeVec = + dynamic_cast( + FuncInst->getHostFunc()); + + { + uint32_t SwsVecId = readUInt32(MemInst, SwsVectorPtr); + EXPECT_TRUE(HostFuncSwsFreeVec.run( + CallFrame, std::initializer_list{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( + FuncInst->getHostFunc()); + + { + HostFuncSwscaleVersion.run( + CallFrame, std::initializer_list{}, Result); + + EXPECT_TRUE(Result[0].get() > 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{}, Result); + + Length = Result[0].get(); + 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{NamePtr, Length}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(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{}, Result); + + Length = Result[0].get(); + EXPECT_TRUE(Length > 0); + } + + // Fill NamePtr with 0. + fillMemContent(MemInst, NamePtr, Length); + FuncInst = + SWScaleMod->findFuncExports("wasmedge_ffmpeg_swscale_swscale_license"); + auto &HostFuncSwscaleLicense = + dynamic_cast( + FuncInst->getHostFunc()); + + { + HostFuncSwscaleLicense.run( + CallFrame, std::initializer_list{NamePtr, Length}, + Result); + EXPECT_EQ(Result[0].get(), static_cast(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..cef6ba40adf6 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/utils.cpp @@ -0,0 +1,259 @@ +#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( + FuncInst->getHostFunc()); + HostFuncAVFrameAlloc.run( + CallFrame, std::initializer_list{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{ + AvFormatCtxId, MediaTypeId, WantedStream, + RelatedStream, DecoderRetId, Flags}, + Result); + + uint32_t StreamIdx = Result[0].get(); + + 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{ + 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{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{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{AVCodecCtxId}, + Result); + + uint32_t CodecId = Result[0].get(); + + 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{CodecId, AVCodecPtr}, Result); + + uint32_t AVCodecId = readUInt32(MemInst, AVCodecPtr); + + FuncInst = + AVCodecMod->findFuncExports("wasmedge_ffmpeg_avcodec_avcodec_open2"); + auto &HostFuncAVCodecOpen2 = + dynamic_cast( + FuncInst->getHostFunc()); + + HostFuncAVCodecOpen2.run( + CallFrame, + std::initializer_list{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( + 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{AVCodecCtxId, FrameId}, + Result); + + // Error returned by FFmpeg are negative. + int32_t Error = Result[0].get() * -1; + + if (Error == EAGAIN) { + while (true) { + + allocPacket(PacketPtr); + + uint32_t PackedId = readUInt32(MemInst, PacketPtr); + + while (true) { + HostFuncAVReadFrame.run(CallFrame, + std::initializer_list{ + AvFormatCtxId, PackedId}, + Result); + + int32_t Res = Result[0].get(); + if (Res == 0 || Res == AVERROR_EOF) { + break; + } + } + + HostFuncAVPacketStreamIndex.run( + CallFrame, + std::initializer_list{AVCodecCtxId, FrameId}, + Result); + + uint32_t PacketStreamIdx = Result[0].get(); + + if (PacketStreamIdx != StreamIdx) { + continue; + } + + HostFuncAVCodecSendPacket.run( + CallFrame, + std::initializer_list{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{ + 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( + FuncInst->getHostFunc()); + + HostFuncAVDictSet.run(CallFrame, + std::initializer_list{ + 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( + FuncInst->getHostFunc()); + + HostFuncAVPacketAlloc.run( + CallFrame, std::initializer_list{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..6c95138e4274 --- /dev/null +++ b/test/plugins/wasmedge_ffmpeg/utils.h @@ -0,0 +1,164 @@ +#pragma once +#include "avcodec/module.h" +#include "avfilter/module.h" +#include "avformat/module.h" +#include "avutil/module.h" +#include "common/types.h" +#include "runtime/callingframe.h" +#include "runtime/instance/module.h" +#include "swresample/module.h" +#include "swscale/module.h" +#include "gtest/gtest.h" + +namespace WasmEdge { +namespace Host { +namespace WasmEdgeFFmpeg { +inline void writeUInt32(WasmEdge::Runtime::Instance::MemoryInstance *MemInst, + uint32_t Value, uint32_t &Ptr) { + uint32_t *BufPtr = MemInst->getPointer(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(Offset), Cnt, C); +} + +inline void fillMemContent(WasmEdge::Runtime::Instance::MemoryInstance *MemInst, + uint32_t Offset, const std::string &Str) noexcept { + char *Buf = MemInst->getPointer(Offset); + std::copy_n(Str.c_str(), Str.length(), Buf); +} + +inline void writeSInt32(WasmEdge::Runtime::Instance::MemoryInstance *MemInst, + int32_t Value, uint32_t &Ptr) { + int32_t *BufPtr = MemInst->getPointer(Ptr); + *BufPtr = Value; +} + +inline int32_t readSInt32(WasmEdge::Runtime::Instance::MemoryInstance *MemInst, + uint32_t &Ptr) { + int32_t *BufPtr = MemInst->getPointer(Ptr); + return *BufPtr; +} + +inline uint32_t readUInt32(WasmEdge::Runtime::Instance::MemoryInstance *MemInst, + uint32_t &Ptr) { + uint32_t *BufPtr = MemInst->getPointer(Ptr); + return *BufPtr; +} + +class FFmpegTest : public ::testing::Test { +public: + FFmpegTest() : Mod(""), CallFrame(nullptr, &Mod) { + Mod.addHostMemory( + "memory", std::make_unique( + 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 = dynamic_cast( + Module->create().release()); + } + if (const auto *Module = Plugin->findModule("wasmedge_ffmpeg_avutil"sv)) { + AVUtilMod = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::WasmEdgeFFmpegAVUtilModule + *>(Module->create().release()); + } + if (const auto *Module = + Plugin->findModule("wasmedge_ffmpeg_swscale"sv)) { + SWScaleMod = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::SWScale::WasmEdgeFFmpegSWScaleModule + *>(Module->create().release()); + } + if (const auto *Module = + Plugin->findModule("wasmedge_ffmpeg_avcodec"sv)) { + AVCodecMod = dynamic_cast< + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::WasmEdgeFFmpegAVCodecModule + *>(Module->create().release()); + } + if (const auto *Module = + Plugin->findModule("wasmedge_ffmpeg_swresample"sv)) { + SWResampleMod = + dynamic_cast( + Module->create().release()); + } + if (const auto *Module = + Plugin->findModule("wasmedge_ffmpeg_avfilter"sv)) { + AVFilterMod = dynamic_cast( + Module->create().release()); + } + } + } + + ~FFmpegTest() override { + if (AVUtilMod) { + delete AVUtilMod; + } + if (AVCodecMod) { + delete AVCodecMod; + } + if (SWScaleMod) { + delete SWScaleMod; + } + if (SWResampleMod) { + delete SWResampleMod; + } + if (AVFormatMod) { + delete AVFormatMod; + } + if (AVFilterMod) { + delete AVFilterMod; + } + } + +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 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. + WasmEdge::Host::WasmEdgeFFmpeg::AVFormat::WasmEdgeFFmpegAVFormatModule + *AVFormatMod = nullptr; + WasmEdge::Host::WasmEdgeFFmpeg::AVUtil::WasmEdgeFFmpegAVUtilModule + *AVUtilMod = nullptr; + WasmEdge::Host::WasmEdgeFFmpeg::SWResample::WasmEdgeFFmpegSWResampleModule + *SWResampleMod = nullptr; + WasmEdge::Host::WasmEdgeFFmpeg::SWScale::WasmEdgeFFmpegSWScaleModule + *SWScaleMod = nullptr; + WasmEdge::Host::WasmEdgeFFmpeg::AVcodec::WasmEdgeFFmpegAVCodecModule + *AVCodecMod = nullptr; + WasmEdge::Host::WasmEdgeFFmpeg::AVFilter::WasmEdgeFFmpegAVFilterModule + *AVFilterMod = nullptr; +}; +} // namespace WasmEdgeFFmpeg +} // namespace Host +} // namespace WasmEdge diff --git a/test/plugins/wasmedge_image/wasmedge_image.cpp b/test/plugins/wasmedge_image/wasmedge_image.cpp index 0583c1c762fc..a5ea33563b82 100644 --- a/test/plugins/wasmedge_image/wasmedge_image.cpp +++ b/test/plugins/wasmedge_image/wasmedge_image.cpp @@ -17,8 +17,8 @@ namespace { WasmEdge::Runtime::Instance::ModuleInstance *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(); diff --git a/test/plugins/wasmedge_opencvmini/wasmedge_opencvmini.cpp b/test/plugins/wasmedge_opencvmini/wasmedge_opencvmini.cpp index 926e1330f2b6..d3b570c9d2dc 100644 --- a/test/plugins/wasmedge_opencvmini/wasmedge_opencvmini.cpp +++ b/test/plugins/wasmedge_opencvmini/wasmedge_opencvmini.cpp @@ -17,8 +17,8 @@ namespace { WasmEdge::Runtime::Instance::ModuleInstance *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)) { diff --git a/test/plugins/wasmedge_process/wasmedge_process.cpp b/test/plugins/wasmedge_process/wasmedge_process.cpp index 9c25f41233ed..96e66b1270d0 100644 --- a/test/plugins/wasmedge_process/wasmedge_process.cpp +++ b/test/plugins/wasmedge_process/wasmedge_process.cpp @@ -19,8 +19,8 @@ WasmEdge::Runtime::CallingFrame DummyCallFrame(nullptr, nullptr); WasmEdge::Runtime::Instance::ModuleInstance *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)) { diff --git a/test/plugins/wasmedge_rustls/wasmedge_rustls.cpp b/test/plugins/wasmedge_rustls/wasmedge_rustls.cpp index 1e758cf0fdc4..f34d3a7848a4 100644 --- a/test/plugins/wasmedge_rustls/wasmedge_rustls.cpp +++ b/test/plugins/wasmedge_rustls/wasmedge_rustls.cpp @@ -15,9 +15,9 @@ 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)); + WasmEdge::Plugin::Plugin::load(std::filesystem::u8path( + "../../../plugins/wasmedge_rustls/" WASMEDGE_LIB_PREFIX + "wasmedge_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(); diff --git a/test/plugins/wasmedge_tensorflow/wasmedge_tensorflow.cpp b/test/plugins/wasmedge_tensorflow/wasmedge_tensorflow.cpp index 253ab8281741..0b0617d3c6ca 100644 --- a/test/plugins/wasmedge_tensorflow/wasmedge_tensorflow.cpp +++ b/test/plugins/wasmedge_tensorflow/wasmedge_tensorflow.cpp @@ -17,8 +17,8 @@ namespace { WasmEdge::Runtime::Instance::ModuleInstance *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)) { diff --git a/test/plugins/wasmedge_tensorflowlite/wasmedge_tensorflowlite.cpp b/test/plugins/wasmedge_tensorflowlite/wasmedge_tensorflowlite.cpp index b0cfa5c3b1c9..ebddf267e10e 100644 --- a/test/plugins/wasmedge_tensorflowlite/wasmedge_tensorflowlite.cpp +++ b/test/plugins/wasmedge_tensorflowlite/wasmedge_tensorflowlite.cpp @@ -17,8 +17,8 @@ namespace { WasmEdge::Runtime::Instance::ModuleInstance *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)) { diff --git a/test/plugins/wasmedge_zlib/wasmedge_zlib.cpp b/test/plugins/wasmedge_zlib/wasmedge_zlib.cpp index d526178ab593..1bf5bdc3d9ab 100644 --- a/test/plugins/wasmedge_zlib/wasmedge_zlib.cpp +++ b/test/plugins/wasmedge_zlib/wasmedge_zlib.cpp @@ -20,8 +20,8 @@ WasmEdge::Runtime::CallingFrame DummyCallFrame(nullptr, nullptr); WasmEdge::Runtime::Instance::ModuleInstance *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(); diff --git a/test/spec/CMakeLists.txt b/test/spec/CMakeLists.txt index 0e1eabe48bc5..2e814f412140 100644 --- a/test/spec/CMakeLists.txt +++ b/test/spec/CMakeLists.txt @@ -26,15 +26,7 @@ else() if(MSVC) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - get_property( - compile_options - DIRECTORY - PROPERTY COMPILE_OPTIONS - ) - set_property( - DIRECTORY - APPEND - PROPERTY COMPILE_OPTIONS + add_compile_options( -Wno-undef -Wno-suggest-override -Wno-documentation @@ -50,15 +42,13 @@ else() -Wno-format-nonliteral -Wno-unused-exception-parameter -Wno-unused-member-function - ) - unset(compile_options) + -Wno-missing-prototypes + ) elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - set_property( - DIRECTORY - APPEND - PROPERTY COMPILE_OPTIONS + add_compile_options( /wd4100 # unreferenced formal parameter - ) + /wd4505 # unreferenced local function has been removed + ) endif() endif() @@ -76,7 +66,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) wasmedge_copy_spec_testsuite(${PROPOSAL}) endforeach() @@ -86,7 +76,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..7151d3583bbc 100644 --- a/test/spec/hostfunc.h +++ b/test/spec/hostfunc.h @@ -94,11 +94,11 @@ class SpecTestModule : public Runtime::Instance::ModuleInstance { addHostGlobal( "global_f32", std::make_unique( - AST::GlobalType(TypeCode::F32, ValMut::Const), float(666))); + AST::GlobalType(TypeCode::F32, ValMut::Const), float(666.6))); addHostGlobal( "global_f64", std::make_unique( - 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..6f6f04d684dd 100644 --- a/test/spec/spectest.cpp +++ b/test/spec/spectest.cpp @@ -15,7 +15,7 @@ //===----------------------------------------------------------------------===// #include "spectest.h" -#include "common/log.h" +#include "common/spdlog.h" #include "simdjson.h" #include @@ -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( - 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(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( - 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) { @@ -254,6 +259,14 @@ 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}, }; } // namespace @@ -299,6 +312,21 @@ bool SpecTest::compare(const std::pair &Expected, const std::pair &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(reinterpret_cast( + R.getPtr())) == static_cast(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 +342,109 @@ bool SpecTest::compare(const std::pair &Expected, } return std::isnan(Got.first.get()); } + } else if (TypeStr == "ref"sv) { + // "ref" fits all reference types. + if (!Got.second.isRefType()) { + return false; + } + return IsRefMatch(Got.first.get()); + } 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()); + } 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()); + } 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()); + } 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()); + } 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()); + } else if (TypeStr == "nullref"sv) { + if (!Got.second.isRefType() || + Got.second.getHeapTypeCode() != TypeCode::NullRef) { + return false; + } + return IsRefMatch(Got.first.get()); } else if (TypeStr == "funcref"sv) { + // "funcref" fits funcref and nullfuncref. if (!Got.second.isFuncRefType()) { return false; } - if (ValStr == "null"sv) { - return Got.first.get().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().isNull(); + return IsRefMatch(Got.first.get()); + } else if (TypeStr == "nullfuncref"sv) { + if (!Got.second.isRefType() || + Got.second.getHeapTypeCode() != TypeCode::NullFuncRef) { + return false; } + return IsRefMatch(Got.first.get()); } else if (TypeStr == "externref"sv) { + // "externref" fits externref and nullexternref. if (!Got.second.isExternRefType()) { return false; } - if (ValStr == "null"sv) { - return Got.first.get().isNull(); - } else { - if (Got.first.get().isNull()) { - return false; - } - return static_cast(reinterpret_cast( - &WasmEdge::retrieveExternRef( - Got.first.get()))) == - static_cast(std::stoul(ValStr)); - } - } else if (TypeStr == "ref"sv) { - if (!Got.second.isNullableRefType()) { + return IsRefMatch(Got.first.get()); + } else if (TypeStr == "nullexternref"sv) { + if (!Got.second.isRefType() || + Got.second.getHeapTypeCode() != TypeCode::NullExternRef) { return false; } - if (ValStr == "null"sv) { - return Got.first.get().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().isNull(); + return IsRefMatch(Got.first.get()); + } else if (TypeStr == "exnref"sv) { + if (!Got.second.isRefType() || + Got.second.getHeapTypeCode() != TypeCode::ExnRef) { + return false; } + return IsRefMatch(Got.first.get()); } else if (TypeStr == "i32"sv) { if (Got.second.getCode() != TypeCode::I32) { return false; @@ -629,6 +723,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) { @@ -691,7 +799,7 @@ void SpecTest::run(std::string_view Proposal, std::string_view UnitName) { } 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 +809,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..53e2c4222e9b 100644 --- a/test/spec/spectest.h +++ b/test/spec/spectest.h @@ -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..cdbad7f85169 100644 --- a/test/thread/CMakeLists.txt +++ b/test/thread/CMakeLists.txt @@ -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..4867a9975c6c 100644 --- a/test/thread/ThreadTest.cpp +++ b/test/thread/ThreadTest.cpp @@ -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/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 0d862b2f429b..ee81128c5b29 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: 2019-2022 Second State INC -if(WASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) add_subdirectory(blake3) endif() 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/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(user_data); -+ if (enable_log && *enable_log) { -+ fputs(text, stderr); -+ fflush(stderr); -+ } - } diff --git a/thirdparty/wasi_crypto/api.hpp b/thirdparty/wasi_crypto/api.hpp index 8d6f60817d28..306526b51c3b 100644 --- a/thirdparty/wasi_crypto/api.hpp +++ b/thirdparty/wasi_crypto/api.hpp @@ -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; diff --git a/tools/wasmedge/CMakeLists.txt b/tools/wasmedge/CMakeLists.txt index a886510d4cbf..a99141340873 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 -if(WASMEDGE_BUILD_AOT_RUNTIME) +if(WASMEDGE_USE_LLVM) wasmedge_add_executable(wasmedgec wasmedgec.cpp ) 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/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.build-plugins-deps b/utils/docker/Dockerfile.build-plugins-deps index 21c73d977aaa..ae797d66466b 100644 --- a/utils/docker/Dockerfile.build-plugins-deps +++ b/utils/docker/Dockerfile.build-plugins-deps @@ -7,6 +7,6 @@ RUN apt update && apt install -y \ RUN rm -rf /var/lib/apt/lists/* -COPY install-opencvmini.sh . +COPY opencvmini/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..92f7bd67d8ed 100644 --- a/utils/docker/Dockerfile.ci-image-base +++ b/utils/docker/Dockerfile.ci-image-base @@ -13,7 +13,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..359f44512ec4 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 "2023.0.2" +ENV OPENVINO_YEAR "2023" + RUN yum clean all diff --git a/utils/docker/Dockerfile.manylinux2014_aarch64 b/utils/docker/Dockerfile.manylinux2014_aarch64 index 59ca239e828a..72c5a1a49f9f 100644 --- a/utils/docker/Dockerfile.manylinux2014_aarch64 +++ b/utils/docker/Dockerfile.manylinux2014_aarch64 @@ -5,7 +5,7 @@ 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}} @@ -27,7 +27,7 @@ RUN cd && (yum check-update || true) && yum install -y xz openssl-devel rpm-buil 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 && \ + 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 v1.11.1.tar.gz | tar -xf - && \ diff --git a/utils/docker/Dockerfile.manylinux2014_x86_64 b/utils/docker/Dockerfile.manylinux2014_x86_64 index cc6a942a3a0f..9555dbbf4b7f 100644 --- a/utils/docker/Dockerfile.manylinux2014_x86_64 +++ b/utils/docker/Dockerfile.manylinux2014_x86_64 @@ -5,7 +5,7 @@ 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}} @@ -27,7 +27,7 @@ RUN cd && (yum check-update || true) && yum install -y xz openssl-devel rpm-buil 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 && \ + 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 v1.11.1.tar.gz | tar -xf - && \ diff --git a/utils/docker/Dockerfile.manylinux_2_28-build-plugins-deps b/utils/docker/Dockerfile.manylinux_2_28-build-plugins-deps new file mode 100644 index 000000000000..4be4bf9743c3 --- /dev/null +++ b/utils/docker/Dockerfile.manylinux_2_28-build-plugins-deps @@ -0,0 +1,39 @@ +ARG BASE=wasmedge/wasmedge:manylinux_2_28_x86_64 +FROM ${BASE} + +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 PKG_CONFIG_PATH /opt/rh/gcc-toolset-13/root/usr/lib64/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}} + +RUN cd && (yum check-update || true) && \ + yum install -y wget unzip zlib-devel zlib-static +RUN yum install -y yum-utils && \ + yum-config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo && \ + yum install -y gh + +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_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 "2023.0.2" +ENV OPENVINO_YEAR "2023" + +RUN yum clean all diff --git a/utils/docker/Dockerfile.manylinux_2_28_aarch64 b/utils/docker/Dockerfile.manylinux_2_28_aarch64 new file mode 100644 index 000000000000..98dc2e368db8 --- /dev/null +++ b/utils/docker/Dockerfile.manylinux_2_28_aarch64 @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# SPDX-FileCopyrightText: 2019-2022 Second State INC + +FROM quay.io/pypa/manylinux_2_28_aarch64 + +MAINTAINER hydai hydai@secondstate.io + +ADD SHA256SUM.manylinux_2_28 /root/ + +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 PKG_CONFIG_PATH /opt/rh/gcc-toolset-13/root/usr/lib64/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}} + +RUN cd && (yum check-update || true) && yum install -y openssl-devel rpm-build cmake && \ + 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="AArch64;BPF" -DLLVM_ENABLE_PROJECTS="lld;clang" \ + -DLLVM_DEFAULT_TARGET_TRIPLE="aarch64-redhat-linux-gnu" \ + -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_x86_64 b/utils/docker/Dockerfile.manylinux_2_28_x86_64 new file mode 100644 index 000000000000..ba1fe2e9078d --- /dev/null +++ b/utils/docker/Dockerfile.manylinux_2_28_x86_64 @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# SPDX-FileCopyrightText: 2019-2022 Second State INC + +FROM quay.io/pypa/manylinux_2_28_x86_64 + +MAINTAINER hydai hydai@secondstate.io + +ADD SHA256SUM.manylinux_2_28 /root/ + +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 PKG_CONFIG_PATH /opt/rh/gcc-toolset-13/root/usr/lib64/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}} + +RUN cd && (yum check-update || true) && yum install -y openssl-devel rpm-build cmake && \ + 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="X86;BPF" -DLLVM_ENABLE_PROJECTS="lld;clang" \ + -DLLVM_DEFAULT_TARGET_TRIPLE="x86_64-pc-linux-gnu" \ + -DBUILD_SHARED_LIBS=OFF llvm && \ + cmake --build build --target install && \ + rm -rf build && rm -rf * + +RUN yum clean all diff --git a/utils/docker/SHA256SUM b/utils/docker/SHA256SUM.manylinux2014 similarity index 100% rename from utils/docker/SHA256SUM rename to utils/docker/SHA256SUM.manylinux2014 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.sh b/utils/docker/build.sh index 3d99a86ffc3d..bdcea629c9a2 100755 --- a/utils/docker/build.sh +++ b/utils/docker/build.sh @@ -15,7 +15,7 @@ function docker_build local NAME_TAG=${NAME}:${TAG} echo "Building docker image \"${NAME_TAG}\" from file \"${FILENAME}\"." - ( set -x; docker build "$@" -f "${FILENAME}" -t "${NAME_TAG}" . ) + ( set -x; docker build "$@" -f "docker/${FILENAME}" -t "${NAME_TAG}" . ) if [[ "${TAG}" == im-* ]]; then INTERMEDIATES+=( "${NAME_TAG}" ) diff --git a/utils/docker/docker-bake.ci-image-base b/utils/docker/docker-bake.ci-image-base new file mode 100644 index 000000000000..0054032c0912 --- /dev/null +++ b/utils/docker/docker-bake.ci-image-base @@ -0,0 +1,26 @@ +group "default" { + targets = [ + "x86_64", + "aarch64" + ] +} + +target "base" { + dockerfile = "./utils/docker/Dockerfile.ci-image-base" + context = "." +} + +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/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..fabbf84ab9b2 --- /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-2022 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..72ac145898a6 --- /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 .. \ No newline at end of file diff --git a/utils/install.py b/utils/install.py index 921f51676bbe..eb6fe81d9936 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) ] @@ -332,6 +339,7 @@ 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_NOAVX = "wasi_nn-ggml-noavx" WASI_NN_GGML_BLAS = "wasi_nn-ggml-blas" WASMEDGE_TENSORFLOW_PLUGIN = WASMEDGE.lower() + "_" + TENSORFLOW WASMEDGE_TENSORFLOW_LITE_PLUGIN = WASMEDGE.lower() + "_" + TENSORFLOW_LITE_P @@ -346,6 +354,7 @@ def compare(self, version2, separator=". |-", ignorecase=True): WASI_NN_TENSORFLOW_LITE, WASI_NN_GGML, WASI_NN_GGML_CUDA, + WASI_NN_GGML_NOAVX, WASI_NN_GGML_BLAS, WASMEDGE_TENSORFLOW_PLUGIN, WASMEDGE_TENSORFLOW_LITE_PLUGIN, @@ -363,6 +372,7 @@ def compare(self, version2, separator=". |-", ignorecase=True): "ubuntu20.04" + "x86_64" + WASI_NN_PYTORCH: VersionString("0.11.1-alpha.1"), "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"), @@ -396,8 +406,10 @@ def compare(self, version2, separator=". |-", ignorecase=True): "ubuntu20.04" + "x86_64" + WASMEDGE_IMAGE_PLUGIN: VersionString("0.13.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"), } @@ -1146,11 +1158,45 @@ 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: + # 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 +1204,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, @@ -1614,8 +1659,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: diff --git a/utils/install_v2.sh b/utils/install_v2.sh new file mode 100755 index 000000000000..83e4b0c86b06 --- /dev/null +++ b/utils/install_v2.sh @@ -0,0 +1,607 @@ +#!/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 +} + +detect_cuda_nvcc() { + local cuda="" + cuda=$(/usr/local/cuda/bin/nvcc --version 2>/dev/null | grep "Cuda compilation tools" | cut -f5 -d ' ' | cut -f1 -d ',') + if [[ "${cuda}" =~ "12" ]]; then + cuda="12" + elif [[ "${cuda}" =~ "11" ]]; then + cuda="11" + fi + + echo ${cuda} +} + +detect_cuda_nvidia_smi() { + local cuda="" + cuda=$(nvidia-smi -q 2>/dev/null | grep CUDA | cut -f2 -d ':' | cut -f2 -d ' ') + if [[ "${cuda}" =~ "12" ]]; then + cuda="12" + elif [[ "${cuda}" =~ "11" ]]; then + cuda="11" + fi + + echo ${cuda} +} + +detect_cuda() { + local cuda="" + cuda=$(detect_cuda_nvcc) + if [[ "${cuda}" == "" ]]; then + cuda=$(detect_cuda_nvidia_smi) + fi + + echo ${cuda} +} + +_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.13.5" +} + +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_RUSTLS=0 +ENABLE_NOAVX=0 +GGML_BUILD_NUMBER="" + +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 < [-V] + WasmEdge installation. + Mandatory arguments to long options are mandatory for short options too. + Long options should be assigned with '=' + + -h, --help Display help + + --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. + + --rustls Install the Rustls plugin. + Default is disabled. + + --ggmlbn=[b2963] Install the specific GGML plugin. + Default is the latest. + + --os=[Linux/Darwin] Set the OS. + Default is detected OS. + + --arch[x86_64/aarch64/arm64] Set the ARCH. + Default is detected ARCH. + + 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 <>"$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) + info "Detected CUDA version: ${cuda}" + info "CUDA version from nvcc: $(detect_cuda_nvcc)" + info "CUDA version from nvidia-smi: $(detect_cuda_nvidia_smi)" + + if [ "${cuda}" == "12" ]; then + CUDA_EXT="-cuda" + elif [ "${cuda}" == "11" ]; then + if [ "${ARCH}" == "aarch64" ]; then + CUDA_EXT="-cuda" + else + CUDA_EXT="-cuda-11" + fi + 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_rustls_plugin() { + info "Fetching WasmEdge-Rustls-Plugin" + _downloader "https://github.com/WasmEdge/WasmEdge/releases/download/$VERSION/WasmEdge-plugin-wasmedge_rustls-$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-wasmedge_rustls-${VERSION}-${RELEASE_PKG}" +} + +wasmedge_checks() { + if [ "${ARCH}" == $(uname -m) ] && [ "${OS}" == $(uname) ] ; then + # Check only MAJOR.MINOR.PATCH + local version=$1 + shift + for var in "$@"; do + if [ "$var" == "" ]; then + continue + fi + local V=$("$IPATH/bin/$var" --version | sed 's/^.*[^0-9]\([0-9]*\.[0-9]*\.[0-9]*\).*$/\1/') + local V_=$(echo $version | sed 's/\([0-9]*\.[0-9]*\.[0-9]*\).*$/\1/') + if [ "$V" = "$V_" ]; then + echo "${GREEN}Installation of $var-$version successful${NC}" + else + echo "${YELLOW}version $V_ does not match $V for $var-$version${NC}" + exit 1 + fi + done + 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 + while getopts "e:hp:v:r:u:V-:" 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}")" + ;; + ggmlbn) + GGML_BUILD_NUMBER="${OPTARG}" + ;; + noavx) + ENABLE_NOAVX=1 + ;; + rustls) + ENABLE_RUSTLS=1 + ;; + os) + OS="${OPTARG^}" + ;; + arch) + ARCH="${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 + [ -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 [ "${ENABLE_RUSTLS}" == 1 ]; then + get_wasmedge_rustls_plugin + fi + + install "$IPKG" "include" "lib" "bin" "plugin" + wasmedge_checks "$VERSION" "wasmedge" + 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..2fba76ab763b 100755 --- a/utils/ohos/build_for_ohos.sh +++ b/utils/ohos/build_for_ohos.sh @@ -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/CMakeLists.txt b/utils/ohos/configuration/CMakeLists.txt index 980a23a2119a..f6b88b78ac9c 100644 --- a/utils/ohos/configuration/CMakeLists.txt +++ b/utils/ohos/configuration/CMakeLists.txt @@ -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) diff --git a/utils/opencvmini/install-opencvmini.sh b/utils/opencvmini/install-opencvmini.sh index ac5128efd0cc..bd95a9029665 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 +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/configuration/Makefile b/utils/openwrt/configuration/Makefile index 08995b25b9b5..7fdfa0fa9b03 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,7 @@ 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-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-openvino.sh b/utils/wasi-nn/install-openvino.sh index 761b6a21d2f8..57afdee82455 100755 --- a/utils/wasi-nn/install-openvino.sh +++ b/utils/wasi-nn/install-openvino.sh @@ -3,7 +3,7 @@ # SPDX-FileCopyrightText: 2019-2022 Second State INC set -e -echo "Installing OpenVINO with version 2023.0.2" +echo "Installing OpenVINO with version 2023.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