From c11d72d7fec187a13930ecbb137a902be29a6fd6 Mon Sep 17 00:00:00 2001 From: YiYing He Date: Tue, 13 Jan 2026 19:50:00 +0800 Subject: [PATCH] docs: update C API docs to 0.16.1 Signed-off-by: YiYing He --- .env | 2 +- docs/embed/c/intro.md | 4 +- docs/embed/c/reference/0.10.x.md | 2 +- docs/embed/c/reference/0.11.x.md | 2 +- docs/embed/c/reference/0.12.x.md | 2 +- docs/embed/c/reference/0.13.x.md | 4 +- docs/embed/c/reference/0.14.x.md | 3206 ++++++++++++++++ docs/embed/c/reference/0.15.x.md | 3295 +++++++++++++++++ docs/embed/c/reference/0.9.x.md | 2 +- docs/embed/c/reference/latest.md | 193 +- docs/embed/c/reference/upgrade_to_0.10.0.md | 2 +- docs/embed/c/reference/upgrade_to_0.11.0.md | 2 +- docs/embed/c/reference/upgrade_to_0.12.0.md | 2 +- docs/embed/c/reference/upgrade_to_0.13.0.md | 2 +- docs/embed/c/reference/upgrade_to_0.14.0.md | 2 +- docs/embed/c/reference/upgrade_to_0.15.0.md | 118 + docs/embed/c/reference/upgrade_to_0.16.0.md | 83 + docs/start/build-and-run/aot.md | 34 +- docs/start/build-and-run/cli.md | 38 +- docs/start/wasmedge/component_model.md | 2 +- docs/start/wasmedge/extensions/proposals.md | 17 +- .../current/embed/c/intro.md | 4 +- .../current/embed/c/reference/0.10.x.md | 2 +- .../current/embed/c/reference/0.11.x.md | 2 +- .../current/embed/c/reference/0.12.x.md | 2 +- .../current/embed/c/reference/0.13.x.md | 4 +- .../current/embed/c/reference/0.14.x.md | 3206 ++++++++++++++++ .../current/embed/c/reference/0.15.x.md | 3295 +++++++++++++++++ .../current/embed/c/reference/0.9.x.md | 2 +- .../current/embed/c/reference/latest.md | 193 +- .../embed/c/reference/upgrade_to_0.10.0.md | 2 +- .../embed/c/reference/upgrade_to_0.11.0.md | 2 +- .../embed/c/reference/upgrade_to_0.12.0.md | 2 +- .../embed/c/reference/upgrade_to_0.13.0.md | 2 +- .../embed/c/reference/upgrade_to_0.14.0.md | 2 +- .../embed/c/reference/upgrade_to_0.15.0.md | 118 + .../embed/c/reference/upgrade_to_0.16.0.md | 83 + .../current/start/build-and-run/run.md | 2 +- 38 files changed, 13840 insertions(+), 97 deletions(-) create mode 100644 docs/embed/c/reference/0.14.x.md create mode 100644 docs/embed/c/reference/0.15.x.md create mode 100644 docs/embed/c/reference/upgrade_to_0.15.0.md create mode 100644 docs/embed/c/reference/upgrade_to_0.16.0.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.14.x.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.15.x.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.15.0.md create mode 100644 i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.16.0.md diff --git a/.env b/.env index 35eaafb3..0f3557c9 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -WASMEDGE_VERSION='0.14.1' +WASMEDGE_VERSION='0.16.1' WASMEDGE_GO_VERSION='0.14.0' \ No newline at end of file diff --git a/docs/embed/c/intro.md b/docs/embed/c/intro.md index d39e87b7..4c48cc23 100644 --- a/docs/embed/c/intro.md +++ b/docs/embed/c/intro.md @@ -121,7 +121,9 @@ sys 0m0.011s ## API References -- [0.14.1](reference/latest.md) +- [0.16.1](reference/latest.md) +- [0.15.1](reference/0.15.x.md) +- [0.14.1](reference/0.14.x.md) - [0.13.5](reference/0.13.x.md) - [0.12.1](reference/0.12.x.md) - [0.11.2](reference/0.11.x.md) diff --git a/docs/embed/c/reference/0.10.x.md b/docs/embed/c/reference/0.10.x.md index c25208fb..ae706550 100644 --- a/docs/embed/c/reference/0.10.x.md +++ b/docs/embed/c/reference/0.10.x.md @@ -1,5 +1,5 @@ --- -sidebar_position: 9 +sidebar_position: 13 --- # C API 0.10.1 Documentation diff --git a/docs/embed/c/reference/0.11.x.md b/docs/embed/c/reference/0.11.x.md index a3708cbe..8269f8bb 100644 --- a/docs/embed/c/reference/0.11.x.md +++ b/docs/embed/c/reference/0.11.x.md @@ -1,5 +1,5 @@ --- -sidebar_position: 7 +sidebar_position: 11 --- # C API 0.11.2 Documentation diff --git a/docs/embed/c/reference/0.12.x.md b/docs/embed/c/reference/0.12.x.md index 33e8df49..e6dfa214 100644 --- a/docs/embed/c/reference/0.12.x.md +++ b/docs/embed/c/reference/0.12.x.md @@ -1,5 +1,5 @@ --- -sidebar_position: 5 +sidebar_position: 9 --- # C API 0.12.1 Documentation diff --git a/docs/embed/c/reference/0.13.x.md b/docs/embed/c/reference/0.13.x.md index 714ac119..ea4aaad7 100644 --- a/docs/embed/c/reference/0.13.x.md +++ b/docs/embed/c/reference/0.13.x.md @@ -1,11 +1,13 @@ --- -sidebar_position: 3 +sidebar_position: 7 --- # C API 0.13.5 Documentation [WasmEdge C API](https://github.com/WasmEdge/WasmEdge/blob/master/include/api/wasmedge/wasmedge.h) denotes an interface to access the WasmEdge runtime at version `0.13.5`. The following are the guides to working with the C APIs of WasmEdge. +**Developers can refer to [here to upgrade to v0.14.0](upgrade_to_0.14.0).** + ## WasmEdge Installation ### Download And Install diff --git a/docs/embed/c/reference/0.14.x.md b/docs/embed/c/reference/0.14.x.md new file mode 100644 index 00000000..3a00ec5a --- /dev/null +++ b/docs/embed/c/reference/0.14.x.md @@ -0,0 +1,3206 @@ +--- +sidebar_position: 5 +--- + +# C API 0.14.1 Documentation + +[WasmEdge C API](https://github.com/WasmEdge/WasmEdge/blob/master/include/api/wasmedge/wasmedge.h) denotes an interface to access the WasmEdge runtime at version `0.14.1`. The following are the guides to working with the C APIs of WasmEdge. + +**Developers can refer to [here to upgrade to v0.15.0](upgrade_to_0.15.0).** + +## WasmEdge Installation + +### Download And Install + +The easiest way to install WasmEdge is to run the following command. Your system should have `git` and `wget` as prerequisites. + +```bash +curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -v 0.14.1 +``` + +For more details, please refer to the [Installation Guide](../../../start/install.md#install) for the WasmEdge installation. + +### Compile Sources + +After the installation of WasmEdge, the following guide can help you to test for the availability of the WasmEdge C API. + +1. Prepare the test C file (and assumed saved as `test.c`): + + ```c + #include + #include + int main() { + printf("WasmEdge version: %s\n", WasmEdge_VersionGet()); + return 0; + } + ``` + +2. Compile the file with `gcc` or `clang`. + + ```bash + gcc test.c -lwasmedge + ``` + +3. Run and get the expected output. + + ```bash + $ ./a.out + WasmEdge version: 0.14.1 + ``` + +### ABI Compatibility + +WasmEdge C API introduces SONAME and SOVERSION since the `0.11.0` release to present the compatibility between different C API versions. + +The releases before 0.11.0 are all unversioned. Please make sure the library version is the same as the corresponding C API version you used. + +| WasmEdge Version | WasmEdge C API Library Name | WasmEdge C API SONAME | WasmEdge C API SOVERSION | +| --- | --- | --- | --- | +| < 0.11.0 | libwasmedge_c.so | Unversioned | Unversioned | +| 0.11.0 to 0.11.1 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.0 | +| 0.11.2 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.1 | +| 0.12.0 to 0.12.1 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.2 | +| 0.13.0 to 0.13.5 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.3 | +| Since 0.14.0 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.1.0 | + +## WasmEdge Basics + +In this part, we will introduce the utilities and concepts of WasmEdge shared library. + +### Version + +The `Version` related APIs provide developers to check for the WasmEdge shared library version. + +```c +#include +printf("WasmEdge version: %s\n", WasmEdge_VersionGet()); +printf("WasmEdge version major: %u\n", WasmEdge_VersionGetMajor()); +printf("WasmEdge version minor: %u\n", WasmEdge_VersionGetMinor()); +printf("WasmEdge version patch: %u\n", WasmEdge_VersionGetPatch()); +``` + +### Logging Settings + +The `WasmEdge_LogSetErrorLevel()` and `WasmEdge_LogSetDebugLevel()` APIs can set the logging system to debug level or error level. By default, the error level is set, and the debug info is hidden. + +Developers can also use the `WasmEdge_LogOff()` API to disable all logging. + +### Value Types + +To describe the value types in WASM, WasmEdge uses the `WasmEdge_ValType` struct to encode the value types. + +1. Number types: `i32`, `i64`, `f32`, `f64`, and `v128` for the `SIMD` proposal + + ```c + WasmEdge_ValType ValType; + ValType = WasmEdge_ValTypeGenI32(); + bool IsTypeI32 = WasmEdge_ValTypeIsI32(ValType); + /* The `IsTypeI32` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenI64(); + bool IsTypeI64 = WasmEdge_ValTypeIsI64(ValType); + /* The `IsTypeI64` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenF32(); + bool IsTypeF32 = WasmEdge_ValTypeIsF32(ValType); + /* The `IsTypeF32` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenF64(); + bool IsTypeF64 = WasmEdge_ValTypeIsF64(ValType); + /* The `IsTypeF64` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenV128(); + bool IsTypeV128 = WasmEdge_ValTypeIsV128(ValType); + /* The `IsTypeV128` will be `TRUE`. */ + ``` + +2. Reference types: `funcref` and `externref` for the `Reference-Types` or `Typed-Function References` proposal + + ```c + WasmEdge_ValType ValType; + + ValType = WasmEdge_ValTypeGenFuncRef(); + /* The nullable funcref type is generated. */ + bool IsTypeFuncRef = WasmEdge_ValTypeIsFuncRef(ValType); + /* The `IsTypeFuncRef` will be `TRUE`. */ + bool IsTypeRef = WasmEdge_ValTypeIsRef(ValType); + /* The `IsTypeRef` will be `TRUE`. */ + bool IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(ValType); + /* The `IsTypeNullableRef` will be `TRUE`. */ + + ValType = WasmEdge_ValTypeGenExternRef(); + /* The nullable externref type is generated. */ + bool IsTypeExternRef = WasmEdge_ValTypeIsExternRef(ValType); + /* The `IsTypeExternRef` will be `TRUE`. */ + IsTypeRef = WasmEdge_ValTypeIsRef(ValType); + /* The `IsTypeRef` will be `TRUE`. */ + IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(ValType); + /* The `IsTypeNullableRef` will be `TRUE`. */ + ``` + +### Values + +In WasmEdge, developers should convert the values to `WasmEdge_Value` objects through APIs for matching to the WASM values for the arguments or returns. With the APIs, the output `WasmEdge_Value` objects will record the correct value types with values. + +1. Number types: `i32`, `i64`, `f32`, `f64`, and `v128` for the `SIMD` proposal + + ```c + WasmEdge_Value Val; + + Val = WasmEdge_ValueGenI32(123456); + bool IsTypeI32 = WasmEdge_ValTypeIsI32(Val.Type); + /* The `IsTypeI32` will be `TRUE`. */ + printf("%d\n", WasmEdge_ValueGetI32(Val)); + /* Will print "123456" */ + + Val = WasmEdge_ValueGenI64(1234567890123LL); + bool IsTypeI64 = WasmEdge_ValTypeIsI64(Val.Type); + /* The `IsTypeI64` will be `TRUE`. */ + printf("%ld\n", WasmEdge_ValueGetI64(Val)); + /* Will print "1234567890123" */ + + Val = WasmEdge_ValueGenF32(123.456f); + bool IsTypeF32 = WasmEdge_ValTypeIsF32(Val.Type); + /* The `IsTypeF32` will be `TRUE`. */ + printf("%f\n", WasmEdge_ValueGetF32(Val)); + /* Will print "123.456001" */ + + Val = WasmEdge_ValueGenF64(123456.123456789); + bool IsTypeF64 = WasmEdge_ValTypeIsF64(Val.Type); + /* The `IsTypeF64` will be `TRUE`. */ + printf("%.10f\n", WasmEdge_ValueGetF64(Val)); + /* Will print "123456.1234567890" */ + ``` + +2. Reference types: `funcref` and `externref` for the `Reference-Types` or `Typed-Function References` proposal + + ```c + WasmEdge_Value Val; + void *Ptr; + uint32_t Num = 10; + /* Generate an externref to NULL. */ + Val = WasmEdge_ValueGenExternRef(NULL); + bool IsNull = WasmEdge_ValueIsNullRef(Val); + /* The `IsNull` will be `TRUE`. */ + bool IsTypeExternRef = WasmEdge_ValTypeIsExternRef(Val.Type); + /* The `IsTypeExternRef` will be `TRUE`. */ + bool IsTypeRef = WasmEdge_ValTypeIsRef(Val.Type); + /* The `IsTypeRef` will be `TRUE`. */ + bool IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(Val.Type); + /* The `IsTypeNullableRef` will be `TRUE`. */ + Ptr = WasmEdge_ValueGetExternRef(Val); + /* The `Ptr` will be `NULL`. */ + + /* Get the function instance by creation or from module instance. */ + const WasmEdge_FunctionInstanceContext *FuncCxt = ...; + /* Generate a funcref with the given function instance context. */ + Val = WasmEdge_ValueGenFuncRef(FuncCxt); + bool IsTypeFuncRef = WasmEdge_ValTypeIsFuncRef(Val.Type); + /* The `IsTypeFuncRef` will be `TRUE`. */ + IsTypeRef = WasmEdge_ValTypeIsRef(Val.Type); + /* The `IsTypeRef` will be `TRUE`. */ + IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(Val.Type); + /* The `IsTypeNullableRef` will be `TRUE`. */ + const WasmEdge_FunctionInstanceContext *GotFuncCxt = + WasmEdge_ValueGetFuncRef(Val); + /* The `GotFuncCxt` will be the same as `FuncCxt`. */ + + /* Generate a externref to `Num`. */ + Val = WasmEdge_ValueGenExternRef(&Num); + Ptr = WasmEdge_ValueGetExternRef(Val); + /* The `Ptr` will be `&Num`. */ + printf("%u\n", *(uint32_t *)Ptr); + /* Will print "10" */ + Num += 55; + printf("%u\n", *(uint32_t *)Ptr); + /* Will print "65" */ + ``` + +### Buffers + +The `WasmEdge_Bytes` object is for the input buffer of loading or compiling module from memory, or the output buffer of serializing a module. + + +:::note +This object is designed for replacing raw buffer as input and output of WasmEdge C API. We recommand developers to use the `WasmEdge_Bytes` related APIs than the raw buffer, such as using `WasmEdge_LoaderParseFromBytes()` instead of `WasmEdge_LoaderParseFromBuffer()`. +::: + +1. Create a `WasmEdge_Bytes` from a buffer with length. + + ```c + uint8_t Buf[4] = {1, 2, 3, 4}; + WasmEdge_Bytes Bytes = WasmEdge_BytesCreate(Buf, 4); + /* The objects should be deleted by `WasmEdge_BytesDelete()`. */ + WasmEdge_BytesDelete(Bytes); + ``` + +2. Wrap a `WasmEdge_Bytes` to a buffer with length. + + The content will not be copied, and the caller should guarantee the life cycle of the input buffer. + + ```c + uint8_t Buf[4] = {1, 2, 3, 4}; + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(Buf, 4); + /* The object should __NOT__ be deleted by `WasmEdge_BytesDelete()`. */ + ``` + +### Strings + +The `WasmEdge_String` object is for the instance names when invoking a WASM function or finding the contexts of instances. + +1. Create a `WasmEdge_String` from a C string (`const char *` with NULL termination) or a buffer with length. + + The content of the C string or buffer will be copied into the `WasmEdge_String` object. + + ```c + char Buf[4] = {50, 55, 60, 65}; + WasmEdge_String Str1 = WasmEdge_StringCreateByCString("test"); + WasmEdge_String Str2 = WasmEdge_StringCreateByBuffer(Buf, 4); + /* The objects should be deleted by `WasmEdge_StringDelete()`. */ + WasmEdge_StringDelete(Str1); + WasmEdge_StringDelete(Str2); + ``` + +2. Wrap a `WasmEdge_String` to a buffer with length. + + The content will not be copied, and the caller should guarantee the life cycle of the input buffer. + + ```c + const char CStr[] = "test"; + WasmEdge_String Str = WasmEdge_StringWrap(CStr, 4); + /* The object should __NOT__ be deleted by `WasmEdge_StringDelete()`. */ + ``` + +3. String comparison + + ```c + const char CStr[] = "abcd"; + char Buf[4] = {0x61, 0x62, 0x63, 0x64}; + WasmEdge_String Str1 = WasmEdge_StringWrap(CStr, 4); + WasmEdge_String Str2 = WasmEdge_StringCreateByBuffer(Buf, 4); + bool IsEq = WasmEdge_StringIsEqual(Str1, Str2); + /* The `IsEq` will be `TRUE`. */ + WasmEdge_StringDelete(Str2); + ``` + +4. Convert to C string + + ```c + char Buf[256]; + WasmEdge_String Str = + WasmEdge_StringCreateByCString("test_wasmedge_string"); + uint32_t StrLength = WasmEdge_StringCopy(Str, Buf, sizeof(Buf)); + /* StrLength will be 20 */ + printf("String: %s\n", Buf); + /* Will print "test_wasmedge_string". */ + ``` + +### Results + +The `WasmEdge_Result` object specifies the execution status. APIs about WASM execution will return the `WasmEdge_Result` to denote the status. + +```c +WasmEdge_Result Res = WasmEdge_Result_Success; +bool IsSucceeded = WasmEdge_ResultOK(Res); +/* The `IsSucceeded` will be `TRUE`. */ +uint32_t Code = WasmEdge_ResultGetCode(Res); +/* The `Code` will be 0. */ +const char *Msg = WasmEdge_ResultGetMessage(Res); +/* The `Msg` will be "success". */ +enum WasmEdge_ErrCategory Category = WasmEdge_ResultGetCategory(Res); +/* The `Category` will be WasmEdge_ErrCategory_WASM. */ + +Res = WasmEdge_ResultGen(WasmEdge_ErrCategory_UserLevelError, 123); +/* Generate the user-defined result with code. */ +Code = WasmEdge_ResultGetCode(Res); +/* The `Code` will be 123. */ +Category = WasmEdge_ResultGetCategory(Res); +/* The `Category` will be WasmEdge_ErrCategory_UserLevelError. */ +``` + +### Contexts + +The objects, such as `VM`, `Store`, and `Function`, are composed of `Context`s. All of the contexts can be created by calling the corresponding creation APIs and should be destroyed by calling the corresponding deletion APIs. Developers have responsibilities to manage the contexts for memory management. + +```c +/* Create the configure context. */ +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); +/* Delete the configure context. */ +WasmEdge_ConfigureDelete(ConfCxt); +``` + +The details of other contexts will be introduced later. + +### WASM Data Structures + +The WASM data structures are used for creating instances or can be queried from instance contexts. The details of instances creation will be introduced in the [Instances](#instances). + +1. Limit + + The `WasmEdge_Limit` struct is defined in the header: + + ```c + /// Struct of WASM limit. + typedef struct WasmEdge_Limit { + /// Boolean to describe has max value or not. + bool HasMax; + /// Boolean to describe is shared memory or not. + bool Shared; + /// Minimum value. + uint32_t Min; + /// Maximum value. Will be ignored if the `HasMax` is false. + uint32_t Max; + } WasmEdge_Limit; + ``` + + Developers can initialize the struct by assigning it's value, and the `Max` value is needed to be larger or equal to the `Min` value. The API `WasmEdge_LimitIsEqual()` is provided to compare with 2 `WasmEdge_Limit` structs. + +2. Function type context + + The `Function Type` context is used for the `Function` creation, checking the value types of a `Function` instance, or getting the function type with function name from VM. Developers can use the `Function Type` context APIs to get the parameter or return value types information. + + ```c + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI64()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenFuncRef()}; + WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + + WasmEdge_ValType Buf[16]; + uint32_t ParamLen = WasmEdge_FunctionTypeGetParametersLength(FuncTypeCxt); + /* `ParamLen` will be 2. */ + uint32_t GotParamLen = WasmEdge_FunctionTypeGetParameters(FuncTypeCxt, Buf, 16); + /* + * `GotParamLen` will be 2, and `Buf[0]` and `Buf[1]` will be the same as + * `ParamList`. + */ + uint32_t ReturnLen = WasmEdge_FunctionTypeGetReturnsLength(FuncTypeCxt); + /* `ReturnLen` will be 1. */ + uint32_t GotReturnLen = WasmEdge_FunctionTypeGetReturns(FuncTypeCxt, Buf, 16); + /* + * `GotReturnLen` will be 1, and `Buf[0]` will be the same as `ReturnList`. + */ + + WasmEdge_FunctionTypeDelete(FuncTypeCxt); + ``` + +3. Table type context + + The `Table Type` context is used for `Table` instance creation or getting information from `Table` instances. + + ```c + WasmEdge_Limit TabLim = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_TableTypeCreate(WasmEdge_ValTypeGenExternRef(), TabLim); + + WasmEdge_ValType GotRefType = WasmEdge_TableTypeGetRefType(TabTypeCxt); + bool IsTypeExternRef = WasmEdge_ValTypeIsExternRef(GotRefType); + /* `IsTypeExternRef` will be `TRUE`. */ + bool IsTypeRef = WasmEdge_ValTypeIsRef(GotRefType); + /* `IsTypeRef` will be `TRUE`. */ + bool IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(GotRefType); + /* `IsTypeNullableRef` will be `TRUE`. */ + WasmEdge_Limit GotTabLim = WasmEdge_TableTypeGetLimit(TabTypeCxt); + /* `GotTabLim` will be the same value as `TabLim`. */ + + WasmEdge_TableTypeDelete(TabTypeCxt); + ``` + +4. Memory type context + + The `Memory Type` context is used for `Memory` instance creation or getting information from `Memory` instances. + + ```c + WasmEdge_Limit MemLim = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + WasmEdge_MemoryTypeContext *MemTypeCxt = WasmEdge_MemoryTypeCreate(MemLim); + + WasmEdge_Limit GotMemLim = WasmEdge_MemoryTypeGetLimit(MemTypeCxt); + /* `GotMemLim` will be the same value as `MemLim`. */ + + WasmEdge_MemoryTypeDelete(MemTypeCxt) + ``` + +5. Global type context + + The `Global Type` context is used for `Global` instance creation or getting information from `Global` instances. + + ```c + WasmEdge_GlobalTypeContext *GlobTypeCxt = WasmEdge_GlobalTypeCreate( + WasmEdge_ValTypeGenF64(), WasmEdge_Mutability_Var); + + WasmEdge_ValType GotValType = WasmEdge_GlobalTypeGetValType(GlobTypeCxt); + bool IsTypeF64 = WasmEdge_ValTypeIsF64(GotValType); + /* `IsTypeF64` will be `TRUE`. */ + WasmEdge_Mutability GotValMut = + WasmEdge_GlobalTypeGetMutability(GlobTypeCxt); + /* `GotValMut` will be WasmEdge_Mutability_Var. */ + + WasmEdge_GlobalTypeDelete(GlobTypeCxt); + ``` + +6. Tag type context + + The `Tag Type` context is used for getting information from `Tag` instances. + This will only usable if the `Exception Handling` proposal turned on. + + ```c + /* Get the tag type from a tag instance. */ + const WasmEdge_TagTypeContext *TagTypeCxt = WasmEdge_TagInstanceGetTagType(...); + + const WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_TagTypeGetFunctionType(TagTypeCxt); + ``` + +7. Import type context + + The `Import Type` context is used for getting the imports information from a [AST Module](#ast-module). Developers can get the external type (`function`, `table`, `memory`, `tag`, or `global`), import module name, and external name from an `Import Type` context. The details about querying `Import Type` contexts will be introduced in the [AST Module](#ast-module). + + ```c + WasmEdge_ASTModuleContext *ASTCxt = ...; + /* + * Assume that `ASTCxt` is returned by the `WasmEdge_LoaderContext` for the + * result of loading a WASM file. + */ + const WasmEdge_ImportTypeContext *ImpType = ...; + /* Assume that `ImpType` is queried from the `ASTCxt` for the import. */ + + enum WasmEdge_ExternalType ExtType = + WasmEdge_ImportTypeGetExternalType(ImpType); + /* + * The `ExtType` can be one of `WasmEdge_ExternalType_Function`, + * `WasmEdge_ExternalType_Table`, `WasmEdge_ExternalType_Memory`, + * `WasmEdge_ExternalType_Tag`, or `WasmEdge_ExternalType_Global`. + */ + WasmEdge_String ModName = WasmEdge_ImportTypeGetModuleName(ImpType); + WasmEdge_String ExtName = WasmEdge_ImportTypeGetExternalName(ImpType); + /* + * The `ModName` and `ExtName` should not be destroyed and the string + * buffers are binded into the `ASTCxt`. + */ + const WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_ImportTypeGetFunctionType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Function`, the + * `FuncTypeCxt` will be NULL. + */ + const WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_ImportTypeGetTableType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Table`, the `TabTypeCxt` + * will be NULL. + */ + const WasmEdge_MemoryTypeContext *MemTypeCxt = + WasmEdge_ImportTypeGetMemoryType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Memory`, the `MemTypeCxt` + * will be NULL. + */ + const WasmEdge_TagTypeContext *TagTypeCxt = + WasmEdge_ImportTypeGetTagType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Tag`, the `TagTypeCxt` + * will be NULL. + */ + const WasmEdge_GlobalTypeContext *GlobTypeCxt = + WasmEdge_ImportTypeGetGlobalType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Global`, the `GlobTypeCxt` + * will be NULL. + */ + ``` + +8. Export type context + + The `Export Type` context is used for getting the exports information from a [AST Module](#ast-module). Developers can get the external type (`function`, `table`, `memory`, `tag`, or `global`) and external name from an `Export Type` context. The details about querying `Export Type` contexts will be introduced in the [AST Module](#ast-module). + + ```c + WasmEdge_ASTModuleContext *ASTCxt = ...; + /* + * Assume that `ASTCxt` is returned by the `WasmEdge_LoaderContext` for the + * result of loading a WASM file. + */ + const WasmEdge_ExportTypeContext *ExpType = ...; + /* Assume that `ExpType` is queried from the `ASTCxt` for the export. */ + + enum WasmEdge_ExternalType ExtType = + WasmEdge_ExportTypeGetExternalType(ExpType); + /* + * The `ExtType` can be one of `WasmEdge_ExternalType_Function`, + * `WasmEdge_ExternalType_Table`, `WasmEdge_ExternalType_Memory`, + * `WasmEdge_ExternalType_Tag`, or `WasmEdge_ExternalType_Global`. + */ + WasmEdge_String ExtName = WasmEdge_ExportTypeGetExternalName(ExpType); + /* + * The `ExtName` should not be destroyed and the string buffer is binded + * into the `ASTCxt`. + */ + const WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_ExportTypeGetFunctionType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Function`, the + * `FuncTypeCxt` will be NULL. + */ + const WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_ExportTypeGetTableType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Table`, the `TabTypeCxt` + * will be NULL. + */ + const WasmEdge_MemoryTypeContext *MemTypeCxt = + WasmEdge_ExportTypeGetMemoryType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Memory`, the `MemTypeCxt` + * will be NULL. + */ + const WasmEdge_TagTypeContext *TagTypeCxt = + WasmEdge_ExportTypeGetTagType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Tag`, the `TagTypeCxt` + * will be NULL. + */ + const WasmEdge_GlobalTypeContext *GlobTypeCxt = + WasmEdge_ExportTypeGetGlobalType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Global`, the `GlobTypeCxt` + * will be NULL. + */ + ``` + +### Async + +After calling the [asynchronous execution APIs](#asynchronous-execution), developers will get the `WasmEdge_Async` object. Developers own the object and should call the `WasmEdge_AsyncDelete()` API to destroy it. + +1. Wait for the asynchronous execution + + Developers can wait the execution until finished: + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* Blocking and waiting for the execution. */ + WasmEdge_AsyncWait(Async); + WasmEdge_AsyncDelete(Async); + ``` + + Or developers can wait for a time limit. If the time limit exceeded, developers can choose to cancel the execution. For the interruptible execution in AOT mode, developers should set `TRUE` through the `WasmEdge_ConfigureCompilerSetInterruptible()` API into the configure context for the AOT compiler. + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* Blocking and waiting for the execution for 1 second. */ + bool IsEnd = WasmEdge_AsyncWaitFor(Async, 1000); + if (IsEnd) { + /* The execution finished. Developers can get the result. */ + WasmEdge_Result Res = WasmEdge_AsyncGet(/* ... Ignored */); + } else { + /* + * The time limit exceeded. Developers can keep waiting or cancel the + * execution. + */ + WasmEdge_AsyncCancel(Async); + WasmEdge_Result Res = WasmEdge_AsyncGet(Async, 0, NULL); + /* The result error code will be `WasmEdge_ErrCode_Interrupted`. */ + } + WasmEdge_AsyncDelete(Async); + ``` + +2. Get the execution result of the asynchronous execution + + Developers can use the `WasmEdge_AsyncGetReturnsLength()` API to get the return value list length. This function will block and wait for the execution. If the execution has finished, this function will return the length immediately. If the execution failed, this function will return `0`. This function can help the developers to create the buffer to get the return values. If developers have already known the buffer length, they can skip this function and use the `WasmEdge_AsyncGet()` API to get the result. + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* + * Blocking and waiting for the execution and get the return value list + * length. + */ + uint32_t Arity = WasmEdge_AsyncGetReturnsLength(Async); + WasmEdge_AsyncDelete(Async); + ``` + + The `WasmEdge_AsyncGet()` API will block and wait for the execution. If the execution has finished, this function will fill the return values into the buffer and return the execution result immediately. + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* Blocking and waiting for the execution and get the return values. */ + const uint32_t BUF_LEN = 256; + WasmEdge_Value Buf[BUF_LEN]; + WasmEdge_Result Res = WasmEdge_AsyncGet(Async, Buf, BUF_LEN); + WasmEdge_AsyncDelete(Async); + ``` + +### Configurations + +The configuration context, `WasmEdge_ConfigureContext`, manages the configurations for `Loader`, `Validator`, `Executor`, `VM`, and `Compiler` contexts. Developers can adjust the settings about the proposals, VM host pre-registrations (such as `WASI`), and AOT compiler options, and then apply the `Configure` context to create the runtime contexts. + +1. Proposals + + WasmEdge supports turning on or off the WebAssembly proposals. This configuration is effective in any contexts created with the `Configure` context. + + ```c + enum WasmEdge_Proposal { + WasmEdge_Proposal_ImportExportMutGlobals = 0, + WasmEdge_Proposal_NonTrapFloatToIntConversions, + WasmEdge_Proposal_SignExtensionOperators, + WasmEdge_Proposal_MultiValue, + WasmEdge_Proposal_BulkMemoryOperations, + WasmEdge_Proposal_ReferenceTypes, + WasmEdge_Proposal_SIMD, + WasmEdge_Proposal_TailCall, + WasmEdge_Proposal_ExtendedConst, + WasmEdge_Proposal_FunctionReferences, + WasmEdge_Proposal_GC, + WasmEdge_Proposal_MultiMemories, + WasmEdge_Proposal_Threads, + WasmEdge_Proposal_RelaxSIMD, + WasmEdge_Proposal_Annotations, + WasmEdge_Proposal_Memory64, + WasmEdge_Proposal_ExceptionHandling, + WasmEdge_Proposal_Component, + }; + ``` + + Developers can add or remove the proposals into the `Configure` context. + + ```c + /* + * By default, the following proposals have turned on initially: + * * Import/Export of mutable globals + * * Non-trapping float-to-int conversions + * * Sign-extension operators + * * Multi-value returns + * * Bulk memory operations + * * Reference types + * * Fixed-width SIMD + * + * For the current WasmEdge version, the following proposals are supported + * (turned off by default) additionally: + * * Tail-call + * * Extended-const + * * Typed-function references + * * GC (interpreter only) + * * Multiple memories + * * Relaxed SIMD (`0.14.1` or upper only) + * * Threads + * * Exception handling (interpreter only) + * * Component model (loader phase only) + */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddProposal(ConfCxt, WasmEdge_Proposal_MultiMemories); + WasmEdge_ConfigureRemoveProposal(ConfCxt, WasmEdge_Proposal_ReferenceTypes); + bool IsBulkMem = WasmEdge_ConfigureHasProposal( + ConfCxt, WasmEdge_Proposal_BulkMemoryOperations); + /* The `IsBulkMem` will be `TRUE`. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +2. Host registrations + + This configuration is used for the `VM` context to turn on the `WASI` supports and only effective in `VM` contexts. + + The element of this enum is reserved for the other built-in host functions (such as `wasi-socket`) in the future. + + ```c + enum WasmEdge_HostRegistration { + WasmEdge_HostRegistration_Wasi = 0 + }; + ``` + + The details will be introduced in the [preregistrations of VM context](#built-in-host-modules-and-plug-in-preregistrations). + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + bool IsHostWasi = WasmEdge_ConfigureHasHostRegistration( + ConfCxt, WasmEdge_HostRegistration_Wasi); + /* The `IsHostWasi` will be `FALSE`. */ + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + IsHostWasi = WasmEdge_ConfigureHasHostRegistration( + ConfCxt, WasmEdge_HostRegistration_Wasi); + /* The `IsHostWasi` will be `TRUE`. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +3. Maximum memory pages + + Developers can limit the page size of memory instances by this configuration. When growing the page size of memory instances in WASM execution and exceeding the limited size, the page growing will fail. This configuration is only effective in the `Executor` and `VM` contexts. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + uint32_t PageSize = WasmEdge_ConfigureGetMaxMemoryPage(ConfCxt); + /* By default, the maximum memory page size is 65536. */ + WasmEdge_ConfigureSetMaxMemoryPage(ConfCxt, 1024); + /* + * Limit the memory size of each memory instance with not larger than 1024 + * pages (64 MiB). + */ + PageSize = WasmEdge_ConfigureGetMaxMemoryPage(ConfCxt); + /* The `PageSize` will be 1024. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +4. Forcibly interpreter mode + + If developers want to execute the WASM file or the AOT compiled WASM in interpreter mode forcibly, they can turn on the configuration. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + bool IsForceInterp = WasmEdge_ConfigureIsForceInterpreter(ConfCxt); + /* By default, The `IsForceInterp` will be `FALSE`. */ + WasmEdge_ConfigureSetForceInterpreter(ConfCxt, TRUE); + IsForceInterp = WasmEdge_ConfigureIsForceInterpreter(ConfCxt); + /* The `IsForceInterp` will be `TRUE`. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +5. AOT compiler options + + The AOT compiler options configure the behavior about optimization level, output format, dump IR, and generic binary. + + ```c + enum WasmEdge_CompilerOptimizationLevel { + // Disable as many optimizations as possible. + WasmEdge_CompilerOptimizationLevel_O0 = 0, + // Optimize quickly without destroying debuggability. + WasmEdge_CompilerOptimizationLevel_O1, + // Optimize for fast execution as much as possible without triggering + // significant incremental compile time or code size growth. + WasmEdge_CompilerOptimizationLevel_O2, + // Optimize for fast execution as much as possible. + WasmEdge_CompilerOptimizationLevel_O3, + // Optimize for small code size as much as possible without triggering + // significant incremental compile time or execution time slowdowns. + WasmEdge_CompilerOptimizationLevel_Os, + // Optimize for small code size as much as possible. + WasmEdge_CompilerOptimizationLevel_Oz + }; + + enum WasmEdge_CompilerOutputFormat { + // Native dynamic library format. + WasmEdge_CompilerOutputFormat_Native = 0, + // WebAssembly with AOT compiled codes in custom section. + WasmEdge_CompilerOutputFormat_Wasm + }; + ``` + + These configurations are only effective in `Compiler` contexts. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* By default, the optimization level is O3. */ + WasmEdge_ConfigureCompilerSetOptimizationLevel( + ConfCxt, WasmEdge_CompilerOptimizationLevel_O2); + /* By default, the output format is universal WASM. */ + WasmEdge_ConfigureCompilerSetOutputFormat( + ConfCxt, WasmEdge_CompilerOutputFormat_Native); + /* By default, the dump IR is `FALSE`. */ + WasmEdge_ConfigureCompilerSetDumpIR(ConfCxt, TRUE); + /* By default, the generic binary is `FALSE`. */ + WasmEdge_ConfigureCompilerSetGenericBinary(ConfCxt, TRUE); + /* By default, the interruptible is `FALSE`. + /* Set this option to `TRUE` to support the interruptible execution in AOT + mode. */ + WasmEdge_ConfigureCompilerSetInterruptible(ConfCxt, TRUE); + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +6. Statistics options + + The statistics options configure the behavior about instruction counting, cost measuring, and time measuring in both runtime and AOT compiler. These configurations are effective in `Compiler`, `VM`, and `Executor` contexts. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* + * By default, the instruction counting is `FALSE` when running a + * compiled-WASM or a pure-WASM. + */ + WasmEdge_ConfigureStatisticsSetInstructionCounting(ConfCxt, TRUE); + /* + * By default, the cost measurement is `FALSE` when running a compiled-WASM + * or a pure-WASM. + */ + WasmEdge_ConfigureStatisticsSetCostMeasuring(ConfCxt, TRUE); + /* + * By default, the time measurement is `FALSE` when running a compiled-WASM + * or a pure-WASM. + */ + WasmEdge_ConfigureStatisticsSetTimeMeasuring(ConfCxt, TRUE); + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +### Statistics + +The statistics context, `WasmEdge_StatisticsContext`, provides the instruction counter, cost summation, and cost limitation at runtime. + +Before using statistics, the statistics configuration must be set. Otherwise, the return values of calling statistics are undefined behaviour. + +1. Instruction counter + + The instruction counter can help developers to profile the performance of WASM running. Developers can retrieve the `Statistics` context from the `VM` context, or create a new one for the `Executor` creation. The details will be introduced in the next partitions. + + ```c + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * ... + * After running the WASM functions with the `Statistics` context + */ + uint32_t Count = WasmEdge_StatisticsGetInstrCount(StatCxt); + double IPS = WasmEdge_StatisticsGetInstrPerSecond(StatCxt); + WasmEdge_StatisticsDelete(StatCxt); + ``` + +2. Cost table + + The cost table is to accumulate the cost of instructions with their weights. Developers can set the cost table array (the indices are the byte code value of instructions, and the values are the cost of instructions) into the `Statistics` context. If the cost limit value is set, the execution will return the `cost limit exceeded` error immediately when exceeds the cost limit in runtime. + + ```c + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + uint64_t CostTable[16] = { + 0, 0, + 10, /* 0x02: Block */ + 11, /* 0x03: Loop */ + 12, /* 0x04: If */ + 12, /* 0x05: Else */ + 0, 0, 0, 0, 0, 0, + 20, /* 0x0C: Br */ + 21, /* 0x0D: Br_if */ + 22, /* 0x0E: Br_table */ + 0 + }; + /* + * Developers can set the costs of each instruction. The value not + * covered will be 0. + */ + WasmEdge_StatisticsSetCostTable(StatCxt, CostTable, 16); + WasmEdge_StatisticsSetCostLimit(StatCxt, 5000000); + /* + * ... + * After running the WASM functions with the `Statistics` context + */ + uint64_t Cost = WasmEdge_StatisticsGetTotalCost(StatCxt); + WasmEdge_StatisticsDelete(StatCxt); + ``` + +## WasmEdge VM + +In this partition, we will introduce the functions of `WasmEdge_VMContext` object and show examples of executing WASM functions. + +### WASM Execution Example With VM Context + +The following shows the example of running the WASM for getting the Fibonacci. This example uses the [fibonacci.wat](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat). + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```wasm +(module + (export "fib" (func $fib)) + (func $fib (param $n i32) (result i32) + (if + (i32.lt_s (get_local $n)(i32.const 2)) + (return (i32.const 1)) + ) + (return + (i32.add + (call $fib (i32.sub (get_local $n)(i32.const 2))) + (call $fib (i32.sub (get_local $n)(i32.const 1))) + ) + ) + ) +) +``` + +1. Run WASM functions rapidly + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + #include + #include + int main() { + /* Create the configure context and add the WASI support. */ + /* This step is not necessary unless you need WASI support. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + /* The configure and store context to the VM creation can be NULL. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(5)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Run the WASM function from file. */ + WasmEdge_Result Res = WasmEdge_VMRunWasmFromFile( + VMCxt, "fibonacci.wasm", FuncName, Params, 1, Returns, 1); + /* + * Developers can run the WASM binary from buffer with the + * `WasmEdge_VMRunWasmFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMRunWasmFromASTModule()` API. + */ + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_ConfigureDelete(ConfCxt); + WasmEdge_StringDelete(FuncName); + return 0; + } + ``` + + Then you can compile and run: (the 5th Fibonacci number is 8 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 8 + ``` + +2. Instantiate and run WASM functions manually + + Besides the above example, developers can run the WASM functions step-by-step with `VM` context APIs: + + ```c + #include + #include + int main() { + /* Create the configure context and add the WASI support. */ + /* This step is not necessary unless you need the WASI support. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + /* The configure and store context to the VM creation can be NULL. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(10)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Step 1: Load WASM file. */ + Res = WasmEdge_VMLoadWasmFromFile(VMCxt, "fibonacci.wasm"); + /* + * Developers can load the WASM binary from buffer with the + * `WasmEdge_VMLoadWasmFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMLoadWasmFromASTModule()` API. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 2: Validate the WASM module. */ + Res = WasmEdge_VMValidate(VMCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 3: Instantiate the WASM module. */ + Res = WasmEdge_VMInstantiate(VMCxt); + /* + * Developers can load, validate, and instantiate another WASM module to + * replace the instantiated one. In this case, the old module will be + * cleared, but the registered modules are still kept. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Instantiation phase failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * Step 4: Execute WASM functions. You can execute functions repeatedly + * after instantiation. + */ + Res = WasmEdge_VMExecute(VMCxt, FuncName, Params, 1, Returns, 1); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_ConfigureDelete(ConfCxt); + WasmEdge_StringDelete(FuncName); + return 0; + } + ``` + + Then you can compile and run: (the 10th Fibonacci number is 89 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 89 + ``` + + The following graph explains the status of the `VM` context. + + ```text + |========================| + |------->| VM: Initiated | + | |========================| + | | + | LoadWasm + | | + | v + | |========================| + |--------| VM: Loaded |<-------| + | |========================| | + | | ^ | + | Validate | | + Cleanup | LoadWasm | + | v | LoadWasm + | |========================| | + |--------| VM: Validated | | + | |========================| | + | | ^ | + | Instantiate | | + | | RegisterModule | + | v | | + | |========================| | + |--------| VM: Instantiated |--------| + |========================| + | ^ + | | + -------------- + Instantiate, Execute, ExecuteRegistered + ``` + + The status of the `VM` context would be `Inited` when created. After loading WASM successfully, the status will be `Loaded`. After validating WASM successfully, the status will be `Validated`. After instantiating WASM successfully, the status will be `Instantiated`, and developers can invoke functions. Developers can register WASM or module instances in any status, but they should instantiate WASM again. Developers can also load WASM in any status, and they should validate and instantiate the WASM module before function invocation. When in the `Instantiated` status, developers can instantiate the WASM module again to reset the old WASM runtime structures. + +### VM Creations + +The `VM` creation API accepts the `Configure` context and the `Store` context. If developers only need the default settings, just pass `NULL` to the creation API. The details of the `Store` context will be introduced in [Store](#store). + +```c +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); +WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); +WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, StoreCxt); +/* The caller should guarantee the life cycle if the store context. */ +WasmEdge_StatisticsContext *StatCxt = WasmEdge_VMGetStatisticsContext(VMCxt); +/* + * The VM context already contains the statistics context and can be retrieved + * by this API. + */ +/* + * Note that the retrieved store and statistics contexts from the VM contexts by + * VM APIs should __NOT__ be destroyed and owned by the VM contexts. + */ +WasmEdge_VMDelete(VMCxt); +WasmEdge_StoreDelete(StoreCxt); +WasmEdge_ConfigureDelete(ConfCxt); +``` + +### Built-in Host Modules and Plug-in Preregistrations + +WasmEdge provides the following built-in host modules and plug-in pre-registrations. + +1. [WASI (WebAssembly System Interface)](https://github.com/WebAssembly/WASI) + + Developers can turn on the WASI support for VM in the `Configure` context. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + WasmEdge_ConfigureDelete(ConfCxt); + /* + * The following API can retrieve the built-in registered module instances + * from the VM context. + */ + /* + * This API will return `NULL` if the corresponding configuration is not set + * when creating the VM context. + */ + WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_VMGetImportModuleContext(VMCxt, + WasmEdge_HostRegistration_Wasi); + /* Initialize the WASI. */ + WasmEdge_ModuleInstanceInitWASI(WasiModule, /* ... ignored */); + WasmEdge_VMDelete(VMCxt); + ``` + + And also can create the WASI module instance from API. The details will be introduced in the [Host Functions](#host-functions) and the [Host Module Registrations](#host-module-registrations). + +2. Plug-ins + + There may be several plug-ins in the default plug-in paths if users [installed WasmEdge plug-ins by the installer](../../../start/install.md#install-wasmedge-plug-ins-and-dependencies). + + Before using the plug-ins, developers should [load the plug-ins from paths](#load-plug-ins-from-paths). + + The `VM` context will automatically create and register the module of the loaded plug-ins when creation. Furthermore, the following host modules will be mocked if the plug-in not loaded: + + - `wasi_ephemeral_crypto_asymmetric_common` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_common` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_kx` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_signatures` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_symmetric` (for the `WASI-Crypto`) + - `wasi_ephemeral_nn` + - `wasi_snapshot_preview1` + - `wasmedge_httpsreq` + - `wasmedge_process` + + When the WASM want to invoke these host functions but the corresponding plug-in not installed, WasmEdge will print the error message and return an error. + + ```c + /* Load the plug-ins in the default paths first. */ + WasmEdge_PluginLoadWithDefaultPaths(); + /* Create the configure context and add the WASI configuration. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + WasmEdge_ConfigureDelete(ConfCxt); + /* + * The following API can retrieve the registered modules in the VM context, + * includes the built-in WASI and the plug-ins. + */ + /* + * This API will return `NULL` if the module instance not found. + */ + WasmEdge_String WasiName = + WasmEdge_StringCreateByCString("wasi_snapshot_preview1"); + /* The `WasiModule` will not be `NULL` because the configuration was set. */ + const WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_VMGetRegisteredModule(VMCxt, WasiName); + WasmEdge_StringDelete(WasiName); + WasmEdge_String WasiNNName = + WasmEdge_StringCreateByCString("wasi_ephemeral_nn"); + /* + * The `WasiNNModule` will not be `NULL` even if the wasi_nn plug-in is not + * installed, because the VM context will mock and register the host + * modules. + */ + const WasmEdge_ModuleInstanceContext *WasiNNModule = + WasmEdge_VMGetRegisteredModule(VMCxt, WasiNNName); + WasmEdge_StringDelete(WasiNNName); + + WasmEdge_VMDelete(VMCxt); + ``` + +### Host Module Registrations + +[Host functions](https://webassembly.github.io/spec/core/exec/runtime.html#syntax-hostfunc) are functions outside WebAssembly and passed to WASM modules as imports. In WasmEdge, the host functions are composed into host modules as `WasmEdge_ModuleInstanceContext` objects with module names. Please refer to the [Host Functions in WasmEdge Runtime](#host-functions) for the details. + +In this chapter, we show the example for registering the host modules into a `VM` context. Noticed that the developers should guarantee the availability of the registered module instance, and should delete the module instance when it will not be used. + +```c +WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); +WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_ModuleInstanceCreateWASI(/* ... ignored ... */); +/* You can also create and register the WASI host modules by this API. */ +WasmEdge_Result Res = WasmEdge_VMRegisterModuleFromImport(VMCxt, WasiModule); +/* The result status should be checked. */ + +/* ... */ + +WasmEdge_VMDelete(VMCxt); +WasmEdge_ModuleInstanceDelete(WasiModule); +/* + * The created module instances should be deleted by the developers when the VM + * deallocation. + */ +``` + +### WASM Registrations And Executions + +In WebAssembly, the instances in WASM modules can be exported and can be imported by other WASM modules. WasmEdge VM provides APIs for developers to register and export any WASM modules, and execute the functions or host functions in the registered WASM modules. + +1. Register the WASM modules with exported module names + + Unless the module instances have already contained the module names, every WASM module should be named uniquely when registering. + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_Result Res = + WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + /* + * Developers can register the WASM module from buffer with the + * `WasmEdge_VMRegisterModuleFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMRegisterModuleFromASTModule()` API. + */ + /* + * The result status should be checked. + * The error will occur if the WASM module instantiation failed or the + * module name conflicts. + */ + WasmEdge_StringDelete(ModName); + WasmEdge_VMDelete(VMCxt); + ``` + +2. Execute the functions in registered WASM modules + + Assume that the C file `test.c` is as follows: + + ```c + #include + #include + int main() { + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(20)}; + WasmEdge_Value Returns[1]; + /* Names. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Register the WASM module into VM. */ + Res = WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + /* + * Developers can register the WASM module from buffer with the + * `WasmEdge_VMRegisterModuleFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMRegisterModuleFromASTModule()` API. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * The function "fib" in the "fibonacci.wasm" was exported with the module + * name "mod". As the same as host functions, other modules can import the + * function `"mod" "fib"`. + */ + + /* + * Execute WASM functions in registered modules. + * Unlike the execution of functions, the registered functions can be + * invoked without `WasmEdge_VMInstantiate()` because the WASM module was + * instantiated when registering. Developers can also invoke the host + * functions directly with this API. + */ + Res = WasmEdge_VMExecuteRegistered(VMCxt, ModName, FuncName, Params, 1, + Returns, 1); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + WasmEdge_StringDelete(ModName); + WasmEdge_StringDelete(FuncName); + WasmEdge_VMDelete(VMCxt); + return 0; + } + ``` + + Then you can compile and run: (the 20th Fibonacci number is 89 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 10946 + ``` + +### Asynchronous Execution + +1. Asynchronously run WASM functions rapidly + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + #include + #include + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(20)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Asynchronously run the WASM function from file and get the + * `WasmEdge_Async` object. */ + WasmEdge_Async *Async = WasmEdge_VMAsyncRunWasmFromFile( + VMCxt, "fibonacci.wasm", FuncName, Params, 1); + /* + * Developers can run the WASM binary from buffer with the + * `WasmEdge_VMAsyncRunWasmFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMAsyncRunWasmFromASTModule()` API. + */ + + /* Wait for the execution. */ + WasmEdge_AsyncWait(Async); + /* + * Developers can also use the `WasmEdge_AsyncGetReturnsLength()` or + * `WasmEdge_AsyncGet()` APIs to wait for the asynchronous execution. + * These APIs will wait until the execution finished. + */ + + /* Check the return values length. */ + uint32_t Arity = WasmEdge_AsyncGetReturnsLength(Async); + /* The `Arity` should be 1. Developers can skip this step if they have + * known the return arity. */ + + /* Get the result. */ + WasmEdge_Result Res = WasmEdge_AsyncGet(Async, Returns, Arity); + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_AsyncDelete(Async); + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + return 0; + } + ``` + + Then you can compile and run: (the 20th Fibonacci number is 10946 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 10946 + ``` + +2. Instantiate and asynchronously run WASM functions manually + + Besides the above example, developers can run the WASM functions step-by-step with `VM` context APIs: + + ```c + #include + #include + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(25)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Step 1: Load WASM file. */ + Res = WasmEdge_VMLoadWasmFromFile(VMCxt, "fibonacci.wasm"); + /* + * Developers can load the WASM binary from buffer with the + * `WasmEdge_VMLoadWasmFromBytes()` API, or from `WasmEdge_ASTModuleContext` + * object with the `WasmEdge_VMLoadWasmFromASTModule()` API. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 2: Validate the WASM module. */ + Res = WasmEdge_VMValidate(VMCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 3: Instantiate the WASM module. */ + Res = WasmEdge_VMInstantiate(VMCxt); + /* + * Developers can load, validate, and instantiate another WASM module to + * replace the instantiated one. In this case, the old module will be + * cleared, but the registered modules are still kept. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Instantiation phase failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 4: Asynchronously execute the WASM function and get the + * `WasmEdge_Async` object. */ + WasmEdge_Async *Async = + WasmEdge_VMAsyncExecute(VMCxt, FuncName, Params, 1); + /* + * Developers can execute functions repeatedly after instantiation. + * For invoking the registered functions, you can use the + * `WasmEdge_VMAsyncExecuteRegistered()` API. + */ + + /* Wait and check the return values length. */ + uint32_t Arity = WasmEdge_AsyncGetReturnsLength(Async); + /* The `Arity` should be 1. Developers can skip this step if they have + * known the return arity. */ + + /* Get the result. */ + Res = WasmEdge_AsyncGet(Async, Returns, Arity); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_AsyncDelete(Async); + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + } + ``` + + Then you can compile and run: (the 25th Fibonacci number is 121393 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 121393 + ``` + +### Instance Tracing + +Sometimes the developers may have requirements to get the instances of the WASM runtime. The `VM` context supplies the APIs to retrieve the instances. + +1. Store + + If the `VM` context is created without assigning a `Store` context, the `VM` context will allocate and own a `Store` context. + + ```c + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + WasmEdge_StoreContext *StoreCxt = WasmEdge_VMGetStoreContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_StoreDelete()`. */ + WasmEdge_VMDelete(VMCxt); + ``` + + Developers can also create the `VM` context with a `Store` context. In this case, developers should guarantee the life cycle of the `Store` context. Please refer to the [Store Contexts](#store) for the details about the `Store` context APIs. + + ```c + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, StoreCxt); + WasmEdge_StoreContext *StoreCxtMock = WasmEdge_VMGetStoreContext(VMCxt); + /* The `StoreCxt` and the `StoreCxtMock` are the same. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StoreDelete(StoreCxt); + ``` + +2. List exported functions + + After the WASM module instantiation, developers can use the `WasmEdge_VMExecute()` API to invoke the exported WASM functions. For this purpose, developers may need information about the exported WASM function list. Please refer to the [Instances in runtime](#instances) for the details about the function types. + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + #include + #include + int main() { + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, StoreCxt); + + WasmEdge_VMLoadWasmFromFile(VMCxt, "fibonacci.wasm"); + WasmEdge_VMValidate(VMCxt); + WasmEdge_VMInstantiate(VMCxt); + + /* List the exported functions. */ + /* Get the number of exported functions. */ + uint32_t FuncNum = WasmEdge_VMGetFunctionListLength(VMCxt); + /* Create the name buffers and the function type buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String FuncNames[BUF_LEN]; + WasmEdge_FunctionTypeContext *FuncTypes[BUF_LEN]; + /* + * Get the export function list. + * If the function list length is larger than the buffer length, the + * overflowed data will be discarded. The `FuncNames` and `FuncTypes` can + * be NULL if developers don't need them. + */ + uint32_t RealFuncNum = + WasmEdge_VMGetFunctionList(VMCxt, FuncNames, FuncTypes, BUF_LEN); + + for (uint32_t I = 0; I < RealFuncNum && I < BUF_LEN; I++) { + char Buf[BUF_LEN]; + uint32_t Size = WasmEdge_StringCopy(FuncNames[I], Buf, sizeof(Buf)); + printf("Get exported function string length: %u, name: %s\n", Size, + Buf); + /* + * The function names should be __NOT__ destroyed. + * The returned function type contexts should __NOT__ be destroyed. + */ + } + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_VMDelete(VMCxt); + return 0; + } + ``` + + Then you can compile and run: (the only exported function in `fibonacci.wasm` is `fib`) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get exported function string length: 3, name: fib + ``` + + If developers want to get the exported function names in the registered WASM modules, please retrieve the `Store` context from the `VM` context and refer to the APIs of [Store Contexts](#store) to list the registered functions by the module name. + +3. Get function types + + The `VM` context provides APIs to find the function type by function name. Please refer to the [Instances in runtime](#instances) for the details about the function types. + + ```c + /* + * ... + * Assume that a WASM module is instantiated in `VMCxt`. + */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + const WasmEdge_FunctionTypeContext *FuncType = + WasmEdge_VMGetFunctionType(VMCxt, FuncName); + /* + * Developers can get the function types of functions in the registered + * modules via the `WasmEdge_VMGetFunctionTypeRegistered()` API with the + * module name. If the function is not found, these APIs will return `NULL`. + * The returned function type contexts should __NOT__ be destroyed. + */ + WasmEdge_StringDelete(FuncName); + ``` + +4. Get the active module + + After the WASM module instantiation, an anonymous module is instantiated and owned by the `VM` context. Developers may need to retrieve it to get the instances beyond the module. Then developers can use the `WasmEdge_VMGetActiveModule()` API to get that anonymous module instance. Please refer to the [Module instance](#instances) for the details about the module instance APIs. + + ```c + /* + * ... + * Assume that a WASM module is instantiated in `VMCxt`. + */ + const WasmEdge_ModuleInstanceContext *ModCxt = + WasmEdge_VMGetActiveModule(VMCxt); + /* + * If there's no WASM module instantiated, this API will return `NULL`. + * The returned module instance context should __NOT__ be destroyed. + */ + ``` + +5. List and get the registered modules + + To list and retrieve the registered modules in the `VM` context, besides accessing the `store` context of the `VM`, developers can use the following APIs. + + ```c + /* + * ... + * Assume that the `VMCxt` is created. + */ + WasmEdge_String Names[32]; + uint32_t ModuleLen = WasmEdge_VMListRegisteredModule(VMCxt, Names, 32); + for (uint32_t I = 0; I < ModuleLen; I++) { + /* Will print the registered module names in the VM context. */ + printf("%s\n", Names[I].Buf); + } + + WasmEdge_String WasiName = + WasmEdge_StringCreateByCString("wasi_snapshot_preview1"); + /* The `WasiModule` will not be `NULL` because the configuration was set. */ + const WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_VMGetRegisteredModule(VMCxt, WasiName); + WasmEdge_StringDelete(WasiName); + ``` + +6. Get the components + + The `VM` context is composed by the `Loader`, `Validator`, and `Executor` contexts. For the developers who want to use these contexts without creating another instances, these APIs can help developers to get them from the `VM` context. The get contexts are owned by the `VM` context, and developers should not call their delete functions. + + ```c + WasmEdge_LoaderContext *LoadCxt = WasmEdge_VMGetLoaderContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_LoaderDelete()`. */ + WasmEdge_ValidatorContext *ValidCxt = WasmEdge_VMGetValidatorContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_ValidatorDelete()`. */ + WasmEdge_ExecutorContext *ExecCxt = WasmEdge_VMGetExecutorContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_ExecutorDelete()`. */ + ``` + +## WasmEdge Runtime + +In this partition, we will introduce the objects of WasmEdge runtime manually. + +### WASM Execution Example Step-By-Step + +Besides the WASM execution through the [`VM` context](#wasmedge-vm), developers can execute the WASM functions or instantiate WASM modules step-by-step with the `Loader`, `Validator`, `Executor`, and `Store` contexts. + +Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```c +#include +#include +int main() { + /* + * Create the configure context. This step is not necessary because we didn't + * adjust any setting. + */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* + * Create the statistics context. This step is not necessary if the statistics + * in runtime is not needed. + */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + /* Result. */ + WasmEdge_Result Res; + + /* Create the loader context. The configure context can be NULL. */ + WasmEdge_LoaderContext *LoadCxt = WasmEdge_LoaderCreate(ConfCxt); + /* Create the validator context. The configure context can be NULL. */ + WasmEdge_ValidatorContext *ValidCxt = WasmEdge_ValidatorCreate(ConfCxt); + /* + * Create the executor context. The configure context and the statistics + * context can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + + /* + * Load the WASM file or the compiled-WASM file and convert into the AST + * module context. + */ + WasmEdge_ASTModuleContext *ASTCxt = NULL; + Res = WasmEdge_LoaderParseFromFile(LoadCxt, &ASTCxt, "fibonacci.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Validate the WASM module. */ + Res = WasmEdge_ValidatorValidate(ValidCxt, ASTCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Instantiate the WASM module into store context. */ + WasmEdge_ModuleInstanceContext *ModCxt = NULL; + Res = WasmEdge_ExecutorInstantiate(ExecCxt, &ModCxt, StoreCxt, ASTCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Instantiation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + + /* Try to list the exported functions of the instantiated WASM module. */ + uint32_t FuncNum = WasmEdge_ModuleInstanceListFunctionLength(ModCxt); + /* Create the name buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String FuncNames[BUF_LEN]; + /* + * If the list length is larger than the buffer length, the overflowed data + * will be discarded. + */ + uint32_t RealFuncNum = + WasmEdge_ModuleInstanceListFunction(ModCxt, FuncNames, BUF_LEN); + for (uint32_t I = 0; I < RealFuncNum && I < BUF_LEN; I++) { + char Buf[BUF_LEN]; + uint32_t Size = WasmEdge_StringCopy(FuncNames[I], Buf, sizeof(Buf)); + printf("Get exported function string length: %u, name: %s\n", Size, Buf); + /* The function names should __NOT__ be destroyed. */ + } + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(18)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Find the exported function by function name. */ + WasmEdge_FunctionInstanceContext *FuncCxt = + WasmEdge_ModuleInstanceFindFunction(ModCxt, FuncName); + if (FuncCxt == NULL) { + printf("Function `fib` not found.\n"); + return 1; + } + /* Invoke the WASM function. */ + Res = WasmEdge_ExecutorInvoke(ExecCxt, FuncCxt, Params, 1, Returns, 1); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_StringDelete(FuncName); + WasmEdge_ASTModuleDelete(ASTCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + WasmEdge_LoaderDelete(LoadCxt); + WasmEdge_ValidatorDelete(ValidCxt); + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_ConfigureDelete(ConfCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_StatisticsDelete(StatCxt); + return 0; +} +``` + +Then you can compile and run: (the 18th Fibonacci number is 4181 in 0-based index) + +```bash +$ gcc test.c -lwasmedge +$ ./a.out +Get exported function string length: 3, name: fib +Get the result: 4181 +``` + +### Loader + +The `Loader` context loads the WASM binary from files or buffers. Both the WASM and the compiled-WASM from the [WasmEdge AOT Compiler](#wasmedge-aot-compiler) are supported. + +```c +uint8_t Buf[4096]; +/* ... Read the WASM code to the buffer. */ +uint32_t FileSize = ...; +/* The `FileSize` is the length of the WASM code. */ + +/* Developers can adjust settings in the configure context. */ +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); +/* Create the loader context. The configure context can be NULL. */ +WasmEdge_LoaderContext *LoadCxt = WasmEdge_LoaderCreate(ConfCxt); + +WasmEdge_ASTModuleContext *ASTCxt = NULL; +WasmEdge_Result Res; + +/* Load WASM or compiled-WASM from the file. */ +Res = WasmEdge_LoaderParseFromFile(LoadCxt, &ASTCxt, "fibonacci.wasm"); +if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} +/* The output AST module context should be destroyed. */ +WasmEdge_ASTModuleDelete(ASTCxt); + +/* Load WASM or compiled-WASM from the buffer. */ +WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(Buf, FileSize); +Res = WasmEdge_LoaderParseFromBytes(LoadCxt, &ASTCxt, Bytes); +/* + * Note: `WasmEdge_LoaderParseFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_LoaderParseFromBytes()` instead. + */ +if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} +/* The output AST module context should be destroyed. */ +WasmEdge_ASTModuleDelete(ASTCxt); + +WasmEdge_LoaderDelete(LoadCxt); +WasmEdge_ConfigureDelete(ConfCxt); +``` + +### Validator + +The `Validator` context can validate the WASM module. Every WASM module should be validated before instantiation. + +```c +/* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context. + * Assume that the `ConfCxt` is the configure context. + */ +/* Create the validator context. The configure context can be NULL. */ +WasmEdge_ValidatorContext *ValidCxt = WasmEdge_ValidatorCreate(ConfCxt); +WasmEdge_Result Res = WasmEdge_ValidatorValidate(ValidCxt, ASTCxt); +if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} +WasmEdge_ValidatorDelete(ValidCxt); +``` + +### Executor + +The `Executor` context is the executor for both WASM and compiled-WASM. This object should work base on the `Store` context. For the details of the `Store` context, please refer to the [next chapter](#store). + +1. Instantiate and register an `AST module` as a named `Module` instance + + As the same of [registering host modules](#host-module-registrations) or [importing WASM modules](#wasm-registrations-and-executions) in `VM` contexts, developers can instantiate an `AST module` contexts into a named `Module` instance, and register it into the `Store` context. After the registration, the result `Module` instance is exported to the `Store` with the given module name and can be linked when instantiating another module. + + For the details about the `Module` instances APIs, please refer to the [Instances](#instances). The `Store` context is only the linker for searching and linking the exported modules when instantiation. Developers should delete the output `Module` instance when it will no longer be used. When the `Module` instance being deleted, it will automatically unlink to all linked `Store` contexts. + + ```c + /* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context and has passed the validation. Assume that the `ConfCxt` is the + * configure context. + */ + /* Create the statistics context. This step is not necessary. */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the executor context. The configure and the statistics contexts + * can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = + WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + /* Result. */ + WasmEdge_Result Res; + + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + /* The output module instance. */ + WasmEdge_ModuleInstanceContext *ModCxt = NULL; + /* + * Register the WASM module into the store with the export module name + * "mod". + */ + Res = + WasmEdge_ExecutorRegister(ExecCxt, &ModCxt, StoreCxt, ASTCxt, ModName); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return -1; + } + WasmEdge_StringDelete(ModName); + + /* ... */ + + /* After the execution, the resources should be released. */ + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_StatisticsDelete(StatCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + ``` + +2. Register an existing `Module` instance and export the module name + + Besides instantiating and registering an `AST module` contexts, developers can register an existing `Module` instance into the store with exporting the module name (which is in the `Module` instance already). This case occurs when developers create a `Module` instance for the host functions and want to register it for linking. For the details about the construction of host functions in `Module` instances, please refer to the [Host Functions](#host-functions). + + ```c + /* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context and has passed the validation. Assume that the `ConfCxt` is the + * configure context. + */ + /* Create the statistics context. This step is not necessary. */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the executor context. The configure and the statistics contexts + * can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = + WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + /* Result. */ + WasmEdge_Result Res; + + /* Create a module instance for host functions. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("host-module"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ModName); + WasmEdge_StringDelete(ModName); + /* + * ... + * Create and add the host functions, tables, memories, and globals into the + * module instance. + */ + + /* Register the module instance into store with the exported module name. */ + /* The export module name is in the module instance already. */ + Res = WasmEdge_ExecutorRegisterImport(ExecCxt, StoreCxt, HostModCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return -1; + } + + /* ... */ + + /* After the execution, the resources should be released. */ + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_StatisticsDelete(StatCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + ``` + +3. Instantiate an `AST module` to an anonymous `Module` instance + + WASM or compiled-WASM modules should be instantiated before the function invocation. Before instantiating a WASM module, please check the [import section](https://webassembly.github.io/spec/core/syntax/modules.html#syntax-import) for ensuring the imports are registered into the `Store` context for linking. + + ```c + /* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context and has passed the validation. Assume that the `ConfCxt` is the + * configure context. + */ + /* Create the statistics context. This step is not necessary. */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the executor context. The configure and the statistics contexts + * can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = + WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + + /* The output module instance. */ + WasmEdge_ModuleInstanceContext *ModCxt = NULL; + /* Instantiate the WASM module. */ + WasmEdge_Result Res = + WasmEdge_ExecutorInstantiate(ExecCxt, &ModCxt, StoreCxt, ASTCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM instantiation failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return -1; + } + + /* ... */ + + /* After the execution, the resources should be released. */ + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_StatisticsDelete(StatCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + ``` + +4. Invoke functions + + After registering or instantiating and get the result `Module` instance, developers can retrieve the exported `Function` instances from the `Module` instance for invocation. For the details about the `Module` instances APIs, please refer to the [Instances](#instances). Please refer to the [example above](#wasm-execution-example-step-by-step) for the `Function` instance invocation with the `WasmEdge_ExecutorInvoke()` API. + +5. Asynchronously invoke functions + + Such as [executing WASM functions in VM asynchronously](#asynchronous-execution), developers can also invoke a function asynchronously by `Executor` contexts API. + + After getting the `Function` instance, developers will get the `Async` context by calling the `WasmEdge_ExecutorAsyncInvoke()` API. Please refer to the [Async](#async) chapter to work with this context for getting the results. + +### AST Module + +The `AST Module` context presents the loaded structure from a WASM file or buffer. Developer will get this object after loading a WASM file or buffer from [Loader](#loader). Before instantiation, developers can also query the imports and exports of an `AST Module` context. + +```c +WasmEdge_ASTModuleContext *ASTCxt = ...; +/* Assume that a WASM is loaded into an AST module context. */ + +/* Create the import type context buffers. */ +const uint32_t BUF_LEN = 256; +const WasmEdge_ImportTypeContext *ImpTypes[BUF_LEN]; +uint32_t ImportNum = WasmEdge_ASTModuleListImportsLength(ASTCxt); +/* + * If the list length is larger than the buffer length, the overflowed data will + * be discarded. + */ +uint32_t RealImportNum = + WasmEdge_ASTModuleListImports(ASTCxt, ImpTypes, BUF_LEN); +for (uint32_t I = 0; I < RealImportNum && I < BUF_LEN; I++) { + /* Working with the import type `ImpTypes[I]` ... */ +} + +/* Create the export type context buffers. */ +const WasmEdge_ExportTypeContext *ExpTypes[BUF_LEN]; +uint32_t ExportNum = WasmEdge_ASTModuleListExportsLength(ASTCxt); +/* + * If the list length is larger than the buffer length, the overflowed data will + * be discarded. + */ +uint32_t RealExportNum = + WasmEdge_ASTModuleListExports(ASTCxt, ExpTypes, BUF_LEN); +for (uint32_t I = 0; I < RealExportNum && I < BUF_LEN; I++) { + /* Working with the export type `ExpTypes[I]` ... */ +} + +WasmEdge_ASTModuleDelete(ASTCxt); +/* + * After deletion of `ASTCxt`, all data queried from the `ASTCxt` should not be + * accessed. + */ +``` + +### Serializer + +As the reversion of loading WASM file or buffer into a `AST Module`, the `Loader` context also provide the serializer to serialze the `AST Module` back into a WASM buffer. + +```c +WasmEdge_ASTModuleContext *ASTCxt = ...; +/* Assume that a WASM is loaded into an AST module context. */ + +WasmEdge_LoaderContext *LoadCxt = ...; +/* Assume that a loader context is created with configuration. */ + +WasmEdbe_Bytes Bytes; +/* Serialize the AST module back into WASM binary format. */ +Res = WasmEdge_LoaderSerializeASTModule(LoadCxt, ASTCxt, &Bytes); +if (!WasmEdge_ResultOK(Res)) { + printf("Serialization failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} + +/* The output WasmEdge_Bytes should be destroyed. */ +WasmEdge_BytesDelete(Bytes); +``` + +### Store + +[Store](https://webassembly.github.io/spec/core/exec/runtime.html#store) is the runtime structure for the representation of all global state that can be manipulated by WebAssembly programs. The `Store` context in WasmEdge is an object which present the linker to provide the instance exporting and importing when instantiating WASM modules. Developers can retrieve the named modules from the `Store` context, and should delete the `Module` instances registered into the `Store` context if they will not be used anymore. + +When the `Store` context being deleted, the linked `Module` instances will automatically unlink to this `Store` context. When a `Module` instance being deleted, it will automatically unlink to all the linked `Store` contexts. + +```c +WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + +/* + * ... + * Register a WASM module via the executor context. + */ + +/* Try to list the registered WASM modules. */ +uint32_t ModNum = WasmEdge_StoreListModuleLength(StoreCxt); +/* Create the name buffers. */ +const uint32_t BUF_LEN = 256; +WasmEdge_String ModNames[BUF_LEN]; +/* + * If the list length is larger than the buffer length, the overflowed data will + * be discarded. + */ +uint32_t RealModNum = WasmEdge_StoreListModule(StoreCxt, ModNames, BUF_LEN); +for (uint32_t I = 0; I < RealModNum && I < BUF_LEN; I++) { + /* Working with the module name `ModNames[I]` ... */ + /* The module names should __NOT__ be destroyed. */ +} + +/* Find named module by name. */ +WasmEdge_String ModName = WasmEdge_StringCreateByCString("module"); +const WasmEdge_ModuleInstanceContext *ModCxt = + WasmEdge_StoreFindModule(StoreCxt, ModName); +/* If the module with name not found, the `ModCxt` will be NULL. */ +WasmEdge_StringDelete(ModName); +``` + +### Instances + +The instances are the runtime structures of WASM. Developers can retrieve the `Module` instances from the `Store` contexts, and retrieve the other instances from the `Module` instances. A single instance can be allocated by its creation function. Developers can construct instances into an `Module` instance for registration. Please refer to the [Host Functions](#host-functions) for details. The instances created by their creation functions should be destroyed by developers, EXCEPT they are added into an `Module` instance. + +1. Module instance + + After instantiating or registering an `AST module` context, developers will get a `Module` instance as the result, and have the responsibility to destroy it when not in use. A `Module` instance can also be created for the host module. Please refer to the [host function](#host-functions) for the details. `Module` instance provides APIs to list and find the exported instances in the module. + + ```c + /* + * ... + * Instantiate a WASM module via the executor context and get the `ModCxt` + * as the output module instance. + */ + + /* Try to list the exported instance of the instantiated WASM module. */ + /* Take the function instances for example here. */ + uint32_t FuncNum = WasmEdge_ModuleInstanceListFunctionLength(ModCxt); + /* Create the name buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String FuncNames[BUF_LEN]; + /* + * If the list length is larger than the buffer length, the overflowed data + * will be discarded. + */ + uint32_t RealFuncNum = + WasmEdge_ModuleInstanceListFunction(ModCxt, FuncNames, BUF_LEN); + for (uint32_t I = 0; I < RealFuncNum && I < BUF_LEN; I++) { + /* Working with the function name `FuncNames[I]` ... */ + /* The function names should __NOT__ be destroyed. */ + } + + /* Try to find the exported instance of the instantiated WASM module. */ + /* Take the function instances for example here. */ + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + WasmEdge_FunctionInstanceContext *FuncCxt = + WasmEdge_ModuleInstanceFindFunction(ModCxt, FuncName); + /* `FuncCxt` will be `NULL` if the function not found. */ + /* + * The returned instance is owned by the module instance context and should + * __NOT__ be destroyed. + */ + WasmEdge_StringDelete(FuncName); + ``` + +2. Function instance + + [Host functions](https://webassembly.github.io/spec/core/exec/runtime.html#syntax-hostfunc) are functions outside WebAssembly and passed to WASM modules as imports. In WasmEdge, developers can create the `Function` contexts for host functions and add them into an `Module` instance context for registering into a `VM` or a `Store`. Developers can retrieve the `Function Type` from the `Function` contexts through the API. For the details of the `Host Function` guide, please refer to the [next chapter](#host-functions). + + ```c + /* Retrieve the function instance from the module instance context. */ + WasmEdge_FunctionInstanceContext *FuncCxt = ...; + WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_FunctionInstanceGetFunctionType(FuncCxt); + /* + * The `FuncTypeCxt` is owned by the `FuncCxt` and should __NOT__ be + * destroyed. + */ + + /* + * For the function instance creation, please refer to the `Host Function` + * guide. + */ + ``` + +3. Table instance + + In WasmEdge, developers can create the `Table` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. The `Table` contexts supply APIs to control the data in table instances. + + ```c + WasmEdge_Limit TabLimit = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + /* Create the table type with limit and the `FuncRef` element type. */ + WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_TableTypeCreate(WasmEdge_ValTypeGenFuncRef(), TabLimit); + /* Create the table instance with table type. */ + /* + * Developers can also use the `WasmEdge_TableInstanceCreateWithInit()` API to + * create the table instance with default reference values. + */ + WasmEdge_TableInstanceContext *HostTable = + WasmEdge_TableInstanceCreate(TabTypeCxt); + /* Delete the table type. */ + WasmEdge_TableTypeDelete(TabTypeCxt); + WasmEdge_Result Res; + WasmEdge_Value Data; + + const WasmEdge_TableTypeContext *GotTabTypeCxt = + WasmEdge_TableInstanceGetTableType(HostTable); + /* + * The `GotTabTypeCxt` got from table instance is owned by the `HostTable` and + * should __NOT__ be destroyed. + */ + WasmEdge_ValType RefType = WasmEdge_TableTypeGetRefType(GotGlobTypeCxt); + bool IsTypeFuncRef = WasmEdge_ValTypeIsFuncRef(RefType); + /* `IsTypeFuncRef` will be `TRUE`. */ + Data = WasmEdge_ValueGenFuncRef(5); + Res = WasmEdge_TableInstanceSetData(HostTable, Data, 3); + /* Set the function index 5 to the table[3]. */ + /* + * This will get an "out of bounds table access" error + * because the position (13) is out of the table size (10): + * Res = WasmEdge_TableInstanceSetData(HostTable, Data, 13); + */ + Res = WasmEdge_TableInstanceGetData(HostTable, &Data, 3); + /* Get the FuncRef value of the table[3]. */ + /* + * This will get an "out of bounds table access" error + * because the position (13) is out of the table size (10): + * Res = WasmEdge_TableInstanceGetData(HostTable, &Data, 13); + */ + + uint32_t Size = WasmEdge_TableInstanceGetSize(HostTable); + /* `Size` will be 10. */ + Res = WasmEdge_TableInstanceGrow(HostTable, 6); + /* Grow the table size of 6, the table size will be 16. */ + /* + * This will get an "out of bounds table access" error because + * the size (16 + 6) will reach the table limit(20): + * Res = WasmEdge_TableInstanceGrow(HostTable, 6); + */ + + WasmEdge_TableInstanceDelete(HostTable); + ``` + +4. Memory instance + + In WasmEdge, developers can create the `Memory` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. The `Memory` contexts supply APIs to control the data in memory instances. + + ```c + WasmEdge_Limit MemLimit = { + .HasMax = true, .Shared = false, .Min = 1, .Max = 5}; + /* Create the memory type with limit. The memory page size is 64KiB. */ + WasmEdge_MemoryTypeContext *MemTypeCxt = + WasmEdge_MemoryTypeCreate(MemLimit); + /* Create the memory instance with memory type. */ + WasmEdge_MemoryInstanceContext *HostMemory = + WasmEdge_MemoryInstanceCreate(MemTypeCxt); + /* Delete the memory type. */ + WasmEdge_MemoryTypeDelete(MemTypeCxt); + WasmEdge_Result Res; + uint8_t Buf[256]; + + Buf[0] = 0xAA; + Buf[1] = 0xBB; + Buf[2] = 0xCC; + Res = WasmEdge_MemoryInstanceSetData(HostMemory, Buf, 0x1000, 3); + /* Set the data[0:2] to the memory[4096:4098]. */ + /* + * This will get an "out of bounds memory access" error + * because [65535:65537] is out of 1 page size (65536): + * Res = WasmEdge_MemoryInstanceSetData(HostMemory, Buf, 0xFFFF, 3); + */ + Buf[0] = 0; + Buf[1] = 0; + Buf[2] = 0; + Res = WasmEdge_MemoryInstanceGetData(HostMemory, Buf, 0x1000, 3); + /* Get the memory[4096:4098]. Buf[0:2] will be `{0xAA, 0xBB, 0xCC}`. */ + /* + * This will get an "out of bounds memory access" error + * because [65535:65537] is out of 1 page size (65536): + * Res = WasmEdge_MemoryInstanceSetData(HostMemory, Buf, 0xFFFF, 3); + */ + + uint32_t PageSize = WasmEdge_MemoryInstanceGetPageSize(HostMemory); + /* `PageSize` will be 1. */ + Res = WasmEdge_MemoryInstanceGrowPage(HostMemory, 2); + /* Grow the page size of 2, the page size of the memory instance will be 3. */ + /* + * This will get an "out of bounds memory access" error because + * the page size (3 + 3) will reach the memory limit(5): + * Res = WasmEdge_MemoryInstanceGrowPage(HostMemory, 3); + */ + + WasmEdge_MemoryInstanceDelete(HostMemory); + ``` + +5. Tag instance + + Unlike the other instances, the `Tag` contexts are only available and can be retrieved from a `Module` instance context when turning on the `Exception Handling` proposal. Developers can retrieve the `Tag Type` from the instance. + + ```c + /* + * ... + * Instantiate a WASM module with exception handling instructions via the + * executor context and get the `ModCxt` as the output module instance. + */ + + /* Try to list the exported tag instance of the instantiated WASM module. */ + uint32_t TagNum = WasmEdge_ModuleInstanceListTagLength(ModCxt); + /* Create the name buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String TagNames[BUF_LEN]; + /* + * If the list length is larger than the buffer length, the overflowed data + * will be discarded. + */ + uint32_t RealTagNum = WasmEdge_ModuleInstanceListTag(ModCxt, TagNames, BUF_LEN); + for (uint32_t I = 0; I < RealTagNum && I < BUF_LEN; I++) { + /* Working with the tag name `TagNames[I]` ... */ + /* The function names should __NOT__ be destroyed. */ + } + + /* Try to find the exported tag instance of the instantiated WASM module. */ + WasmEdge_String TagName = WasmEdge_StringCreateByCString("tag-1"); + WasmEdge_TagInstanceContext *TagCxt = + WasmEdge_ModuleInstanceFindTag(ModCxt, TagName); + /* `TagCxt` will be `NULL` if the tag not found. */ + /* + * The returned instance is owned by the module instance context and should + * __NOT__ be destroyed. + */ + + /* Try to retrieve the tag type from the tag instance. */ + const WasmEdge_TagTypeContext *TagTypeCxt = + WasmEdge_TagInstanceGetTagType(TagCxt); + /* + * The returned tag type context is owned by the tag instance context and should + * __NOT__ be destroyed. + */ + + WasmEdge_StringDelete(TagName); + ``` + +6. Global instance + + In WasmEdge, developers can create the `Global` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. The `Global` contexts supply APIs to control the value in global instances. + + ```c + WasmEdge_Value Val = WasmEdge_ValueGenI64(1000); + /* Create the global type with value type and mutation. */ + WasmEdge_GlobalTypeContext *GlobTypeCxt = WasmEdge_GlobalTypeCreate( + WasmEdge_ValTypeGenI64(), WasmEdge_Mutability_Var); + /* Create the global instance with value and global type. */ + WasmEdge_GlobalInstanceContext *HostGlobal = + WasmEdge_GlobalInstanceCreate(GlobTypeCxt, Val); + /* Delete the global type. */ + WasmEdge_GlobalTypeDelete(GlobTypeCxt); + WasmEdge_Result Res; + + const WasmEdge_GlobalTypeContext *GotGlobTypeCxt = + WasmEdge_GlobalInstanceGetGlobalType(HostGlobal); + /* + * The `GotGlobTypeCxt` got from global instance is owned by the `HostGlobal` + * and should __NOT__ be destroyed. + */ + WasmEdge_ValType ValType = WasmEdge_GlobalTypeGetValType(GotGlobTypeCxt); + bool IsTypeF64 = WasmEdge_ValTypeIsI64(ValType); + /* `ValType` will be `TRUE`. */ + enum WasmEdge_Mutability ValMut = + WasmEdge_GlobalTypeGetMutability(GotGlobTypeCxt); + /* `ValMut` will be `WasmEdge_Mutability_Var`. */ + + Res = WasmEdge_GlobalInstanceSetValue(HostGlobal, WasmEdge_ValueGenI64(888)); + /* + * Set the value u64(888) to the global. + * This function will return error if the value type mismatched or + * the global mutability is `WasmEdge_Mutability_Const`. + */ + WasmEdge_Value GlobVal = WasmEdge_GlobalInstanceGetValue(HostGlobal); + /* Get the value (888 now) of the global context. */ + + WasmEdge_GlobalInstanceDelete(HostGlobal); + ``` + +### Host Functions + +[Host functions](https://webassembly.github.io/spec/core/exec/runtime.html#syntax-hostfunc) are functions outside WebAssembly and passed to WASM modules as imports. In WasmEdge, developers can create the `Function`, `Memory`, `Table`, and `Global` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. + +1. Host function allocation + + Developers can define C functions with the following function signature as the host function body: + + ```c + typedef WasmEdge_Result (*WasmEdge_HostFunc_t)( + void *Data, const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *Params, WasmEdge_Value *Returns); + ``` + + The example of an `add` host function to add 2 `i32` values: + + ```c + WasmEdge_Result Add(void *, const WasmEdge_CallingFrameContext *, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + /* + * Params: {i32, i32} + * Returns: {i32} + * Developers should take care about the function type. + */ + /* Retrieve the value 1. */ + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + /* Retrieve the value 2. */ + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + /* Output value 1 is Val1 + Val2. */ + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + /* Return the status of success. */ + return WasmEdge_Result_Success; + } + ``` + + Then developers can create `Function` context with the host function body and the function type: + + ```c + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + /* Create a function type: {i32, i32} -> {i32}. */ + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + /* + * Create a function context with the function type and host function body. + * The `Cost` parameter can be 0 if developers do not need the cost + * measuring. + */ + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, NULL, 0); + /* + * The third parameter is the pointer to the additional data. + * Developers should guarantee the life cycle of the data, and it can be + * `NULL` if the external data is not needed. + */ + WasmEdge_FunctionTypeDelete(HostType); + + /* + * If the function instance is __NOT__ added into a module instance context, + * it should be deleted. + */ + WasmEdge_FunctionInstanceDelete(HostFunc); + ``` + +2. Calling frame context + + The `WasmEdge_CallingFrameContext` is the context to provide developers to access the module instance of the [frame on the top of the calling stack](https://webassembly.github.io/spec/core/exec/runtime.html#activations-and-frames). According to the [WASM spec](https://webassembly.github.io/spec/core/exec/instructions.html#function-calls), a frame with the module instance is pushed into the stack when invoking a function. Therefore, the host functions can access the module instance of the top frame to retrieve the memory instances to read/write data. + + ```c + WasmEdge_Result LoadOffset(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + /* Function type: {i32} -> {} */ + uint32_t Offset = (uint32_t)WasmEdge_ValueGetI32(In[0]); + uint32_t Num = 0; + + /* + * Get the 0-th memory instance of the module instance of the top frame on + * stack. + */ + WasmEdge_MemoryInstanceContext *MemCxt = + WasmEdge_CallingFrameGetMemoryInstance(CallFrameCxt, 0); + + WasmEdge_Result Res = + WasmEdge_MemoryInstanceGetData(MemCxt, (uint8_t *)(&Num), Offset, 4); + if (WasmEdge_ResultOK(Res)) { + printf("u32 at memory[%lu]: %lu\n", Offset, Num); + } else { + return Res; + } + return WasmEdge_Result_Success; + } + ``` + + Besides using the `WasmEdge_CallingFrameGetMemoryInstance()` API to get the memory instance by index in the module instance, developers can use the `WasmEdge_CallingFrameGetModuleInstance()` to get the module instance directly. Therefore, developers can retrieve the exported contexts by the `WasmEdge_ModuleInstanceContext` APIs. And also, developers can use the `WasmEdge_CallingFrameGetExecutor()` API to get the currently used executor context. + +3. User-defined error code of the host functions + + In host functions, WasmEdge provides `WasmEdge_Result_Success` to return success, `WasmEdge_Result_Terminate` to terminate the WASM execution, and `WasmEdge_Result_Fail` to return fail. WasmEdge also provides the usage of returning the user-specified codes. Developers can use the `WasmEdge_ResultGen()` API to generate the `WasmEdge_Result` with error code, and use the `WasmEdge_ResultGetCode()` API to get the error code. + + > Notice: The error code only supports 24-bit integer (0 ~ 16777216 in `uint32_t`). The values larger than 24-bit will be truncated. + + Assume that a simple WASM from the WAT is as following: + + ```wasm + (module + (type $t0 (func (param i32))) + (import "extern" "trap" (func $f-trap (type $t0))) + (func (export "trap") (param i32) + local.get 0 + call $f-trap) + ) + ``` + + And the `test.c` is as following: + + ```c + #include + #include + + /* Host function body definition. */ + WasmEdge_Result Trap(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val = WasmEdge_ValueGetI32(In[0]); + /* Return the error code from the param[0]. */ + return WasmEdge_ResultGen(WasmEdge_ErrCategory_UserLevelError, Val); + } + + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The WASM module buffer. */ + uint8_t WASM[] = {/* WASM header */ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + /* Type section */ + 0x01, 0x05, 0x01, + /* function type {i32} -> {} */ + 0x60, 0x01, 0x7F, 0x00, + /* Import section */ + 0x02, 0x0F, 0x01, + /* module name: "extern" */ + 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, + /* extern name: "trap" */ + 0x04, 0x74, 0x72, 0x61, 0x70, + /* import desc: func 0 */ + 0x00, 0x00, + /* Function section */ + 0x03, 0x02, 0x01, 0x00, + /* Export section */ + 0x07, 0x08, 0x01, + /* export name: "trap" */ + 0x04, 0x74, 0x72, 0x61, 0x70, + /* export desc: func 0 */ + 0x00, 0x01, + /* Code section */ + 0x0A, 0x08, 0x01, + /* code body */ + 0x06, 0x00, 0x20, 0x00, 0x10, 0x00, 0x0B}; + + /* Create the module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + WasmEdge_ValType ParamList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 1, NULL, 0); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Trap, NULL, 0); + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String HostFuncName = WasmEdge_StringCreateByCString("trap"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, HostFuncName, HostFunc); + WasmEdge_StringDelete(HostFuncName); + + WasmEdge_VMRegisterModuleFromImport(VMCxt, HostModCxt); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(5566)}; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("trap"); + /* Run the WASM function from memory. */ + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(WASM, sizeof(WASM)); + /* + * Note: `WasmEdge_VMRunWasmFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_VMRunWasmFromBytes()` instead. + */ + WasmEdge_Result Res = + WasmEdge_VMRunWasmFromBytes(VMCxt, Bytes, FuncName, Params, 1, NULL, 0); + + /* Get the result code and print. */ + printf("Get the error code: %u\n", WasmEdge_ResultGetCode(Res)); + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_ModuleInstanceDelete(HostModCxt); + return 0; + } + ``` + + Then you can compile and run: (giving the expected error code `5566`) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + [2022-08-26 15:06:40.384] [error] user defined failed: user defined error code, Code: 0x15be + [2022-08-26 15:06:40.384] [error] When executing function name: "trap" + Get the error code: 5566 + ``` + +4. Construct a module instance with host instances + + Besides creating a `Module` instance by registering or instantiating a WASM module, developers can create a `Module` instance with a module name and add the `Function`, `Memory`, `Table`, and `Global` instances into it with their exporting names. + + ```c + /* Host function body definition. */ + WasmEdge_Result Add(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + return WasmEdge_Result_Success; + } + + /* Create a module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("module"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + /* + * Developers can also use the WasmEdge_ModuleInstanceCreateWithData() to + * create the module instance with the data and its finalizer. It will be + * introduced later. + */ + WasmEdge_StringDelete(ExportName); + + /* Create and add a function instance into the module instance. */ + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, NULL, 0); + /* + * The third parameter is the pointer to the additional data object. + * Developers should guarantee the life cycle of the data, and it can be + * `NULL` if the external data is not needed. + */ + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("add"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, FuncName, HostFunc); + WasmEdge_StringDelete(FuncName); + + /* Create and add a table instance into the import object. */ + WasmEdge_Limit TableLimit = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + WasmEdge_TableTypeContext *HostTType = + WasmEdge_TableTypeCreate(WasmEdge_ValTypeGenFuncRef(), TableLimit); + WasmEdge_TableInstanceContext *HostTable = + WasmEdge_TableInstanceCreate(HostTType); + WasmEdge_TableTypeDelete(HostTType); + WasmEdge_String TableName = WasmEdge_StringCreateByCString("table"); + WasmEdge_ModuleInstanceAddTable(HostModCxt, TableName, HostTable); + WasmEdge_StringDelete(TableName); + + /* Create and add a memory instance into the import object. */ + WasmEdge_Limit MemoryLimit = { + .HasMax = true, .Shared = false, .Min = 1, .Max = 2}; + WasmEdge_MemoryTypeContext *HostMType = + WasmEdge_MemoryTypeCreate(MemoryLimit); + WasmEdge_MemoryInstanceContext *HostMemory = + WasmEdge_MemoryInstanceCreate(HostMType); + WasmEdge_MemoryTypeDelete(HostMType); + WasmEdge_String MemoryName = WasmEdge_StringCreateByCString("memory"); + WasmEdge_ModuleInstanceAddMemory(HostModCxt, MemoryName, HostMemory); + WasmEdge_StringDelete(MemoryName); + + /* Create and add a global instance into the module instance. */ + WasmEdge_GlobalTypeContext *HostGType = WasmEdge_GlobalTypeCreate( + WasmEdge_ValTypeGenI32(), WasmEdge_Mutability_Var); + WasmEdge_GlobalInstanceContext *HostGlobal = + WasmEdge_GlobalInstanceCreate(HostGType, WasmEdge_ValueGenI32(666)); + WasmEdge_GlobalTypeDelete(HostGType); + WasmEdge_String GlobalName = WasmEdge_StringCreateByCString("global"); + WasmEdge_ModuleInstanceAddGlobal(HostModCxt, GlobalName, HostGlobal); + WasmEdge_StringDelete(GlobalName); + + /* + * The module instance should be deleted. + * Developers should __NOT__ destroy the instances added into the module + * instance contexts. + */ + WasmEdge_ModuleInstanceDelete(HostModCxt); + ``` + +5. Specified module instance + + `WasmEdge_ModuleInstanceCreateWASI()` API can create and initialize the `WASI` module instance. + + Developers can create these module instance contexts and register them into the `Store` or `VM` contexts rather than adjust the settings in the `Configure` contexts. + + ```c + WasmEdge_ModuleInstanceContext *WasiModCxt = + WasmEdge_ModuleInstanceCreateWASI(/* ... ignored */); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + /* Register the WASI and WasmEdge_Process into the VM context. */ + WasmEdge_VMRegisterModuleFromImport(VMCxt, WasiModCxt); + /* Get the WASI exit code. */ + uint32_t ExitCode = WasmEdge_ModuleInstanceWASIGetExitCode(WasiModCxt); + /* + * The `ExitCode` will be EXIT_SUCCESS if the execution has no error. + * Otherwise, it will return with the related exit code. + */ + WasmEdge_VMDelete(VMCxt); + /* The module instances should be deleted. */ + WasmEdge_ModuleInstanceDelete(WasiModCxt); + ``` + +6. Example + + Assume that a simple WASM from the WAT is as following: + + ```wasm + (module + (type $t0 (func (param i32 i32) (result i32))) + (import "extern" "func-add" (func $f-add (type $t0))) + (func (export "addTwo") (param i32 i32) (result i32) + local.get 0 + local.get 1 + call $f-add) + ) + ``` + + And the `test.c` is as following: + + ```c + #include + #include + + /* Host function body definition. */ + WasmEdge_Result Add(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + printf("Host function \"Add\": %d + %d\n", Val1, Val2); + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + return WasmEdge_Result_Success; + } + + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The WASM module buffer. */ + uint8_t WASM[] = {/* WASM header */ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + /* Type section */ + 0x01, 0x07, 0x01, + /* function type {i32, i32} -> {i32} */ + 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, + /* Import section */ + 0x02, 0x13, 0x01, + /* module name: "extern" */ + 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, + /* extern name: "func-add" */ + 0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64, + /* import desc: func 0 */ + 0x00, 0x00, + /* Function section */ + 0x03, 0x02, 0x01, 0x00, + /* Export section */ + 0x07, 0x0A, 0x01, + /* export name: "addTwo" */ + 0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F, + /* export desc: func 0 */ + 0x00, 0x01, + /* Code section */ + 0x0A, 0x0A, 0x01, + /* code body */ + 0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B}; + + /* Create the module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, NULL, 0); + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String HostFuncName = WasmEdge_StringCreateByCString("func-add"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, HostFuncName, HostFunc); + WasmEdge_StringDelete(HostFuncName); + + WasmEdge_VMRegisterModuleFromImport(VMCxt, HostModCxt); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[2] = {WasmEdge_ValueGenI32(1234), + WasmEdge_ValueGenI32(5678)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("addTwo"); + /* Run the WASM function from memory. */ + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(WASM, sizeof(WASM)); + /* + * Note: `WasmEdge_VMRunWasmFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_VMRunWasmFromBytes()` instead. + */ + WasmEdge_Result Res = WasmEdge_VMRunWasmFromBytes(VMCxt, Bytes, FuncName, + Params, 2, Returns, 1); + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_ModuleInstanceDelete(HostModCxt); + return 0; + } + ``` + + Then you can compile and run: (the result of 1234 + 5678 is 6912) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Host function "Add": 1234 + 5678 + Get the result: 6912 + ``` + +7. Host Data Example + + Developers can set a external data object to the `Function` context, and access to the object in the function body. Assume that a simple WASM from the WAT is as following: + + ```wasm + (module + (type $t0 (func (param i32 i32) (result i32))) + (import "extern" "func-add" (func $f-add (type $t0))) + (func (export "addTwo") (param i32 i32) (result i32) + local.get 0 + local.get 1 + call $f-add) + ) + ``` + + And the `test.c` is as following: + + ```c + #include + #include + + /* Host function body definition. */ + WasmEdge_Result Add(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + printf("Host function \"Add\": %d + %d\n", Val1, Val2); + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + /* Also set the result to the data. */ + int32_t *DataPtr = (int32_t *)Data; + *DataPtr = Val1 + Val2; + return WasmEdge_Result_Success; + } + + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The WASM module buffer. */ + uint8_t WASM[] = {/* WASM header */ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + /* Type section */ + 0x01, 0x07, 0x01, + /* function type {i32, i32} -> {i32} */ + 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, + /* Import section */ + 0x02, 0x13, 0x01, + /* module name: "extern" */ + 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, + /* extern name: "func-add" */ + 0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64, + /* import desc: func 0 */ + 0x00, 0x00, + /* Function section */ + 0x03, 0x02, 0x01, 0x00, + /* Export section */ + 0x07, 0x0A, 0x01, + /* export name: "addTwo" */ + 0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F, + /* export desc: func 0 */ + 0x00, 0x01, + /* Code section */ + 0x0A, 0x0A, 0x01, + /* code body */ + 0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B}; + + /* The external data object: an integer. */ + int32_t Data; + + /* Create the module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, &Data, 0); + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String HostFuncName = WasmEdge_StringCreateByCString("func-add"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, HostFuncName, HostFunc); + WasmEdge_StringDelete(HostFuncName); + + WasmEdge_VMRegisterModuleFromImport(VMCxt, HostModCxt); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[2] = {WasmEdge_ValueGenI32(1234), + WasmEdge_ValueGenI32(5678)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("addTwo"); + /* Run the WASM function from memory. */ + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(WASM, sizeof(WASM)); + /* + * Note: `WasmEdge_VMRunWasmFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_VMRunWasmFromBytes()` instead. + */ + WasmEdge_Result Res = WasmEdge_VMRunWasmFromBytes(VMCxt, Bytes, FuncName, + Params, 2, Returns, 1); + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + printf("Data value: %d\n", Data); + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_ModuleInstanceDelete(HostModCxt); + return 0; + } + ``` + + Then you can compile and run: (the result of 1234 + 5678 is 6912) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Host function "Add": 1234 + 5678 + Get the result: 6912 + Data value: 6912 + ``` + +8. Host Data in Module Instance with Finalizer + + Besides setting host data into a host function, developers can set and move ownership of host data into a `Module` instance context with its finalizer. This may be useful when implementing the plug-ins. + + ```c + /* Struct definition. */ + typedef struct Point { + int X; + int Y; + } Point; + + /* Host function body definition. */ + WasmEdge_Result Print(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + Point *P = (Point *)In; + printf("Point: (%d, %d)\n", P->X, P->Y); + return WasmEdge_Result_Success; + } + + /* Finalizer definition. */ + void PointFinalizer(void *Data) { + if (Data) { + free((Point *)Data); + } + } + + /* Create a module instance with host data and its finalizer. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("module"); + Point *Data = (Point *)malloc(sizeof(Point)); + Data->X = 5; + Data->Y = -5; + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreateWithData(ExportName, Data, PointFinalizer); + /* + * When the `HostModCxt` being destroyed, the finalizer will be invoked and the + * `Data` will be its argument. + */ + WasmEdge_StringDelete(ExportName); + ``` + +### Plug-ins + +The WasmEdge plug-ins are the shared libraries to provide the WasmEdge runtime to load and create host module instances. With the plug-ins, the WasmEdge runtime can be extended more easily. + +#### Load plug-ins from paths + +To use the plug-ins, developers should load the plug-ins from paths first. + +```c +WasmEdge_PluginLoadWithDefaultPaths(); +``` + +After calling this API, the plug-ins in the default paths will be loaded. The default paths are: + +1. The path given in the environment variable `WASMEDGE_PLUGIN_PATH`. +2. The `../plugin/` directory related to the WasmEdge installation path. +3. The `./wasmedge/` directory under the library path if the WasmEdge is installed under the system directory (such as `/usr` and `/usr/local`). + +To load the plug-ins from a specific path or under a specific directory, developers can use this API: + +```c +WasmEdge_PluginLoadFromPath("PATH_TO_PLUGIN/plugin.so"); +``` + +#### Get the plug-in by name + +After loading the plug-ins, developers can list the loaded plug-in names. + +```c +WasmEdge_PluginLoadWithDefaultPaths(); +printf("Number of loaded plug-ins: %d\n", WasmEdge_PluginListPluginsLength()); + +WasmEdge_String Names[20]; +uint32_t NumPlugins = WasmEdge_PluginListPlugins(Names, 20); +for (int I = 0; I < NumPlugins; I++) { + printf("plug-in %d name: %s\n", I, Names[I].Buf); +} +``` + +And developers can retrieve the plug-in context by its name. + +```c +/* Assume that wasi_crypto plug-in is installed in the default plug-in path. */ +WasmEdge_PluginLoadWithDefaultPaths(); + +const char PluginName[] = "wasi_crypto"; +WasmEdge_String NameString = + WasmEdge_StringWrap(PluginName, strlen(PluginName)); +const WasmEdge_PluginContext *PluginCxt = WasmEdge_PluginFind(NameString); +``` + +#### Create the module instance from a plug-in + +With the plug-in context, developers can create the module instances by the module name. + +```c +/* Assume that the `PluginCxt` is the context to the wasi_crypto plug-in. */ + +/* List the available host modules in the plug-in. */ +WasmEdge_String Names[20]; +uint32_t ModuleLen = WasmEdge_PluginListModule(PluginCxt, Names, 20); +for (uint32_t I = 0; I < ModuleLen; I++) { + /* Will print the available host module names in the plug-in. */ + printf("%s\n", Names[I].Buf); +} +/* + * Will print here for the WASI-Crypto plug-in here: + * wasi_ephemeral_crypto_asymmetric_common + * wasi_ephemeral_crypto_common + * wasi_ephemeral_crypto_kx + * wasi_ephemeral_crypto_signatures + * wasi_ephemeral_crypto_symmetric + */ + +/* Create a module instance from the plug-in by the module name. */ +const char ModuleName[] = "wasi_ephemeral_crypto_common"; +WasmEdge_String NameString = + WasmEdge_StringWrap(ModuleName, strlen(ModuleName)); +WasmEdge_ModuleInstance *ModCxt = + WasmEdge_PluginCreateModule(PluginCxt, NameString); + +WasmEdge_ModuleInstanceDelete(ModCxt); +``` + +## WasmEdge AOT Compiler + +In this partition, we will introduce the WasmEdge AOT compiler and the options. + +WasmEdge runs the WASM files in interpreter mode, and WasmEdge also supports the AOT (ahead-of-time) mode running without modifying any code. The WasmEdge AOT (ahead-of-time) compiler compiles the WASM files for running in AOT mode which is much faster than interpreter mode. Developers can compile the WASM files into the compiled-WASM files in shared library format for universal WASM format for the AOT mode execution. + +### Compilation Example + +Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```c +#include +#include +int main() { + /* Create the configure context. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* ... Adjust settings in the configure context. */ + /* Result. */ + WasmEdge_Result Res; + + /* Create the compiler context. The configure context can be NULL. */ + WasmEdge_CompilerContext *CompilerCxt = WasmEdge_CompilerCreate(ConfCxt); + /* Compile the WASM file with input and output paths. */ + Res = WasmEdge_CompilerCompile(CompilerCxt, "fibonacci.wasm", + "fibonacci-aot.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("Compilation failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + + WasmEdge_CompilerDelete(CompilerCxt); + WasmEdge_ConfigureDelete(ConfCxt); + return 0; +} +``` + +Then you can compile and run (the output file is "fibonacci-aot.wasm"): + +```bash +$ gcc test.c -lwasmedge +$ ./a.out +[2021-07-02 11:08:08.651] [info] compile start +[2021-07-02 11:08:08.653] [info] verify start +[2021-07-02 11:08:08.653] [info] optimize start +[2021-07-02 11:08:08.670] [info] codegen start +[2021-07-02 11:08:08.706] [info] compile done +``` + +### Compiler Options + +Developers can set options for AOT compilers such as optimization level and output format: + +```c +/// AOT compiler optimization level enumeration. +enum WasmEdge_CompilerOptimizationLevel { + /// Disable as many optimizations as possible. + WasmEdge_CompilerOptimizationLevel_O0 = 0, + /// Optimize quickly without destroying debuggability. + WasmEdge_CompilerOptimizationLevel_O1, + /// Optimize for fast execution as much as possible without triggering + /// significant incremental compile time or code size growth. + WasmEdge_CompilerOptimizationLevel_O2, + /// Optimize for fast execution as much as possible. + WasmEdge_CompilerOptimizationLevel_O3, + /// Optimize for small code size as much as possible without triggering + /// significant incremental compile time or execution time slowdowns. + WasmEdge_CompilerOptimizationLevel_Os, + /// Optimize for small code size as much as possible. + WasmEdge_CompilerOptimizationLevel_Oz +}; + +/// AOT compiler output binary format enumeration. +enum WasmEdge_CompilerOutputFormat { + /// Native dynamic library format. + WasmEdge_CompilerOutputFormat_Native = 0, + /// WebAssembly with AOT compiled codes in custom sections. + WasmEdge_CompilerOutputFormat_Wasm +}; +``` + +Please refer to the [AOT compiler options configuration](#configurations) for details. + +## WasmEdge CLI Tools + +In this partition, we will introduce the C API for triggering the WasmEdge CLI tools. + +Besides executing the `wasmedge` and `wasmedgec` CLI tools, developers can trigger the WasmEdge CLI tools by WasmEdge C API. The API arguments are the same as the command line arguments of the CLI tools. + +### Runtime CLI + +The `WasmEdge_Driver_Tool()` API presents the same function as running the [`wasmedge run` command](../../../start/build-and-run/run.md). + +Noticed that this API presents the old `wasmedge` CLI tool, which is the same as the `wasmedge run` command. For the current unified `wasmedge` CLI, please refer to the [API below](#unified-cli). + +```c +#include +#include +int main(int argc, const char *argv[]) { + /* Run the WasmEdge runtime tool. */ + return WasmEdge_Driver_Tool(argc, argv); +} +``` + +### Compiler CLI + +The `WasmEdge_Driver_Compiler()` API presents the same function as running the [`wasmedge compile` tool](../../../start/build-and-run/aot.md). + +Noticed that this API presents the old `wasmedgec` CLI tool, which is the same as the `wasmedge compile` command. For the current unified `wasmedge` CLI, please refer to the [API below](#unified-cli). + +```c +#include +#include +int main(int argc, const char *argv[]) { + /* Run the WasmEdge AOT compiler. */ + return WasmEdge_Driver_Compiler(argc, argv); +} +``` + +### Unified CLI + +The `WasmEdge_Driver_UniTool()` API presents the same function as running the [`wasmedge` tool](../../../start/build-and-run/cli.md). + +```c +#include +#include +int main(int argc, const char *argv[]) { + /* Run the WasmEdge unified tool. */ + /* (Within both runtime and AOT compiler) */ + return WasmEdge_Driver_UniTool(argc, argv); +} +``` + +### CLI Helpers for Windows + +On Windows platforms, developers can use the `WasmEdge_Driver_ArgvCreate()` and `WasmEdge_Driver_ArgvDelete()` APIs to convert and handle the `UTF-8` command line arguments, or use the `WasmEdge_Driver_SetConsoleOutputCPtoUTF8()` API to set the console output code page to `UTF-8`. diff --git a/docs/embed/c/reference/0.15.x.md b/docs/embed/c/reference/0.15.x.md new file mode 100644 index 00000000..ac201d6b --- /dev/null +++ b/docs/embed/c/reference/0.15.x.md @@ -0,0 +1,3295 @@ +--- +sidebar_position: 3 +--- + +# C API 0.15.1 Documentation + +[WasmEdge C API](https://github.com/WasmEdge/WasmEdge/blob/master/include/api/wasmedge/wasmedge.h) denotes an interface to access the WasmEdge runtime at version `0.15.1`. The following are the guides to working with the C APIs of WasmEdge. + +**Developers can refer to [here to upgrade to v0.16.0](upgrade_to_0.16.0).** + +## WasmEdge Installation + +### Download And Install + +The easiest way to install WasmEdge is to run the following command. Your system should have `git` and `wget` as prerequisites. + +```bash +curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -v 0.15.1 +``` + +For more details, please refer to the [Installation Guide](../../../start/install.md#install) for the WasmEdge installation. + +### Compile Sources + +After the installation of WasmEdge, the following guide can help you to test for the availability of the WasmEdge C API. + +1. Prepare the test C file (and assumed saved as `test.c`): + + ```c + #include + #include + int main() { + printf("WasmEdge version: %s\n", WasmEdge_VersionGet()); + return 0; + } + ``` + +2. Compile the file with `gcc` or `clang`. + + ```bash + gcc test.c -lwasmedge + ``` + +3. Run and get the expected output. + + ```bash + $ ./a.out + WasmEdge version: 0.15.1 + ``` + +### ABI Compatibility + +WasmEdge C API introduces SONAME and SOVERSION since the `0.11.0` release to present the compatibility between different C API versions. + +The releases before 0.11.0 are all unversioned. Please make sure the library version is the same as the corresponding C API version you used. + +| WasmEdge Version | WasmEdge C API Library Name | WasmEdge C API SONAME | WasmEdge C API SOVERSION | +| --- | --- | --- | --- | +| < 0.11.0 | libwasmedge_c.so | Unversioned | Unversioned | +| 0.11.0 to 0.11.1 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.0 | +| 0.11.2 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.1 | +| 0.12.0 to 0.12.1 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.2 | +| 0.13.0 to 0.13.5 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.3 | +| Since 0.14.0 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.1.0 | + +## WasmEdge Basics + +In this part, we will introduce the utilities and concepts of WasmEdge shared library. + +### Version + +The `Version` related APIs provide developers to check for the WasmEdge shared library version. + +```c +#include +printf("WasmEdge version: %s\n", WasmEdge_VersionGet()); +printf("WasmEdge version major: %u\n", WasmEdge_VersionGetMajor()); +printf("WasmEdge version minor: %u\n", WasmEdge_VersionGetMinor()); +printf("WasmEdge version patch: %u\n", WasmEdge_VersionGetPatch()); +``` + +### Logging Settings + +1. Setting logging levels + + The `WasmEdge_LogSetErrorLevel()` and `WasmEdge_LogSetDebugLevel()` APIs can set the logging system to debug level or error level. By default, the error level is set, and the debug info is hidden. + + Developers can set the logging level by the `WasmEdge_LogSetLevel()` API with the level enumeration: + + ```c + typedef enum WasmEdge_LogLevel { + WasmEdge_LogLevel_Trace, + WasmEdge_LogLevel_Debug, + WasmEdge_LogLevel_Info, + WasmEdge_LogLevel_Warn, + WasmEdge_LogLevel_Error, + WasmEdge_LogLevel_Critical, + } WasmEdge_LogLevel; + ``` + + Developers can also use the `WasmEdge_LogOff()` API to disable all logging. + +2. Logging callback + + For getting the detailed result or error message, WasmEdge provides the callback interface to register the customized callback function into the logging sink. + + Developers will get the message struct via the callback argument: + + ```c + typedef struct WasmEdge_LogMessage { + WasmEdge_String Message; + WasmEdge_String LoggerName; + WasmEdge_LogLevel Level; + time_t Time; + uint64_t ThreadId; + } WasmEdge_LogMessage; + ``` + + Developers can register the callback by the `WasmEdge_LogSetCallback()` API to receive the message when logging occurs. + + ```c + #include + void callback(const WasmEdge_LogMessage *Message) { + printf("Message: %s, LoggerName: %s\n", Message->Message.Buf, Message->LoggerName.Buf); + } + + int main() { + WasmEdge_LogSetCallback(callback); + return 0; + } + ``` + +### Value Types + +To describe the value types in WASM, WasmEdge uses the `WasmEdge_ValType` struct to encode the value types. + +1. Number types: `i32`, `i64`, `f32`, `f64`, and `v128` for the `SIMD` proposal + + ```c + WasmEdge_ValType ValType; + ValType = WasmEdge_ValTypeGenI32(); + bool IsTypeI32 = WasmEdge_ValTypeIsI32(ValType); + /* The `IsTypeI32` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenI64(); + bool IsTypeI64 = WasmEdge_ValTypeIsI64(ValType); + /* The `IsTypeI64` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenF32(); + bool IsTypeF32 = WasmEdge_ValTypeIsF32(ValType); + /* The `IsTypeF32` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenF64(); + bool IsTypeF64 = WasmEdge_ValTypeIsF64(ValType); + /* The `IsTypeF64` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenV128(); + bool IsTypeV128 = WasmEdge_ValTypeIsV128(ValType); + /* The `IsTypeV128` will be `TRUE`. */ + ``` + +2. Reference types: `funcref` and `externref` for the `Reference-Types` or `Typed-Function References` proposal + + ```c + WasmEdge_ValType ValType; + + ValType = WasmEdge_ValTypeGenFuncRef(); + /* The nullable funcref type is generated. */ + bool IsTypeFuncRef = WasmEdge_ValTypeIsFuncRef(ValType); + /* The `IsTypeFuncRef` will be `TRUE`. */ + bool IsTypeRef = WasmEdge_ValTypeIsRef(ValType); + /* The `IsTypeRef` will be `TRUE`. */ + bool IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(ValType); + /* The `IsTypeNullableRef` will be `TRUE`. */ + + ValType = WasmEdge_ValTypeGenExternRef(); + /* The nullable externref type is generated. */ + bool IsTypeExternRef = WasmEdge_ValTypeIsExternRef(ValType); + /* The `IsTypeExternRef` will be `TRUE`. */ + IsTypeRef = WasmEdge_ValTypeIsRef(ValType); + /* The `IsTypeRef` will be `TRUE`. */ + IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(ValType); + /* The `IsTypeNullableRef` will be `TRUE`. */ + ``` + +### Values + +In WasmEdge, developers should convert the values to `WasmEdge_Value` objects through APIs for matching to the WASM values for the arguments or returns. With the APIs, the output `WasmEdge_Value` objects will record the correct value types with values. + +1. Number types: `i32`, `i64`, `f32`, `f64`, and `v128` for the `SIMD` proposal + + ```c + WasmEdge_Value Val; + + Val = WasmEdge_ValueGenI32(123456); + bool IsTypeI32 = WasmEdge_ValTypeIsI32(Val.Type); + /* The `IsTypeI32` will be `TRUE`. */ + printf("%d\n", WasmEdge_ValueGetI32(Val)); + /* Will print "123456" */ + + Val = WasmEdge_ValueGenI64(1234567890123LL); + bool IsTypeI64 = WasmEdge_ValTypeIsI64(Val.Type); + /* The `IsTypeI64` will be `TRUE`. */ + printf("%ld\n", WasmEdge_ValueGetI64(Val)); + /* Will print "1234567890123" */ + + Val = WasmEdge_ValueGenF32(123.456f); + bool IsTypeF32 = WasmEdge_ValTypeIsF32(Val.Type); + /* The `IsTypeF32` will be `TRUE`. */ + printf("%f\n", WasmEdge_ValueGetF32(Val)); + /* Will print "123.456001" */ + + Val = WasmEdge_ValueGenF64(123456.123456789); + bool IsTypeF64 = WasmEdge_ValTypeIsF64(Val.Type); + /* The `IsTypeF64` will be `TRUE`. */ + printf("%.10f\n", WasmEdge_ValueGetF64(Val)); + /* Will print "123456.1234567890" */ + ``` + +2. Reference types: `funcref` and `externref` for the `Reference-Types` or `Typed-Function References` proposal + + ```c + WasmEdge_Value Val; + void *Ptr; + uint32_t Num = 10; + /* Generate an externref to NULL. */ + Val = WasmEdge_ValueGenExternRef(NULL); + bool IsNull = WasmEdge_ValueIsNullRef(Val); + /* The `IsNull` will be `TRUE`. */ + bool IsTypeExternRef = WasmEdge_ValTypeIsExternRef(Val.Type); + /* The `IsTypeExternRef` will be `TRUE`. */ + bool IsTypeRef = WasmEdge_ValTypeIsRef(Val.Type); + /* The `IsTypeRef` will be `TRUE`. */ + bool IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(Val.Type); + /* The `IsTypeNullableRef` will be `TRUE`. */ + Ptr = WasmEdge_ValueGetExternRef(Val); + /* The `Ptr` will be `NULL`. */ + + /* Get the function instance by creation or from module instance. */ + const WasmEdge_FunctionInstanceContext *FuncCxt = ...; + /* Generate a funcref with the given function instance context. */ + Val = WasmEdge_ValueGenFuncRef(FuncCxt); + bool IsTypeFuncRef = WasmEdge_ValTypeIsFuncRef(Val.Type); + /* The `IsTypeFuncRef` will be `TRUE`. */ + IsTypeRef = WasmEdge_ValTypeIsRef(Val.Type); + /* The `IsTypeRef` will be `TRUE`. */ + IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(Val.Type); + /* The `IsTypeNullableRef` will be `TRUE`. */ + const WasmEdge_FunctionInstanceContext *GotFuncCxt = + WasmEdge_ValueGetFuncRef(Val); + /* The `GotFuncCxt` will be the same as `FuncCxt`. */ + + /* Generate a externref to `Num`. */ + Val = WasmEdge_ValueGenExternRef(&Num); + Ptr = WasmEdge_ValueGetExternRef(Val); + /* The `Ptr` will be `&Num`. */ + printf("%u\n", *(uint32_t *)Ptr); + /* Will print "10" */ + Num += 55; + printf("%u\n", *(uint32_t *)Ptr); + /* Will print "65" */ + ``` + +### Buffers + +The `WasmEdge_Bytes` object is for the input buffer of loading or compiling module from memory, or the output buffer of serializing a module. + + +:::note +This object is designed for replacing raw buffer as input and output of WasmEdge C API. We recommand developers to use the `WasmEdge_Bytes` related APIs than the raw buffer, such as using `WasmEdge_LoaderParseFromBytes()` instead of `WasmEdge_LoaderParseFromBuffer()`. +::: + +1. Create a `WasmEdge_Bytes` from a buffer with length. + + ```c + uint8_t Buf[4] = {1, 2, 3, 4}; + WasmEdge_Bytes Bytes = WasmEdge_BytesCreate(Buf, 4); + /* The objects should be deleted by `WasmEdge_BytesDelete()`. */ + WasmEdge_BytesDelete(Bytes); + ``` + +2. Wrap a `WasmEdge_Bytes` to a buffer with length. + + The content will not be copied, and the caller should guarantee the life cycle of the input buffer. + + ```c + uint8_t Buf[4] = {1, 2, 3, 4}; + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(Buf, 4); + /* The object should __NOT__ be deleted by `WasmEdge_BytesDelete()`. */ + ``` + +### Strings + +The `WasmEdge_String` object is for the instance names when invoking a WASM function or finding the contexts of instances. + +1. Create a `WasmEdge_String` from a C string (`const char *` with NULL termination) or a buffer with length. + + The content of the C string or buffer will be copied into the `WasmEdge_String` object. + + ```c + char Buf[4] = {50, 55, 60, 65}; + WasmEdge_String Str1 = WasmEdge_StringCreateByCString("test"); + WasmEdge_String Str2 = WasmEdge_StringCreateByBuffer(Buf, 4); + /* The objects should be deleted by `WasmEdge_StringDelete()`. */ + WasmEdge_StringDelete(Str1); + WasmEdge_StringDelete(Str2); + ``` + +2. Wrap a `WasmEdge_String` to a buffer with length. + + The content will not be copied, and the caller should guarantee the life cycle of the input buffer. + + ```c + const char CStr[] = "test"; + WasmEdge_String Str = WasmEdge_StringWrap(CStr, 4); + /* The object should __NOT__ be deleted by `WasmEdge_StringDelete()`. */ + ``` + +3. String comparison + + ```c + const char CStr[] = "abcd"; + char Buf[4] = {0x61, 0x62, 0x63, 0x64}; + WasmEdge_String Str1 = WasmEdge_StringWrap(CStr, 4); + WasmEdge_String Str2 = WasmEdge_StringCreateByBuffer(Buf, 4); + bool IsEq = WasmEdge_StringIsEqual(Str1, Str2); + /* The `IsEq` will be `TRUE`. */ + WasmEdge_StringDelete(Str2); + ``` + +4. Convert to C string + + ```c + char Buf[256]; + WasmEdge_String Str = + WasmEdge_StringCreateByCString("test_wasmedge_string"); + uint32_t StrLength = WasmEdge_StringCopy(Str, Buf, sizeof(Buf)); + /* StrLength will be 20 */ + printf("String: %s\n", Buf); + /* Will print "test_wasmedge_string". */ + ``` + +### Results + +The `WasmEdge_Result` object specifies the execution status. APIs about WASM execution will return the `WasmEdge_Result` to denote the status. + +```c +WasmEdge_Result Res = WasmEdge_Result_Success; +bool IsSucceeded = WasmEdge_ResultOK(Res); +/* The `IsSucceeded` will be `TRUE`. */ +uint32_t Code = WasmEdge_ResultGetCode(Res); +/* The `Code` will be 0. */ +const char *Msg = WasmEdge_ResultGetMessage(Res); +/* The `Msg` will be "success". */ +enum WasmEdge_ErrCategory Category = WasmEdge_ResultGetCategory(Res); +/* The `Category` will be WasmEdge_ErrCategory_WASM. */ + +Res = WasmEdge_ResultGen(WasmEdge_ErrCategory_UserLevelError, 123); +/* Generate the user-defined result with code. */ +Code = WasmEdge_ResultGetCode(Res); +/* The `Code` will be 123. */ +Category = WasmEdge_ResultGetCategory(Res); +/* The `Category` will be WasmEdge_ErrCategory_UserLevelError. */ +``` + +### Contexts + +The objects, such as `VM`, `Store`, and `Function`, are composed of `Context`s. All of the contexts can be created by calling the corresponding creation APIs and should be destroyed by calling the corresponding deletion APIs. Developers have responsibilities to manage the contexts for memory management. + +```c +/* Create the configure context. */ +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); +/* Delete the configure context. */ +WasmEdge_ConfigureDelete(ConfCxt); +``` + +The details of other contexts will be introduced later. + +### WASM Data Structures + +The WASM data structures are used for creating instances or can be queried from instance contexts. The details of instances creation will be introduced in the [Instances](#instances). + +1. Limit + + The `WasmEdge_Limit` struct is defined in the header: + + ```c + /// Struct of WASM limit. + typedef struct WasmEdge_Limit { + /// Boolean to describe has max value or not. + bool HasMax; + /// Boolean to describe is shared memory or not. + bool Shared; + /// Minimum value. + uint32_t Min; + /// Maximum value. Will be ignored if the `HasMax` is false. + uint32_t Max; + } WasmEdge_Limit; + ``` + + Developers can initialize the struct by assigning it's value, and the `Max` value is needed to be larger or equal to the `Min` value. The API `WasmEdge_LimitIsEqual()` is provided to compare with 2 `WasmEdge_Limit` structs. + +2. Function type context + + The `Function Type` context is used for the `Function` creation, checking the value types of a `Function` instance, or getting the function type with function name from VM. Developers can use the `Function Type` context APIs to get the parameter or return value types information. + + ```c + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI64()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenFuncRef()}; + WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + + WasmEdge_ValType Buf[16]; + uint32_t ParamLen = WasmEdge_FunctionTypeGetParametersLength(FuncTypeCxt); + /* `ParamLen` will be 2. */ + uint32_t GotParamLen = WasmEdge_FunctionTypeGetParameters(FuncTypeCxt, Buf, 16); + /* + * `GotParamLen` will be 2, and `Buf[0]` and `Buf[1]` will be the same as + * `ParamList`. + */ + uint32_t ReturnLen = WasmEdge_FunctionTypeGetReturnsLength(FuncTypeCxt); + /* `ReturnLen` will be 1. */ + uint32_t GotReturnLen = WasmEdge_FunctionTypeGetReturns(FuncTypeCxt, Buf, 16); + /* + * `GotReturnLen` will be 1, and `Buf[0]` will be the same as `ReturnList`. + */ + + WasmEdge_FunctionTypeDelete(FuncTypeCxt); + ``` + +3. Table type context + + The `Table Type` context is used for `Table` instance creation or getting information from `Table` instances. + + ```c + WasmEdge_Limit TabLim = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_TableTypeCreate(WasmEdge_ValTypeGenExternRef(), TabLim); + + WasmEdge_ValType GotRefType = WasmEdge_TableTypeGetRefType(TabTypeCxt); + bool IsTypeExternRef = WasmEdge_ValTypeIsExternRef(GotRefType); + /* `IsTypeExternRef` will be `TRUE`. */ + bool IsTypeRef = WasmEdge_ValTypeIsRef(GotRefType); + /* `IsTypeRef` will be `TRUE`. */ + bool IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(GotRefType); + /* `IsTypeNullableRef` will be `TRUE`. */ + WasmEdge_Limit GotTabLim = WasmEdge_TableTypeGetLimit(TabTypeCxt); + /* `GotTabLim` will be the same value as `TabLim`. */ + + WasmEdge_TableTypeDelete(TabTypeCxt); + ``` + +4. Memory type context + + The `Memory Type` context is used for `Memory` instance creation or getting information from `Memory` instances. + + ```c + WasmEdge_Limit MemLim = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + WasmEdge_MemoryTypeContext *MemTypeCxt = WasmEdge_MemoryTypeCreate(MemLim); + + WasmEdge_Limit GotMemLim = WasmEdge_MemoryTypeGetLimit(MemTypeCxt); + /* `GotMemLim` will be the same value as `MemLim`. */ + + WasmEdge_MemoryTypeDelete(MemTypeCxt) + ``` + +5. Global type context + + The `Global Type` context is used for `Global` instance creation or getting information from `Global` instances. + + ```c + WasmEdge_GlobalTypeContext *GlobTypeCxt = WasmEdge_GlobalTypeCreate( + WasmEdge_ValTypeGenF64(), WasmEdge_Mutability_Var); + + WasmEdge_ValType GotValType = WasmEdge_GlobalTypeGetValType(GlobTypeCxt); + bool IsTypeF64 = WasmEdge_ValTypeIsF64(GotValType); + /* `IsTypeF64` will be `TRUE`. */ + WasmEdge_Mutability GotValMut = + WasmEdge_GlobalTypeGetMutability(GlobTypeCxt); + /* `GotValMut` will be WasmEdge_Mutability_Var. */ + + WasmEdge_GlobalTypeDelete(GlobTypeCxt); + ``` + +6. Tag type context + + The `Tag Type` context is used for getting information from `Tag` instances. + This will only usable if the `Exception Handling` proposal turned on. + + ```c + /* Get the tag type from a tag instance. */ + const WasmEdge_TagTypeContext *TagTypeCxt = WasmEdge_TagInstanceGetTagType(...); + + const WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_TagTypeGetFunctionType(TagTypeCxt); + ``` + +7. Import type context + + The `Import Type` context is used for getting the imports information from a [AST Module](#ast-module). Developers can get the external type (`function`, `table`, `memory`, `tag`, or `global`), import module name, and external name from an `Import Type` context. The details about querying `Import Type` contexts will be introduced in the [AST Module](#ast-module). + + ```c + WasmEdge_ASTModuleContext *ASTCxt = ...; + /* + * Assume that `ASTCxt` is returned by the `WasmEdge_LoaderContext` for the + * result of loading a WASM file. + */ + const WasmEdge_ImportTypeContext *ImpType = ...; + /* Assume that `ImpType` is queried from the `ASTCxt` for the import. */ + + enum WasmEdge_ExternalType ExtType = + WasmEdge_ImportTypeGetExternalType(ImpType); + /* + * The `ExtType` can be one of `WasmEdge_ExternalType_Function`, + * `WasmEdge_ExternalType_Table`, `WasmEdge_ExternalType_Memory`, + * `WasmEdge_ExternalType_Tag`, or `WasmEdge_ExternalType_Global`. + */ + WasmEdge_String ModName = WasmEdge_ImportTypeGetModuleName(ImpType); + WasmEdge_String ExtName = WasmEdge_ImportTypeGetExternalName(ImpType); + /* + * The `ModName` and `ExtName` should not be destroyed and the string + * buffers are binded into the `ASTCxt`. + */ + const WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_ImportTypeGetFunctionType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Function`, the + * `FuncTypeCxt` will be NULL. + */ + const WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_ImportTypeGetTableType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Table`, the `TabTypeCxt` + * will be NULL. + */ + const WasmEdge_MemoryTypeContext *MemTypeCxt = + WasmEdge_ImportTypeGetMemoryType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Memory`, the `MemTypeCxt` + * will be NULL. + */ + const WasmEdge_TagTypeContext *TagTypeCxt = + WasmEdge_ImportTypeGetTagType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Tag`, the `TagTypeCxt` + * will be NULL. + */ + const WasmEdge_GlobalTypeContext *GlobTypeCxt = + WasmEdge_ImportTypeGetGlobalType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Global`, the `GlobTypeCxt` + * will be NULL. + */ + ``` + +8. Export type context + + The `Export Type` context is used for getting the exports information from a [AST Module](#ast-module). Developers can get the external type (`function`, `table`, `memory`, `tag`, or `global`) and external name from an `Export Type` context. The details about querying `Export Type` contexts will be introduced in the [AST Module](#ast-module). + + ```c + WasmEdge_ASTModuleContext *ASTCxt = ...; + /* + * Assume that `ASTCxt` is returned by the `WasmEdge_LoaderContext` for the + * result of loading a WASM file. + */ + const WasmEdge_ExportTypeContext *ExpType = ...; + /* Assume that `ExpType` is queried from the `ASTCxt` for the export. */ + + enum WasmEdge_ExternalType ExtType = + WasmEdge_ExportTypeGetExternalType(ExpType); + /* + * The `ExtType` can be one of `WasmEdge_ExternalType_Function`, + * `WasmEdge_ExternalType_Table`, `WasmEdge_ExternalType_Memory`, + * `WasmEdge_ExternalType_Tag`, or `WasmEdge_ExternalType_Global`. + */ + WasmEdge_String ExtName = WasmEdge_ExportTypeGetExternalName(ExpType); + /* + * The `ExtName` should not be destroyed and the string buffer is binded + * into the `ASTCxt`. + */ + const WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_ExportTypeGetFunctionType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Function`, the + * `FuncTypeCxt` will be NULL. + */ + const WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_ExportTypeGetTableType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Table`, the `TabTypeCxt` + * will be NULL. + */ + const WasmEdge_MemoryTypeContext *MemTypeCxt = + WasmEdge_ExportTypeGetMemoryType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Memory`, the `MemTypeCxt` + * will be NULL. + */ + const WasmEdge_TagTypeContext *TagTypeCxt = + WasmEdge_ExportTypeGetTagType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Tag`, the `TagTypeCxt` + * will be NULL. + */ + const WasmEdge_GlobalTypeContext *GlobTypeCxt = + WasmEdge_ExportTypeGetGlobalType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Global`, the `GlobTypeCxt` + * will be NULL. + */ + ``` + +### Async + +After calling the [asynchronous execution APIs](#asynchronous-execution), developers will get the `WasmEdge_Async` object. Developers own the object and should call the `WasmEdge_AsyncDelete()` API to destroy it. + +1. Wait for the asynchronous execution + + Developers can wait the execution until finished: + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* Blocking and waiting for the execution. */ + WasmEdge_AsyncWait(Async); + WasmEdge_AsyncDelete(Async); + ``` + + Or developers can wait for a time limit. If the time limit exceeded, developers can choose to cancel the execution. For the interruptible execution in AOT mode, developers should set `TRUE` through the `WasmEdge_ConfigureCompilerSetInterruptible()` API into the configure context for the AOT compiler. + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* Blocking and waiting for the execution for 1 second. */ + bool IsEnd = WasmEdge_AsyncWaitFor(Async, 1000); + if (IsEnd) { + /* The execution finished. Developers can get the result. */ + WasmEdge_Result Res = WasmEdge_AsyncGet(/* ... Ignored */); + } else { + /* + * The time limit exceeded. Developers can keep waiting or cancel the + * execution. + */ + WasmEdge_AsyncCancel(Async); + WasmEdge_Result Res = WasmEdge_AsyncGet(Async, 0, NULL); + /* The result error code will be `WasmEdge_ErrCode_Interrupted`. */ + } + WasmEdge_AsyncDelete(Async); + ``` + +2. Get the execution result of the asynchronous execution + + Developers can use the `WasmEdge_AsyncGetReturnsLength()` API to get the return value list length. This function will block and wait for the execution. If the execution has finished, this function will return the length immediately. If the execution failed, this function will return `0`. This function can help the developers to create the buffer to get the return values. If developers have already known the buffer length, they can skip this function and use the `WasmEdge_AsyncGet()` API to get the result. + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* + * Blocking and waiting for the execution and get the return value list + * length. + */ + uint32_t Arity = WasmEdge_AsyncGetReturnsLength(Async); + WasmEdge_AsyncDelete(Async); + ``` + + The `WasmEdge_AsyncGet()` API will block and wait for the execution. If the execution has finished, this function will fill the return values into the buffer and return the execution result immediately. + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* Blocking and waiting for the execution and get the return values. */ + const uint32_t BUF_LEN = 256; + WasmEdge_Value Buf[BUF_LEN]; + WasmEdge_Result Res = WasmEdge_AsyncGet(Async, Buf, BUF_LEN); + WasmEdge_AsyncDelete(Async); + ``` + +### Configurations + +The configuration context, `WasmEdge_ConfigureContext`, manages the configurations for `Loader`, `Validator`, `Executor`, `VM`, and `Compiler` contexts. Developers can adjust the settings about the proposals, VM host pre-registrations (such as `WASI`), and AOT compiler options, and then apply the `Configure` context to create the runtime contexts. + +1. Proposals + + WasmEdge supports turning on or off the WebAssembly proposals. This configuration is effective in any contexts created with the `Configure` context. + + ```c + enum WasmEdge_Proposal { + WasmEdge_Proposal_ImportExportMutGlobals = 0, + WasmEdge_Proposal_NonTrapFloatToIntConversions, + WasmEdge_Proposal_SignExtensionOperators, + WasmEdge_Proposal_MultiValue, + WasmEdge_Proposal_BulkMemoryOperations, + WasmEdge_Proposal_ReferenceTypes, + WasmEdge_Proposal_SIMD, + WasmEdge_Proposal_TailCall, + WasmEdge_Proposal_ExtendedConst, + WasmEdge_Proposal_FunctionReferences, + WasmEdge_Proposal_GC, + WasmEdge_Proposal_MultiMemories, + WasmEdge_Proposal_RelaxSIMD, + WasmEdge_Proposal_Annotations, + WasmEdge_Proposal_Threads, + WasmEdge_Proposal_ExceptionHandling, + WasmEdge_Proposal_Memory64, + WasmEdge_Proposal_Component, + }; + ``` + + Developers can add or remove the proposals into the `Configure` context. + + ```c + /* + * By default, the following proposals have turned on initially: + * * Import/Export of mutable globals + * * Non-trapping float-to-int conversions + * * Sign-extension operators + * * Multi-value returns + * * Bulk memory operations + * * Reference types + * * Fixed-width SIMD + * + * For the current WasmEdge version, the following proposals are supported + * (turned off by default) additionally: + * * Tail-call + * * Extended-const + * * Typed-function references + * * GC + * * Multiple memories + * * Relaxed SIMD + * * Threads + * * Exception handling (interpreter only) + * * Component model (loader phase only) + */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddProposal(ConfCxt, WasmEdge_Proposal_MultiMemories); + WasmEdge_ConfigureRemoveProposal(ConfCxt, WasmEdge_Proposal_ReferenceTypes); + bool IsBulkMem = WasmEdge_ConfigureHasProposal( + ConfCxt, WasmEdge_Proposal_BulkMemoryOperations); + /* The `IsBulkMem` will be `TRUE`. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +2. Host registrations + + This configuration is used for the `VM` context to turn on the `WASI` supports and only effective in `VM` contexts. + + The element of this enum is reserved for the other built-in host functions (such as `wasi-socket`) in the future. + + ```c + enum WasmEdge_HostRegistration { + WasmEdge_HostRegistration_Wasi = 0 + }; + ``` + + The details will be introduced in the [preregistrations of VM context](#built-in-host-modules-and-plug-in-preregistrations). + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + bool IsHostWasi = WasmEdge_ConfigureHasHostRegistration( + ConfCxt, WasmEdge_HostRegistration_Wasi); + /* The `IsHostWasi` will be `FALSE`. */ + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + IsHostWasi = WasmEdge_ConfigureHasHostRegistration( + ConfCxt, WasmEdge_HostRegistration_Wasi); + /* The `IsHostWasi` will be `TRUE`. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +3. Maximum memory pages + + Developers can limit the page size of memory instances by this configuration. When growing the page size of memory instances in WASM execution and exceeding the limited size, the page growing will fail. This configuration is only effective in the `Executor` and `VM` contexts. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + uint32_t PageSize = WasmEdge_ConfigureGetMaxMemoryPage(ConfCxt); + /* By default, the maximum memory page size is 65536. */ + WasmEdge_ConfigureSetMaxMemoryPage(ConfCxt, 1024); + /* + * Limit the memory size of each memory instance with not larger than 1024 + * pages (64 MiB). + */ + PageSize = WasmEdge_ConfigureGetMaxMemoryPage(ConfCxt); + /* The `PageSize` will be 1024. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +4. Forcibly interpreter mode + + If developers want to execute the WASM file or the AOT compiled WASM in interpreter mode forcibly, they can turn on the configuration. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + bool IsForceInterp = WasmEdge_ConfigureIsForceInterpreter(ConfCxt); + /* By default, The `IsForceInterp` will be `FALSE`. */ + WasmEdge_ConfigureSetForceInterpreter(ConfCxt, TRUE); + IsForceInterp = WasmEdge_ConfigureIsForceInterpreter(ConfCxt); + /* The `IsForceInterp` will be `TRUE`. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +5. AOT compiler options + + The AOT compiler options configure the behavior about optimization level, output format, dump IR, and generic binary. + + ```c + enum WasmEdge_CompilerOptimizationLevel { + // Disable as many optimizations as possible. + WasmEdge_CompilerOptimizationLevel_O0 = 0, + // Optimize quickly without destroying debuggability. + WasmEdge_CompilerOptimizationLevel_O1, + // Optimize for fast execution as much as possible without triggering + // significant incremental compile time or code size growth. + WasmEdge_CompilerOptimizationLevel_O2, + // Optimize for fast execution as much as possible. + WasmEdge_CompilerOptimizationLevel_O3, + // Optimize for small code size as much as possible without triggering + // significant incremental compile time or execution time slowdowns. + WasmEdge_CompilerOptimizationLevel_Os, + // Optimize for small code size as much as possible. + WasmEdge_CompilerOptimizationLevel_Oz + }; + + enum WasmEdge_CompilerOutputFormat { + // Native dynamic library format. + WasmEdge_CompilerOutputFormat_Native = 0, + // WebAssembly with AOT compiled codes in custom section. + WasmEdge_CompilerOutputFormat_Wasm + }; + ``` + + These configurations are only effective in `Compiler` contexts. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* By default, the optimization level is O3. */ + WasmEdge_ConfigureCompilerSetOptimizationLevel( + ConfCxt, WasmEdge_CompilerOptimizationLevel_O2); + /* By default, the output format is universal WASM. */ + WasmEdge_ConfigureCompilerSetOutputFormat( + ConfCxt, WasmEdge_CompilerOutputFormat_Native); + /* By default, the dump IR is `FALSE`. */ + WasmEdge_ConfigureCompilerSetDumpIR(ConfCxt, TRUE); + /* By default, the generic binary is `FALSE`. */ + WasmEdge_ConfigureCompilerSetGenericBinary(ConfCxt, TRUE); + /* By default, the interruptible is `FALSE`. + /* Set this option to `TRUE` to support the interruptible execution in AOT + mode. */ + WasmEdge_ConfigureCompilerSetInterruptible(ConfCxt, TRUE); + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +6. Statistics options + + The statistics options configure the behavior about instruction counting, cost measuring, and time measuring in both runtime and AOT compiler. These configurations are effective in `Compiler`, `VM`, and `Executor` contexts. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* + * By default, the instruction counting is `FALSE` when running a + * compiled-WASM or a pure-WASM. + */ + WasmEdge_ConfigureStatisticsSetInstructionCounting(ConfCxt, TRUE); + /* + * By default, the cost measurement is `FALSE` when running a compiled-WASM + * or a pure-WASM. + */ + WasmEdge_ConfigureStatisticsSetCostMeasuring(ConfCxt, TRUE); + /* + * By default, the time measurement is `FALSE` when running a compiled-WASM + * or a pure-WASM. + */ + WasmEdge_ConfigureStatisticsSetTimeMeasuring(ConfCxt, TRUE); + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +### Statistics + +The statistics context, `WasmEdge_StatisticsContext`, provides the instruction counter, cost summation, and cost limitation at runtime. + +Before using statistics, the statistics configuration must be set. Otherwise, the return values of calling statistics are undefined behaviour. + +1. Instruction counter + + The instruction counter can help developers to profile the performance of WASM running. Developers can retrieve the `Statistics` context from the `VM` context, or create a new one for the `Executor` creation. The details will be introduced in the next partitions. + + ```c + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * ... + * After running the WASM functions with the `Statistics` context + */ + uint32_t Count = WasmEdge_StatisticsGetInstrCount(StatCxt); + double IPS = WasmEdge_StatisticsGetInstrPerSecond(StatCxt); + WasmEdge_StatisticsDelete(StatCxt); + ``` + +2. Cost table + + The cost table is to accumulate the cost of instructions with their weights. Developers can set the cost table array (the indices are the byte code value of instructions, and the values are the cost of instructions) into the `Statistics` context. If the cost limit value is set, the execution will return the `cost limit exceeded` error immediately when exceeds the cost limit in runtime. + + ```c + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + uint64_t CostTable[16] = { + 0, 0, + 10, /* 0x02: Block */ + 11, /* 0x03: Loop */ + 12, /* 0x04: If */ + 12, /* 0x05: Else */ + 0, 0, 0, 0, 0, 0, + 20, /* 0x0C: Br */ + 21, /* 0x0D: Br_if */ + 22, /* 0x0E: Br_table */ + 0 + }; + /* + * Developers can set the costs of each instruction. The value not + * covered will be 0. + */ + WasmEdge_StatisticsSetCostTable(StatCxt, CostTable, 16); + WasmEdge_StatisticsSetCostLimit(StatCxt, 5000000); + /* + * ... + * After running the WASM functions with the `Statistics` context + */ + uint64_t Cost = WasmEdge_StatisticsGetTotalCost(StatCxt); + WasmEdge_StatisticsDelete(StatCxt); + ``` + +## WasmEdge VM + +In this partition, we will introduce the functions of `WasmEdge_VMContext` object and show examples of executing WASM functions. + +### WASM Execution Example With VM Context + +The following shows the example of running the WASM for getting the Fibonacci. This example uses the [fibonacci.wat](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat). + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```wasm +(module + (export "fib" (func $fib)) + (func $fib (param $n i32) (result i32) + (if + (i32.lt_s (get_local $n)(i32.const 2)) + (return (i32.const 1)) + ) + (return + (i32.add + (call $fib (i32.sub (get_local $n)(i32.const 2))) + (call $fib (i32.sub (get_local $n)(i32.const 1))) + ) + ) + ) +) +``` + +1. Run WASM functions rapidly + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + #include + #include + int main() { + /* Create the configure context and add the WASI support. */ + /* This step is not necessary unless you need WASI support. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + /* The configure and store context to the VM creation can be NULL. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(5)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Run the WASM function from file. */ + WasmEdge_Result Res = WasmEdge_VMRunWasmFromFile( + VMCxt, "fibonacci.wasm", FuncName, Params, 1, Returns, 1); + /* + * Developers can run the WASM binary from buffer with the + * `WasmEdge_VMRunWasmFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMRunWasmFromASTModule()` API. + */ + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_ConfigureDelete(ConfCxt); + WasmEdge_StringDelete(FuncName); + return 0; + } + ``` + + Then you can compile and run: (the 5th Fibonacci number is 8 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 8 + ``` + +2. Instantiate and run WASM functions manually + + Besides the above example, developers can run the WASM functions step-by-step with `VM` context APIs: + + ```c + #include + #include + int main() { + /* Create the configure context and add the WASI support. */ + /* This step is not necessary unless you need the WASI support. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + /* The configure and store context to the VM creation can be NULL. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(10)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Step 1: Load WASM file. */ + Res = WasmEdge_VMLoadWasmFromFile(VMCxt, "fibonacci.wasm"); + /* + * Developers can load the WASM binary from buffer with the + * `WasmEdge_VMLoadWasmFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMLoadWasmFromASTModule()` API. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 2: Validate the WASM module. */ + Res = WasmEdge_VMValidate(VMCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 3: Instantiate the WASM module. */ + Res = WasmEdge_VMInstantiate(VMCxt); + /* + * Developers can load, validate, and instantiate another WASM module to + * replace the instantiated one. In this case, the old module will be + * cleared, but the registered modules are still kept. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Instantiation phase failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * Step 4: Execute WASM functions. You can execute functions repeatedly + * after instantiation. + */ + Res = WasmEdge_VMExecute(VMCxt, FuncName, Params, 1, Returns, 1); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_ConfigureDelete(ConfCxt); + WasmEdge_StringDelete(FuncName); + return 0; + } + ``` + + Then you can compile and run: (the 10th Fibonacci number is 89 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 89 + ``` + + The following graph explains the status of the `VM` context. + + ```text + |========================| + |------->| VM: Initiated | + | |========================| + | | + | LoadWasm + | | + | v + | |========================| + |--------| VM: Loaded |<-------| + | |========================| | + | | ^ | + | Validate | | + Cleanup | LoadWasm | + | v | LoadWasm + | |========================| | + |--------| VM: Validated | | + | |========================| | + | | ^ | + | Instantiate | | + | | RegisterModule | + | v | | + | |========================| | + |--------| VM: Instantiated |--------| + |========================| + | ^ + | | + -------------- + Instantiate, Execute, ExecuteRegistered + ``` + + The status of the `VM` context would be `Inited` when created. After loading WASM successfully, the status will be `Loaded`. After validating WASM successfully, the status will be `Validated`. After instantiating WASM successfully, the status will be `Instantiated`, and developers can invoke functions. Developers can register WASM or module instances in any status, but they should instantiate WASM again. Developers can also load WASM in any status, and they should validate and instantiate the WASM module before function invocation. When in the `Instantiated` status, developers can instantiate the WASM module again to reset the old WASM runtime structures. + +### VM Creations + +The `VM` creation API accepts the `Configure` context and the `Store` context. If developers only need the default settings, just pass `NULL` to the creation API. The details of the `Store` context will be introduced in [Store](#store). + +```c +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); +WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); +WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, StoreCxt); +/* The caller should guarantee the life cycle if the store context. */ +WasmEdge_StatisticsContext *StatCxt = WasmEdge_VMGetStatisticsContext(VMCxt); +/* + * The VM context already contains the statistics context and can be retrieved + * by this API. + */ +/* + * Note that the retrieved store and statistics contexts from the VM contexts by + * VM APIs should __NOT__ be destroyed and owned by the VM contexts. + */ +WasmEdge_VMDelete(VMCxt); +WasmEdge_StoreDelete(StoreCxt); +WasmEdge_ConfigureDelete(ConfCxt); +``` + +### Built-in Host Modules and Plug-in Preregistrations + +WasmEdge provides the following built-in host modules and plug-in pre-registrations. + +1. [WASI (WebAssembly System Interface)](https://github.com/WebAssembly/WASI) + + Developers can turn on the WASI support for VM in the `Configure` context. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + WasmEdge_ConfigureDelete(ConfCxt); + /* + * The following API can retrieve the built-in registered module instances + * from the VM context. + */ + /* + * This API will return `NULL` if the corresponding configuration is not set + * when creating the VM context. + */ + WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_VMGetImportModuleContext(VMCxt, + WasmEdge_HostRegistration_Wasi); + /* Initialize the WASI. */ + WasmEdge_ModuleInstanceInitWASI(WasiModule, /* ... ignored */); + WasmEdge_VMDelete(VMCxt); + ``` + + And also can create the WASI module instance from API. The details will be introduced in the [Host Functions](#host-functions) and the [Host Module Registrations](#host-module-registrations). + +2. Plug-ins + + There may be several plug-ins in the default plug-in paths if users [installed WasmEdge plug-ins by the installer](../../../start/install.md#install-wasmedge-plug-ins-and-dependencies). + + Before using the plug-ins, developers should [load the plug-ins from paths](#load-plug-ins-from-paths). + + The `VM` context will automatically create and register the module of the loaded plug-ins when creation. Furthermore, the following host modules will be mocked if the plug-in not loaded: + + - `wasi_ephemeral_crypto_asymmetric_common` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_common` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_kx` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_signatures` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_symmetric` (for the `WASI-Crypto`) + - `wasi_ephemeral_nn` + - `wasi_snapshot_preview1` + - `wasmedge_httpsreq` + - `wasmedge_process` + + When the WASM want to invoke these host functions but the corresponding plug-in not installed, WasmEdge will print the error message and return an error. + + ```c + /* Load the plug-ins in the default paths first. */ + WasmEdge_PluginLoadWithDefaultPaths(); + /* Create the configure context and add the WASI configuration. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + WasmEdge_ConfigureDelete(ConfCxt); + /* + * The following API can retrieve the registered modules in the VM context, + * includes the built-in WASI and the plug-ins. + */ + /* + * This API will return `NULL` if the module instance not found. + */ + WasmEdge_String WasiName = + WasmEdge_StringCreateByCString("wasi_snapshot_preview1"); + /* The `WasiModule` will not be `NULL` because the configuration was set. */ + const WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_VMGetRegisteredModule(VMCxt, WasiName); + WasmEdge_StringDelete(WasiName); + WasmEdge_String WasiNNName = + WasmEdge_StringCreateByCString("wasi_ephemeral_nn"); + /* + * The `WasiNNModule` will not be `NULL` even if the wasi_nn plug-in is not + * installed, because the VM context will mock and register the host + * modules. + */ + const WasmEdge_ModuleInstanceContext *WasiNNModule = + WasmEdge_VMGetRegisteredModule(VMCxt, WasiNNName); + WasmEdge_StringDelete(WasiNNName); + + WasmEdge_VMDelete(VMCxt); + ``` + +### Host Module Registrations + +[Host functions](https://webassembly.github.io/spec/core/exec/runtime.html#syntax-hostfunc) are functions outside WebAssembly and passed to WASM modules as imports. In WasmEdge, the host functions are composed into host modules as `WasmEdge_ModuleInstanceContext` objects with module names. Please refer to the [Host Functions in WasmEdge Runtime](#host-functions) for the details. + +In this chapter, we show the example for registering the host modules into a `VM` context. Noticed that the developers should guarantee the availability of the registered module instance, and should delete the module instance when it will not be used. + +```c +WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); +WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_ModuleInstanceCreateWASI(/* ... ignored ... */); +/* You can also create and register the WASI host modules by this API. */ +WasmEdge_Result Res = WasmEdge_VMRegisterModuleFromImport(VMCxt, WasiModule); +/* The result status should be checked. */ + +/* ... */ + +WasmEdge_VMDelete(VMCxt); +WasmEdge_ModuleInstanceDelete(WasiModule); +/* + * The created module instances should be deleted by the developers when the VM + * deallocation. + */ +``` + +### WASM Registrations And Executions + +In WebAssembly, the instances in WASM modules can be exported and can be imported by other WASM modules. WasmEdge VM provides APIs for developers to register and export any WASM modules, and execute the functions or host functions in the registered WASM modules. + +1. Register the WASM modules with exported module names + + Unless the module instances have already contained the module names, every WASM module should be named uniquely when registering. + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_Result Res = + WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + /* + * Developers can register the WASM module from buffer with the + * `WasmEdge_VMRegisterModuleFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMRegisterModuleFromASTModule()` API. + */ + /* + * The result status should be checked. + * The error will occur if the WASM module instantiation failed or the + * module name conflicts. + */ + WasmEdge_StringDelete(ModName); + WasmEdge_VMDelete(VMCxt); + ``` + +2. Execute the functions in registered WASM modules + + Assume that the C file `test.c` is as follows: + + ```c + #include + #include + int main() { + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(20)}; + WasmEdge_Value Returns[1]; + /* Names. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Register the WASM module into VM. */ + Res = WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + /* + * Developers can register the WASM module from buffer with the + * `WasmEdge_VMRegisterModuleFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMRegisterModuleFromASTModule()` API. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * The function "fib" in the "fibonacci.wasm" was exported with the module + * name "mod". As the same as host functions, other modules can import the + * function `"mod" "fib"`. + */ + + /* + * Execute WASM functions in registered modules. + * Unlike the execution of functions, the registered functions can be + * invoked without `WasmEdge_VMInstantiate()` because the WASM module was + * instantiated when registering. Developers can also invoke the host + * functions directly with this API. + */ + Res = WasmEdge_VMExecuteRegistered(VMCxt, ModName, FuncName, Params, 1, + Returns, 1); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + WasmEdge_StringDelete(ModName); + WasmEdge_StringDelete(FuncName); + WasmEdge_VMDelete(VMCxt); + return 0; + } + ``` + + Then you can compile and run: (the 20th Fibonacci number is 89 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 10946 + ``` + +3. Forcibly delete the registered WASM modules + + For instantiated and registered modules in VM context, developers can use the `WasmEdge_VMForceDeleteRegisteredModule()` API to forcibly delete and unregister the module instance by name. + + + :::note + This API doesn't check the module instance dependencies for exporting and importing. Developers should guarantee the module dependencies by theirselves when using this API. The safer API will be provided in the future. + ::: + + ```c + #include + #include + int main() { + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* Names. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Register the WASM module into VM. */ + Res = WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * The function "fib" in the "fibonacci.wasm" was exported with the module + * name "mod". As the same as host functions, other modules can import the + * function `"mod" "fib"`. + */ + + /* Forcibly delete the registered module. */ + WasmEdge_VMForceDeleteRegisteredModule(VMCxt, ModName); + + WasmEdge_StringDelete(ModName); + WasmEdge_StringDelete(FuncName); + WasmEdge_VMDelete(VMCxt); + return 0; + } + ``` + +### Asynchronous Execution + +1. Asynchronously run WASM functions rapidly + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + #include + #include + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(20)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Asynchronously run the WASM function from file and get the + * `WasmEdge_Async` object. */ + WasmEdge_Async *Async = WasmEdge_VMAsyncRunWasmFromFile( + VMCxt, "fibonacci.wasm", FuncName, Params, 1); + /* + * Developers can run the WASM binary from buffer with the + * `WasmEdge_VMAsyncRunWasmFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMAsyncRunWasmFromASTModule()` API. + */ + + /* Wait for the execution. */ + WasmEdge_AsyncWait(Async); + /* + * Developers can also use the `WasmEdge_AsyncGetReturnsLength()` or + * `WasmEdge_AsyncGet()` APIs to wait for the asynchronous execution. + * These APIs will wait until the execution finished. + */ + + /* Check the return values length. */ + uint32_t Arity = WasmEdge_AsyncGetReturnsLength(Async); + /* The `Arity` should be 1. Developers can skip this step if they have + * known the return arity. */ + + /* Get the result. */ + WasmEdge_Result Res = WasmEdge_AsyncGet(Async, Returns, Arity); + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_AsyncDelete(Async); + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + return 0; + } + ``` + + Then you can compile and run: (the 20th Fibonacci number is 10946 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 10946 + ``` + +2. Instantiate and asynchronously run WASM functions manually + + Besides the above example, developers can run the WASM functions step-by-step with `VM` context APIs: + + ```c + #include + #include + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(25)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Step 1: Load WASM file. */ + Res = WasmEdge_VMLoadWasmFromFile(VMCxt, "fibonacci.wasm"); + /* + * Developers can load the WASM binary from buffer with the + * `WasmEdge_VMLoadWasmFromBytes()` API, or from `WasmEdge_ASTModuleContext` + * object with the `WasmEdge_VMLoadWasmFromASTModule()` API. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 2: Validate the WASM module. */ + Res = WasmEdge_VMValidate(VMCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 3: Instantiate the WASM module. */ + Res = WasmEdge_VMInstantiate(VMCxt); + /* + * Developers can load, validate, and instantiate another WASM module to + * replace the instantiated one. In this case, the old module will be + * cleared, but the registered modules are still kept. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Instantiation phase failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 4: Asynchronously execute the WASM function and get the + * `WasmEdge_Async` object. */ + WasmEdge_Async *Async = + WasmEdge_VMAsyncExecute(VMCxt, FuncName, Params, 1); + /* + * Developers can execute functions repeatedly after instantiation. + * For invoking the registered functions, you can use the + * `WasmEdge_VMAsyncExecuteRegistered()` API. + */ + + /* Wait and check the return values length. */ + uint32_t Arity = WasmEdge_AsyncGetReturnsLength(Async); + /* The `Arity` should be 1. Developers can skip this step if they have + * known the return arity. */ + + /* Get the result. */ + Res = WasmEdge_AsyncGet(Async, Returns, Arity); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_AsyncDelete(Async); + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + } + ``` + + Then you can compile and run: (the 25th Fibonacci number is 121393 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 121393 + ``` + +### Instance Tracing + +Sometimes the developers may have requirements to get the instances of the WASM runtime. The `VM` context supplies the APIs to retrieve the instances. + +1. Store + + If the `VM` context is created without assigning a `Store` context, the `VM` context will allocate and own a `Store` context. + + ```c + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + WasmEdge_StoreContext *StoreCxt = WasmEdge_VMGetStoreContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_StoreDelete()`. */ + WasmEdge_VMDelete(VMCxt); + ``` + + Developers can also create the `VM` context with a `Store` context. In this case, developers should guarantee the life cycle of the `Store` context. Please refer to the [Store Contexts](#store) for the details about the `Store` context APIs. + + ```c + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, StoreCxt); + WasmEdge_StoreContext *StoreCxtMock = WasmEdge_VMGetStoreContext(VMCxt); + /* The `StoreCxt` and the `StoreCxtMock` are the same. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StoreDelete(StoreCxt); + ``` + +2. List exported functions + + After the WASM module instantiation, developers can use the `WasmEdge_VMExecute()` API to invoke the exported WASM functions. For this purpose, developers may need information about the exported WASM function list. Please refer to the [Instances in runtime](#instances) for the details about the function types. + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + #include + #include + int main() { + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, StoreCxt); + + WasmEdge_VMLoadWasmFromFile(VMCxt, "fibonacci.wasm"); + WasmEdge_VMValidate(VMCxt); + WasmEdge_VMInstantiate(VMCxt); + + /* List the exported functions. */ + /* Get the number of exported functions. */ + uint32_t FuncNum = WasmEdge_VMGetFunctionListLength(VMCxt); + /* Create the name buffers and the function type buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String FuncNames[BUF_LEN]; + WasmEdge_FunctionTypeContext *FuncTypes[BUF_LEN]; + /* + * Get the export function list. + * If the function list length is larger than the buffer length, the + * overflowed data will be discarded. The `FuncNames` and `FuncTypes` can + * be NULL if developers don't need them. + */ + uint32_t RealFuncNum = + WasmEdge_VMGetFunctionList(VMCxt, FuncNames, FuncTypes, BUF_LEN); + + for (uint32_t I = 0; I < RealFuncNum && I < BUF_LEN; I++) { + char Buf[BUF_LEN]; + uint32_t Size = WasmEdge_StringCopy(FuncNames[I], Buf, sizeof(Buf)); + printf("Get exported function string length: %u, name: %s\n", Size, + Buf); + /* + * The function names should be __NOT__ destroyed. + * The returned function type contexts should __NOT__ be destroyed. + */ + } + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_VMDelete(VMCxt); + return 0; + } + ``` + + Then you can compile and run: (the only exported function in `fibonacci.wasm` is `fib`) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get exported function string length: 3, name: fib + ``` + + If developers want to get the exported function names in the registered WASM modules, please retrieve the `Store` context from the `VM` context and refer to the APIs of [Store Contexts](#store) to list the registered functions by the module name. + +3. Get function types + + The `VM` context provides APIs to find the function type by function name. Please refer to the [Instances in runtime](#instances) for the details about the function types. + + ```c + /* + * ... + * Assume that a WASM module is instantiated in `VMCxt`. + */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + const WasmEdge_FunctionTypeContext *FuncType = + WasmEdge_VMGetFunctionType(VMCxt, FuncName); + /* + * Developers can get the function types of functions in the registered + * modules via the `WasmEdge_VMGetFunctionTypeRegistered()` API with the + * module name. If the function is not found, these APIs will return `NULL`. + * The returned function type contexts should __NOT__ be destroyed. + */ + WasmEdge_StringDelete(FuncName); + ``` + +4. Get the active module + + After the WASM module instantiation, an anonymous module is instantiated and owned by the `VM` context. Developers may need to retrieve it to get the instances beyond the module. Then developers can use the `WasmEdge_VMGetActiveModule()` API to get that anonymous module instance. Please refer to the [Module instance](#instances) for the details about the module instance APIs. + + ```c + /* + * ... + * Assume that a WASM module is instantiated in `VMCxt`. + */ + const WasmEdge_ModuleInstanceContext *ModCxt = + WasmEdge_VMGetActiveModule(VMCxt); + /* + * If there's no WASM module instantiated, this API will return `NULL`. + * The returned module instance context should __NOT__ be destroyed. + */ + ``` + +5. List and get the registered modules + + To list and retrieve the registered modules in the `VM` context, besides accessing the `store` context of the `VM`, developers can use the following APIs. + + ```c + /* + * ... + * Assume that the `VMCxt` is created. + */ + WasmEdge_String Names[32]; + uint32_t ModuleLen = WasmEdge_VMListRegisteredModule(VMCxt, Names, 32); + for (uint32_t I = 0; I < ModuleLen; I++) { + /* Will print the registered module names in the VM context. */ + printf("%s\n", Names[I].Buf); + } + + WasmEdge_String WasiName = + WasmEdge_StringCreateByCString("wasi_snapshot_preview1"); + /* The `WasiModule` will not be `NULL` because the configuration was set. */ + const WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_VMGetRegisteredModule(VMCxt, WasiName); + WasmEdge_StringDelete(WasiName); + ``` + +6. Get the components + + The `VM` context is composed by the `Loader`, `Validator`, and `Executor` contexts. For the developers who want to use these contexts without creating another instances, these APIs can help developers to get them from the `VM` context. The get contexts are owned by the `VM` context, and developers should not call their delete functions. + + ```c + WasmEdge_LoaderContext *LoadCxt = WasmEdge_VMGetLoaderContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_LoaderDelete()`. */ + WasmEdge_ValidatorContext *ValidCxt = WasmEdge_VMGetValidatorContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_ValidatorDelete()`. */ + WasmEdge_ExecutorContext *ExecCxt = WasmEdge_VMGetExecutorContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_ExecutorDelete()`. */ + ``` + +## WasmEdge Runtime + +In this partition, we will introduce the objects of WasmEdge runtime manually. + +### WASM Execution Example Step-By-Step + +Besides the WASM execution through the [`VM` context](#wasmedge-vm), developers can execute the WASM functions or instantiate WASM modules step-by-step with the `Loader`, `Validator`, `Executor`, and `Store` contexts. + +Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```c +#include +#include +int main() { + /* + * Create the configure context. This step is not necessary because we didn't + * adjust any setting. + */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* + * Create the statistics context. This step is not necessary if the statistics + * in runtime is not needed. + */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + /* Result. */ + WasmEdge_Result Res; + + /* Create the loader context. The configure context can be NULL. */ + WasmEdge_LoaderContext *LoadCxt = WasmEdge_LoaderCreate(ConfCxt); + /* Create the validator context. The configure context can be NULL. */ + WasmEdge_ValidatorContext *ValidCxt = WasmEdge_ValidatorCreate(ConfCxt); + /* + * Create the executor context. The configure context and the statistics + * context can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + + /* + * Load the WASM file or the compiled-WASM file and convert into the AST + * module context. + */ + WasmEdge_ASTModuleContext *ASTCxt = NULL; + Res = WasmEdge_LoaderParseFromFile(LoadCxt, &ASTCxt, "fibonacci.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Validate the WASM module. */ + Res = WasmEdge_ValidatorValidate(ValidCxt, ASTCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Instantiate the WASM module into store context. */ + WasmEdge_ModuleInstanceContext *ModCxt = NULL; + Res = WasmEdge_ExecutorInstantiate(ExecCxt, &ModCxt, StoreCxt, ASTCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Instantiation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + + /* Try to list the exported functions of the instantiated WASM module. */ + uint32_t FuncNum = WasmEdge_ModuleInstanceListFunctionLength(ModCxt); + /* Create the name buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String FuncNames[BUF_LEN]; + /* + * If the list length is larger than the buffer length, the overflowed data + * will be discarded. + */ + uint32_t RealFuncNum = + WasmEdge_ModuleInstanceListFunction(ModCxt, FuncNames, BUF_LEN); + for (uint32_t I = 0; I < RealFuncNum && I < BUF_LEN; I++) { + char Buf[BUF_LEN]; + uint32_t Size = WasmEdge_StringCopy(FuncNames[I], Buf, sizeof(Buf)); + printf("Get exported function string length: %u, name: %s\n", Size, Buf); + /* The function names should __NOT__ be destroyed. */ + } + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(18)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Find the exported function by function name. */ + WasmEdge_FunctionInstanceContext *FuncCxt = + WasmEdge_ModuleInstanceFindFunction(ModCxt, FuncName); + if (FuncCxt == NULL) { + printf("Function `fib` not found.\n"); + return 1; + } + /* Invoke the WASM function. */ + Res = WasmEdge_ExecutorInvoke(ExecCxt, FuncCxt, Params, 1, Returns, 1); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_StringDelete(FuncName); + WasmEdge_ASTModuleDelete(ASTCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + WasmEdge_LoaderDelete(LoadCxt); + WasmEdge_ValidatorDelete(ValidCxt); + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_ConfigureDelete(ConfCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_StatisticsDelete(StatCxt); + return 0; +} +``` + +Then you can compile and run: (the 18th Fibonacci number is 4181 in 0-based index) + +```bash +$ gcc test.c -lwasmedge +$ ./a.out +Get exported function string length: 3, name: fib +Get the result: 4181 +``` + +### Loader + +The `Loader` context loads the WASM binary from files or buffers. Both the WASM and the compiled-WASM from the [WasmEdge AOT Compiler](#wasmedge-aot-compiler) are supported. + +```c +uint8_t Buf[4096]; +/* ... Read the WASM code to the buffer. */ +uint32_t FileSize = ...; +/* The `FileSize` is the length of the WASM code. */ + +/* Developers can adjust settings in the configure context. */ +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); +/* Create the loader context. The configure context can be NULL. */ +WasmEdge_LoaderContext *LoadCxt = WasmEdge_LoaderCreate(ConfCxt); + +WasmEdge_ASTModuleContext *ASTCxt = NULL; +WasmEdge_Result Res; + +/* Load WASM or compiled-WASM from the file. */ +Res = WasmEdge_LoaderParseFromFile(LoadCxt, &ASTCxt, "fibonacci.wasm"); +if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} +/* The output AST module context should be destroyed. */ +WasmEdge_ASTModuleDelete(ASTCxt); + +/* Load WASM or compiled-WASM from the buffer. */ +WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(Buf, FileSize); +Res = WasmEdge_LoaderParseFromBytes(LoadCxt, &ASTCxt, Bytes); +/* + * Note: `WasmEdge_LoaderParseFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_LoaderParseFromBytes()` instead. + */ +if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} +/* The output AST module context should be destroyed. */ +WasmEdge_ASTModuleDelete(ASTCxt); + +WasmEdge_LoaderDelete(LoadCxt); +WasmEdge_ConfigureDelete(ConfCxt); +``` + +### Validator + +The `Validator` context can validate the WASM module. Every WASM module should be validated before instantiation. + +```c +/* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context. + * Assume that the `ConfCxt` is the configure context. + */ +/* Create the validator context. The configure context can be NULL. */ +WasmEdge_ValidatorContext *ValidCxt = WasmEdge_ValidatorCreate(ConfCxt); +WasmEdge_Result Res = WasmEdge_ValidatorValidate(ValidCxt, ASTCxt); +if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} +WasmEdge_ValidatorDelete(ValidCxt); +``` + +### Executor + +The `Executor` context is the executor for both WASM and compiled-WASM. This object should work base on the `Store` context. For the details of the `Store` context, please refer to the [next chapter](#store). + +1. Instantiate and register an `AST module` as a named `Module` instance + + As the same of [registering host modules](#host-module-registrations) or [importing WASM modules](#wasm-registrations-and-executions) in `VM` contexts, developers can instantiate an `AST module` contexts into a named `Module` instance, and register it into the `Store` context. After the registration, the result `Module` instance is exported to the `Store` with the given module name and can be linked when instantiating another module. + + For the details about the `Module` instances APIs, please refer to the [Instances](#instances). The `Store` context is only the linker for searching and linking the exported modules when instantiation. Developers should delete the output `Module` instance when it will no longer be used. When the `Module` instance being deleted, it will automatically unlink to all linked `Store` contexts. + + ```c + /* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context and has passed the validation. Assume that the `ConfCxt` is the + * configure context. + */ + /* Create the statistics context. This step is not necessary. */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the executor context. The configure and the statistics contexts + * can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = + WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + /* Result. */ + WasmEdge_Result Res; + + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + /* The output module instance. */ + WasmEdge_ModuleInstanceContext *ModCxt = NULL; + /* + * Register the WASM module into the store with the export module name + * "mod". + */ + Res = + WasmEdge_ExecutorRegister(ExecCxt, &ModCxt, StoreCxt, ASTCxt, ModName); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return -1; + } + WasmEdge_StringDelete(ModName); + + /* ... */ + + /* After the execution, the resources should be released. */ + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_StatisticsDelete(StatCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + ``` + +2. Register an existing `Module` instance and export the module name + + Besides instantiating and registering an `AST module` contexts, developers can register an existing `Module` instance into the store with exporting the module name (which is in the `Module` instance already). This case occurs when developers create a `Module` instance for the host functions and want to register it for linking. For the details about the construction of host functions in `Module` instances, please refer to the [Host Functions](#host-functions). + + ```c + /* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context and has passed the validation. Assume that the `ConfCxt` is the + * configure context. + */ + /* Create the statistics context. This step is not necessary. */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the executor context. The configure and the statistics contexts + * can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = + WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + /* Result. */ + WasmEdge_Result Res; + + /* Create a module instance for host functions. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("host-module"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ModName); + WasmEdge_StringDelete(ModName); + /* + * ... + * Create and add the host functions, tables, memories, and globals into the + * module instance. + */ + + /* Register the module instance into store with the exported module name. */ + /* The export module name is in the module instance already. */ + Res = WasmEdge_ExecutorRegisterImport(ExecCxt, StoreCxt, HostModCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return -1; + } + + /* ... */ + + /* After the execution, the resources should be released. */ + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_StatisticsDelete(StatCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + ``` + +3. Instantiate an `AST module` to an anonymous `Module` instance + + WASM or compiled-WASM modules should be instantiated before the function invocation. Before instantiating a WASM module, please check the [import section](https://webassembly.github.io/spec/core/syntax/modules.html#syntax-import) for ensuring the imports are registered into the `Store` context for linking. + + ```c + /* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context and has passed the validation. Assume that the `ConfCxt` is the + * configure context. + */ + /* Create the statistics context. This step is not necessary. */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the executor context. The configure and the statistics contexts + * can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = + WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + + /* The output module instance. */ + WasmEdge_ModuleInstanceContext *ModCxt = NULL; + /* Instantiate the WASM module. */ + WasmEdge_Result Res = + WasmEdge_ExecutorInstantiate(ExecCxt, &ModCxt, StoreCxt, ASTCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM instantiation failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return -1; + } + + /* ... */ + + /* After the execution, the resources should be released. */ + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_StatisticsDelete(StatCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + ``` + +4. Invoke functions + + After registering or instantiating and get the result `Module` instance, developers can retrieve the exported `Function` instances from the `Module` instance for invocation. For the details about the `Module` instances APIs, please refer to the [Instances](#instances). Please refer to the [example above](#wasm-execution-example-step-by-step) for the `Function` instance invocation with the `WasmEdge_ExecutorInvoke()` API. + +5. Asynchronously invoke functions + + Such as [executing WASM functions in VM asynchronously](#asynchronous-execution), developers can also invoke a function asynchronously by `Executor` contexts API. + + After getting the `Function` instance, developers will get the `Async` context by calling the `WasmEdge_ExecutorAsyncInvoke()` API. Please refer to the [Async](#async) chapter to work with this context for getting the results. + +### AST Module + +The `AST Module` context presents the loaded structure from a WASM file or buffer. Developer will get this object after loading a WASM file or buffer from [Loader](#loader). Before instantiation, developers can also query the imports and exports of an `AST Module` context. + +```c +WasmEdge_ASTModuleContext *ASTCxt = ...; +/* Assume that a WASM is loaded into an AST module context. */ + +/* Create the import type context buffers. */ +const uint32_t BUF_LEN = 256; +const WasmEdge_ImportTypeContext *ImpTypes[BUF_LEN]; +uint32_t ImportNum = WasmEdge_ASTModuleListImportsLength(ASTCxt); +/* + * If the list length is larger than the buffer length, the overflowed data will + * be discarded. + */ +uint32_t RealImportNum = + WasmEdge_ASTModuleListImports(ASTCxt, ImpTypes, BUF_LEN); +for (uint32_t I = 0; I < RealImportNum && I < BUF_LEN; I++) { + /* Working with the import type `ImpTypes[I]` ... */ +} + +/* Create the export type context buffers. */ +const WasmEdge_ExportTypeContext *ExpTypes[BUF_LEN]; +uint32_t ExportNum = WasmEdge_ASTModuleListExportsLength(ASTCxt); +/* + * If the list length is larger than the buffer length, the overflowed data will + * be discarded. + */ +uint32_t RealExportNum = + WasmEdge_ASTModuleListExports(ASTCxt, ExpTypes, BUF_LEN); +for (uint32_t I = 0; I < RealExportNum && I < BUF_LEN; I++) { + /* Working with the export type `ExpTypes[I]` ... */ +} + +WasmEdge_ASTModuleDelete(ASTCxt); +/* + * After deletion of `ASTCxt`, all data queried from the `ASTCxt` should not be + * accessed. + */ +``` + +### Serializer + +As the reversion of loading WASM file or buffer into a `AST Module`, the `Loader` context also provide the serializer to serialze the `AST Module` back into a WASM buffer. + +```c +WasmEdge_ASTModuleContext *ASTCxt = ...; +/* Assume that a WASM is loaded into an AST module context. */ + +WasmEdge_LoaderContext *LoadCxt = ...; +/* Assume that a loader context is created with configuration. */ + +WasmEdbe_Bytes Bytes; +/* Serialize the AST module back into WASM binary format. */ +Res = WasmEdge_LoaderSerializeASTModule(LoadCxt, ASTCxt, &Bytes); +if (!WasmEdge_ResultOK(Res)) { + printf("Serialization failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} + +/* The output WasmEdge_Bytes should be destroyed. */ +WasmEdge_BytesDelete(Bytes); +``` + +### Store + +[Store](https://webassembly.github.io/spec/core/exec/runtime.html#store) is the runtime structure for the representation of all global state that can be manipulated by WebAssembly programs. The `Store` context in WasmEdge is an object which present the linker to provide the instance exporting and importing when instantiating WASM modules. Developers can retrieve the named modules from the `Store` context, and should delete the `Module` instances registered into the `Store` context if they will not be used anymore. + +When the `Store` context being deleted, the linked `Module` instances will automatically unlink to this `Store` context. When a `Module` instance being deleted, it will automatically unlink to all the linked `Store` contexts. + +```c +WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + +/* + * ... + * Register a WASM module via the executor context. + */ + +/* Try to list the registered WASM modules. */ +uint32_t ModNum = WasmEdge_StoreListModuleLength(StoreCxt); +/* Create the name buffers. */ +const uint32_t BUF_LEN = 256; +WasmEdge_String ModNames[BUF_LEN]; +/* + * If the list length is larger than the buffer length, the overflowed data will + * be discarded. + */ +uint32_t RealModNum = WasmEdge_StoreListModule(StoreCxt, ModNames, BUF_LEN); +for (uint32_t I = 0; I < RealModNum && I < BUF_LEN; I++) { + /* Working with the module name `ModNames[I]` ... */ + /* The module names should __NOT__ be destroyed. */ +} + +/* Find named module by name. */ +WasmEdge_String ModName = WasmEdge_StringCreateByCString("module"); +const WasmEdge_ModuleInstanceContext *ModCxt = + WasmEdge_StoreFindModule(StoreCxt, ModName); +/* If the module with name not found, the `ModCxt` will be NULL. */ +WasmEdge_StringDelete(ModName); +``` + +### Instances + +The instances are the runtime structures of WASM. Developers can retrieve the `Module` instances from the `Store` contexts, and retrieve the other instances from the `Module` instances. A single instance can be allocated by its creation function. Developers can construct instances into an `Module` instance for registration. Please refer to the [Host Functions](#host-functions) for details. The instances created by their creation functions should be destroyed by developers, EXCEPT they are added into an `Module` instance. + +1. Module instance + + After instantiating or registering an `AST module` context, developers will get a `Module` instance as the result, and have the responsibility to destroy it when not in use. A `Module` instance can also be created for the host module. Please refer to the [host function](#host-functions) for the details. `Module` instance provides APIs to list and find the exported instances in the module. + + ```c + /* + * ... + * Instantiate a WASM module via the executor context and get the `ModCxt` + * as the output module instance. + */ + + /* Try to list the exported instance of the instantiated WASM module. */ + /* Take the function instances for example here. */ + uint32_t FuncNum = WasmEdge_ModuleInstanceListFunctionLength(ModCxt); + /* Create the name buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String FuncNames[BUF_LEN]; + /* + * If the list length is larger than the buffer length, the overflowed data + * will be discarded. + */ + uint32_t RealFuncNum = + WasmEdge_ModuleInstanceListFunction(ModCxt, FuncNames, BUF_LEN); + for (uint32_t I = 0; I < RealFuncNum && I < BUF_LEN; I++) { + /* Working with the function name `FuncNames[I]` ... */ + /* The function names should __NOT__ be destroyed. */ + } + + /* Try to find the exported instance of the instantiated WASM module. */ + /* Take the function instances for example here. */ + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + WasmEdge_FunctionInstanceContext *FuncCxt = + WasmEdge_ModuleInstanceFindFunction(ModCxt, FuncName); + /* `FuncCxt` will be `NULL` if the function not found. */ + /* + * The returned instance is owned by the module instance context and should + * __NOT__ be destroyed. + */ + WasmEdge_StringDelete(FuncName); + ``` + +2. Function instance + + [Host functions](https://webassembly.github.io/spec/core/exec/runtime.html#syntax-hostfunc) are functions outside WebAssembly and passed to WASM modules as imports. In WasmEdge, developers can create the `Function` contexts for host functions and add them into an `Module` instance context for registering into a `VM` or a `Store`. Developers can retrieve the `Function Type` from the `Function` contexts through the API. For the details of the `Host Function` guide, please refer to the [next chapter](#host-functions). + + ```c + /* Retrieve the function instance from the module instance context. */ + WasmEdge_FunctionInstanceContext *FuncCxt = ...; + WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_FunctionInstanceGetFunctionType(FuncCxt); + /* + * The `FuncTypeCxt` is owned by the `FuncCxt` and should __NOT__ be + * destroyed. + */ + + /* + * For the function instance creation, please refer to the `Host Function` + * guide. + */ + ``` + +3. Table instance + + In WasmEdge, developers can create the `Table` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. The `Table` contexts supply APIs to control the data in table instances. + + ```c + WasmEdge_Limit TabLimit = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + /* Create the table type with limit and the `FuncRef` element type. */ + WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_TableTypeCreate(WasmEdge_ValTypeGenFuncRef(), TabLimit); + /* Create the table instance with table type. */ + /* + * Developers can also use the `WasmEdge_TableInstanceCreateWithInit()` API to + * create the table instance with default reference values. + */ + WasmEdge_TableInstanceContext *HostTable = + WasmEdge_TableInstanceCreate(TabTypeCxt); + /* Delete the table type. */ + WasmEdge_TableTypeDelete(TabTypeCxt); + WasmEdge_Result Res; + WasmEdge_Value Data; + + const WasmEdge_TableTypeContext *GotTabTypeCxt = + WasmEdge_TableInstanceGetTableType(HostTable); + /* + * The `GotTabTypeCxt` got from table instance is owned by the `HostTable` and + * should __NOT__ be destroyed. + */ + WasmEdge_ValType RefType = WasmEdge_TableTypeGetRefType(GotGlobTypeCxt); + bool IsTypeFuncRef = WasmEdge_ValTypeIsFuncRef(RefType); + /* `IsTypeFuncRef` will be `TRUE`. */ + Data = WasmEdge_ValueGenFuncRef(5); + Res = WasmEdge_TableInstanceSetData(HostTable, Data, 3); + /* Set the function index 5 to the table[3]. */ + /* + * This will get an "out of bounds table access" error + * because the position (13) is out of the table size (10): + * Res = WasmEdge_TableInstanceSetData(HostTable, Data, 13); + */ + Res = WasmEdge_TableInstanceGetData(HostTable, &Data, 3); + /* Get the FuncRef value of the table[3]. */ + /* + * This will get an "out of bounds table access" error + * because the position (13) is out of the table size (10): + * Res = WasmEdge_TableInstanceGetData(HostTable, &Data, 13); + */ + + uint32_t Size = WasmEdge_TableInstanceGetSize(HostTable); + /* `Size` will be 10. */ + Res = WasmEdge_TableInstanceGrow(HostTable, 6); + /* Grow the table size of 6, the table size will be 16. */ + /* + * This will get an "out of bounds table access" error because + * the size (16 + 6) will reach the table limit(20): + * Res = WasmEdge_TableInstanceGrow(HostTable, 6); + */ + + WasmEdge_TableInstanceDelete(HostTable); + ``` + +4. Memory instance + + In WasmEdge, developers can create the `Memory` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. The `Memory` contexts supply APIs to control the data in memory instances. + + ```c + WasmEdge_Limit MemLimit = { + .HasMax = true, .Shared = false, .Min = 1, .Max = 5}; + /* Create the memory type with limit. The memory page size is 64KiB. */ + WasmEdge_MemoryTypeContext *MemTypeCxt = + WasmEdge_MemoryTypeCreate(MemLimit); + /* Create the memory instance with memory type. */ + WasmEdge_MemoryInstanceContext *HostMemory = + WasmEdge_MemoryInstanceCreate(MemTypeCxt); + /* Delete the memory type. */ + WasmEdge_MemoryTypeDelete(MemTypeCxt); + WasmEdge_Result Res; + uint8_t Buf[256]; + + Buf[0] = 0xAA; + Buf[1] = 0xBB; + Buf[2] = 0xCC; + Res = WasmEdge_MemoryInstanceSetData(HostMemory, Buf, 0x1000, 3); + /* Set the data[0:2] to the memory[4096:4098]. */ + /* + * This will get an "out of bounds memory access" error + * because [65535:65537] is out of 1 page size (65536): + * Res = WasmEdge_MemoryInstanceSetData(HostMemory, Buf, 0xFFFF, 3); + */ + Buf[0] = 0; + Buf[1] = 0; + Buf[2] = 0; + Res = WasmEdge_MemoryInstanceGetData(HostMemory, Buf, 0x1000, 3); + /* Get the memory[4096:4098]. Buf[0:2] will be `{0xAA, 0xBB, 0xCC}`. */ + /* + * This will get an "out of bounds memory access" error + * because [65535:65537] is out of 1 page size (65536): + * Res = WasmEdge_MemoryInstanceSetData(HostMemory, Buf, 0xFFFF, 3); + */ + + uint32_t PageSize = WasmEdge_MemoryInstanceGetPageSize(HostMemory); + /* `PageSize` will be 1. */ + Res = WasmEdge_MemoryInstanceGrowPage(HostMemory, 2); + /* Grow the page size of 2, the page size of the memory instance will be 3. */ + /* + * This will get an "out of bounds memory access" error because + * the page size (3 + 3) will reach the memory limit(5): + * Res = WasmEdge_MemoryInstanceGrowPage(HostMemory, 3); + */ + + WasmEdge_MemoryInstanceDelete(HostMemory); + ``` + +5. Tag instance + + Unlike the other instances, the `Tag` contexts are only available and can be retrieved from a `Module` instance context when turning on the `Exception Handling` proposal. Developers can retrieve the `Tag Type` from the instance. + + ```c + /* + * ... + * Instantiate a WASM module with exception handling instructions via the + * executor context and get the `ModCxt` as the output module instance. + */ + + /* Try to list the exported tag instance of the instantiated WASM module. */ + uint32_t TagNum = WasmEdge_ModuleInstanceListTagLength(ModCxt); + /* Create the name buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String TagNames[BUF_LEN]; + /* + * If the list length is larger than the buffer length, the overflowed data + * will be discarded. + */ + uint32_t RealTagNum = WasmEdge_ModuleInstanceListTag(ModCxt, TagNames, BUF_LEN); + for (uint32_t I = 0; I < RealTagNum && I < BUF_LEN; I++) { + /* Working with the tag name `TagNames[I]` ... */ + /* The function names should __NOT__ be destroyed. */ + } + + /* Try to find the exported tag instance of the instantiated WASM module. */ + WasmEdge_String TagName = WasmEdge_StringCreateByCString("tag-1"); + WasmEdge_TagInstanceContext *TagCxt = + WasmEdge_ModuleInstanceFindTag(ModCxt, TagName); + /* `TagCxt` will be `NULL` if the tag not found. */ + /* + * The returned instance is owned by the module instance context and should + * __NOT__ be destroyed. + */ + + /* Try to retrieve the tag type from the tag instance. */ + const WasmEdge_TagTypeContext *TagTypeCxt = + WasmEdge_TagInstanceGetTagType(TagCxt); + /* + * The returned tag type context is owned by the tag instance context and should + * __NOT__ be destroyed. + */ + + WasmEdge_StringDelete(TagName); + ``` + +6. Global instance + + In WasmEdge, developers can create the `Global` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. The `Global` contexts supply APIs to control the value in global instances. + + ```c + WasmEdge_Value Val = WasmEdge_ValueGenI64(1000); + /* Create the global type with value type and mutation. */ + WasmEdge_GlobalTypeContext *GlobTypeCxt = WasmEdge_GlobalTypeCreate( + WasmEdge_ValTypeGenI64(), WasmEdge_Mutability_Var); + /* Create the global instance with value and global type. */ + WasmEdge_GlobalInstanceContext *HostGlobal = + WasmEdge_GlobalInstanceCreate(GlobTypeCxt, Val); + /* Delete the global type. */ + WasmEdge_GlobalTypeDelete(GlobTypeCxt); + WasmEdge_Result Res; + + const WasmEdge_GlobalTypeContext *GotGlobTypeCxt = + WasmEdge_GlobalInstanceGetGlobalType(HostGlobal); + /* + * The `GotGlobTypeCxt` got from global instance is owned by the `HostGlobal` + * and should __NOT__ be destroyed. + */ + WasmEdge_ValType ValType = WasmEdge_GlobalTypeGetValType(GotGlobTypeCxt); + bool IsTypeF64 = WasmEdge_ValTypeIsI64(ValType); + /* `ValType` will be `TRUE`. */ + enum WasmEdge_Mutability ValMut = + WasmEdge_GlobalTypeGetMutability(GotGlobTypeCxt); + /* `ValMut` will be `WasmEdge_Mutability_Var`. */ + + Res = WasmEdge_GlobalInstanceSetValue(HostGlobal, WasmEdge_ValueGenI64(888)); + /* + * Set the value u64(888) to the global. + * This function will return error if the value type mismatched or + * the global mutability is `WasmEdge_Mutability_Const`. + */ + WasmEdge_Value GlobVal = WasmEdge_GlobalInstanceGetValue(HostGlobal); + /* Get the value (888 now) of the global context. */ + + WasmEdge_GlobalInstanceDelete(HostGlobal); + ``` + +### Host Functions + +[Host functions](https://webassembly.github.io/spec/core/exec/runtime.html#syntax-hostfunc) are functions outside WebAssembly and passed to WASM modules as imports. In WasmEdge, developers can create the `Function`, `Memory`, `Table`, and `Global` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. + +1. Host function allocation + + Developers can define C functions with the following function signature as the host function body: + + ```c + typedef WasmEdge_Result (*WasmEdge_HostFunc_t)( + void *Data, const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *Params, WasmEdge_Value *Returns); + ``` + + The example of an `add` host function to add 2 `i32` values: + + ```c + WasmEdge_Result Add(void *, const WasmEdge_CallingFrameContext *, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + /* + * Params: {i32, i32} + * Returns: {i32} + * Developers should take care about the function type. + */ + /* Retrieve the value 1. */ + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + /* Retrieve the value 2. */ + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + /* Output value 1 is Val1 + Val2. */ + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + /* Return the status of success. */ + return WasmEdge_Result_Success; + } + ``` + + Then developers can create `Function` context with the host function body and the function type: + + ```c + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + /* Create a function type: {i32, i32} -> {i32}. */ + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + /* + * Create a function context with the function type and host function body. + * The `Cost` parameter can be 0 if developers do not need the cost + * measuring. + */ + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, NULL, 0); + /* + * The third parameter is the pointer to the additional data. + * Developers should guarantee the life cycle of the data, and it can be + * `NULL` if the external data is not needed. + */ + WasmEdge_FunctionTypeDelete(HostType); + + /* + * If the function instance is __NOT__ added into a module instance context, + * it should be deleted. + */ + WasmEdge_FunctionInstanceDelete(HostFunc); + ``` + +2. Calling frame context + + The `WasmEdge_CallingFrameContext` is the context to provide developers to access the module instance of the [frame on the top of the calling stack](https://webassembly.github.io/spec/core/exec/runtime.html#activations-and-frames). According to the [WASM spec](https://webassembly.github.io/spec/core/exec/instructions.html#function-calls), a frame with the module instance is pushed into the stack when invoking a function. Therefore, the host functions can access the module instance of the top frame to retrieve the memory instances to read/write data. + + ```c + WasmEdge_Result LoadOffset(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + /* Function type: {i32} -> {} */ + uint32_t Offset = (uint32_t)WasmEdge_ValueGetI32(In[0]); + uint32_t Num = 0; + + /* + * Get the 0-th memory instance of the module instance of the top frame on + * stack. + */ + WasmEdge_MemoryInstanceContext *MemCxt = + WasmEdge_CallingFrameGetMemoryInstance(CallFrameCxt, 0); + + WasmEdge_Result Res = + WasmEdge_MemoryInstanceGetData(MemCxt, (uint8_t *)(&Num), Offset, 4); + if (WasmEdge_ResultOK(Res)) { + printf("u32 at memory[%lu]: %lu\n", Offset, Num); + } else { + return Res; + } + return WasmEdge_Result_Success; + } + ``` + + Besides using the `WasmEdge_CallingFrameGetMemoryInstance()` API to get the memory instance by index in the module instance, developers can use the `WasmEdge_CallingFrameGetModuleInstance()` to get the module instance directly. Therefore, developers can retrieve the exported contexts by the `WasmEdge_ModuleInstanceContext` APIs. And also, developers can use the `WasmEdge_CallingFrameGetExecutor()` API to get the currently used executor context. + +3. User-defined error code of the host functions + + In host functions, WasmEdge provides `WasmEdge_Result_Success` to return success, `WasmEdge_Result_Terminate` to terminate the WASM execution, and `WasmEdge_Result_Fail` to return fail. WasmEdge also provides the usage of returning the user-specified codes. Developers can use the `WasmEdge_ResultGen()` API to generate the `WasmEdge_Result` with error code, and use the `WasmEdge_ResultGetCode()` API to get the error code. + + > Notice: The error code only supports 24-bit integer (0 ~ 16777216 in `uint32_t`). The values larger than 24-bit will be truncated. + + Assume that a simple WASM from the WAT is as following: + + ```wasm + (module + (type $t0 (func (param i32))) + (import "extern" "trap" (func $f-trap (type $t0))) + (func (export "trap") (param i32) + local.get 0 + call $f-trap) + ) + ``` + + And the `test.c` is as following: + + ```c + #include + #include + + /* Host function body definition. */ + WasmEdge_Result Trap(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val = WasmEdge_ValueGetI32(In[0]); + /* Return the error code from the param[0]. */ + return WasmEdge_ResultGen(WasmEdge_ErrCategory_UserLevelError, Val); + } + + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The WASM module buffer. */ + uint8_t WASM[] = {/* WASM header */ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + /* Type section */ + 0x01, 0x05, 0x01, + /* function type {i32} -> {} */ + 0x60, 0x01, 0x7F, 0x00, + /* Import section */ + 0x02, 0x0F, 0x01, + /* module name: "extern" */ + 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, + /* extern name: "trap" */ + 0x04, 0x74, 0x72, 0x61, 0x70, + /* import desc: func 0 */ + 0x00, 0x00, + /* Function section */ + 0x03, 0x02, 0x01, 0x00, + /* Export section */ + 0x07, 0x08, 0x01, + /* export name: "trap" */ + 0x04, 0x74, 0x72, 0x61, 0x70, + /* export desc: func 0 */ + 0x00, 0x01, + /* Code section */ + 0x0A, 0x08, 0x01, + /* code body */ + 0x06, 0x00, 0x20, 0x00, 0x10, 0x00, 0x0B}; + + /* Create the module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + WasmEdge_ValType ParamList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 1, NULL, 0); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Trap, NULL, 0); + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String HostFuncName = WasmEdge_StringCreateByCString("trap"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, HostFuncName, HostFunc); + WasmEdge_StringDelete(HostFuncName); + + WasmEdge_VMRegisterModuleFromImport(VMCxt, HostModCxt); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(5566)}; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("trap"); + /* Run the WASM function from memory. */ + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(WASM, sizeof(WASM)); + /* + * Note: `WasmEdge_VMRunWasmFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_VMRunWasmFromBytes()` instead. + */ + WasmEdge_Result Res = + WasmEdge_VMRunWasmFromBytes(VMCxt, Bytes, FuncName, Params, 1, NULL, 0); + + /* Get the result code and print. */ + printf("Get the error code: %u\n", WasmEdge_ResultGetCode(Res)); + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_ModuleInstanceDelete(HostModCxt); + return 0; + } + ``` + + Then you can compile and run: (giving the expected error code `5566`) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + [2022-08-26 15:06:40.384] [error] user defined failed: user defined error code, Code: 0x15be + [2022-08-26 15:06:40.384] [error] When executing function name: "trap" + Get the error code: 5566 + ``` + +4. Construct a module instance with host instances + + Besides creating a `Module` instance by registering or instantiating a WASM module, developers can create a `Module` instance with a module name and add the `Function`, `Memory`, `Table`, and `Global` instances into it with their exporting names. + + ```c + /* Host function body definition. */ + WasmEdge_Result Add(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + return WasmEdge_Result_Success; + } + + /* Create a module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("module"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + /* + * Developers can also use the WasmEdge_ModuleInstanceCreateWithData() to + * create the module instance with the data and its finalizer. It will be + * introduced later. + */ + WasmEdge_StringDelete(ExportName); + + /* Create and add a function instance into the module instance. */ + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, NULL, 0); + /* + * The third parameter is the pointer to the additional data object. + * Developers should guarantee the life cycle of the data, and it can be + * `NULL` if the external data is not needed. + */ + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("add"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, FuncName, HostFunc); + WasmEdge_StringDelete(FuncName); + + /* Create and add a table instance into the import object. */ + WasmEdge_Limit TableLimit = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + WasmEdge_TableTypeContext *HostTType = + WasmEdge_TableTypeCreate(WasmEdge_ValTypeGenFuncRef(), TableLimit); + WasmEdge_TableInstanceContext *HostTable = + WasmEdge_TableInstanceCreate(HostTType); + WasmEdge_TableTypeDelete(HostTType); + WasmEdge_String TableName = WasmEdge_StringCreateByCString("table"); + WasmEdge_ModuleInstanceAddTable(HostModCxt, TableName, HostTable); + WasmEdge_StringDelete(TableName); + + /* Create and add a memory instance into the import object. */ + WasmEdge_Limit MemoryLimit = { + .HasMax = true, .Shared = false, .Min = 1, .Max = 2}; + WasmEdge_MemoryTypeContext *HostMType = + WasmEdge_MemoryTypeCreate(MemoryLimit); + WasmEdge_MemoryInstanceContext *HostMemory = + WasmEdge_MemoryInstanceCreate(HostMType); + WasmEdge_MemoryTypeDelete(HostMType); + WasmEdge_String MemoryName = WasmEdge_StringCreateByCString("memory"); + WasmEdge_ModuleInstanceAddMemory(HostModCxt, MemoryName, HostMemory); + WasmEdge_StringDelete(MemoryName); + + /* Create and add a global instance into the module instance. */ + WasmEdge_GlobalTypeContext *HostGType = WasmEdge_GlobalTypeCreate( + WasmEdge_ValTypeGenI32(), WasmEdge_Mutability_Var); + WasmEdge_GlobalInstanceContext *HostGlobal = + WasmEdge_GlobalInstanceCreate(HostGType, WasmEdge_ValueGenI32(666)); + WasmEdge_GlobalTypeDelete(HostGType); + WasmEdge_String GlobalName = WasmEdge_StringCreateByCString("global"); + WasmEdge_ModuleInstanceAddGlobal(HostModCxt, GlobalName, HostGlobal); + WasmEdge_StringDelete(GlobalName); + + /* + * The module instance should be deleted. + * Developers should __NOT__ destroy the instances added into the module + * instance contexts. + */ + WasmEdge_ModuleInstanceDelete(HostModCxt); + ``` + +5. Specified module instance + + `WasmEdge_ModuleInstanceCreateWASI()` API can create and initialize the `WASI` module instance. + + Developers can create these module instance contexts and register them into the `Store` or `VM` contexts rather than adjust the settings in the `Configure` contexts. + + ```c + WasmEdge_ModuleInstanceContext *WasiModCxt = + WasmEdge_ModuleInstanceCreateWASI(/* ... ignored */); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + /* Register the WASI and WasmEdge_Process into the VM context. */ + WasmEdge_VMRegisterModuleFromImport(VMCxt, WasiModCxt); + /* Get the WASI exit code. */ + uint32_t ExitCode = WasmEdge_ModuleInstanceWASIGetExitCode(WasiModCxt); + /* + * The `ExitCode` will be EXIT_SUCCESS if the execution has no error. + * Otherwise, it will return with the related exit code. + */ + WasmEdge_VMDelete(VMCxt); + /* The module instances should be deleted. */ + WasmEdge_ModuleInstanceDelete(WasiModCxt); + ``` + +6. Example + + Assume that a simple WASM from the WAT is as following: + + ```wasm + (module + (type $t0 (func (param i32 i32) (result i32))) + (import "extern" "func-add" (func $f-add (type $t0))) + (func (export "addTwo") (param i32 i32) (result i32) + local.get 0 + local.get 1 + call $f-add) + ) + ``` + + And the `test.c` is as following: + + ```c + #include + #include + + /* Host function body definition. */ + WasmEdge_Result Add(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + printf("Host function \"Add\": %d + %d\n", Val1, Val2); + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + return WasmEdge_Result_Success; + } + + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The WASM module buffer. */ + uint8_t WASM[] = {/* WASM header */ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + /* Type section */ + 0x01, 0x07, 0x01, + /* function type {i32, i32} -> {i32} */ + 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, + /* Import section */ + 0x02, 0x13, 0x01, + /* module name: "extern" */ + 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, + /* extern name: "func-add" */ + 0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64, + /* import desc: func 0 */ + 0x00, 0x00, + /* Function section */ + 0x03, 0x02, 0x01, 0x00, + /* Export section */ + 0x07, 0x0A, 0x01, + /* export name: "addTwo" */ + 0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F, + /* export desc: func 0 */ + 0x00, 0x01, + /* Code section */ + 0x0A, 0x0A, 0x01, + /* code body */ + 0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B}; + + /* Create the module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, NULL, 0); + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String HostFuncName = WasmEdge_StringCreateByCString("func-add"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, HostFuncName, HostFunc); + WasmEdge_StringDelete(HostFuncName); + + WasmEdge_VMRegisterModuleFromImport(VMCxt, HostModCxt); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[2] = {WasmEdge_ValueGenI32(1234), + WasmEdge_ValueGenI32(5678)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("addTwo"); + /* Run the WASM function from memory. */ + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(WASM, sizeof(WASM)); + /* + * Note: `WasmEdge_VMRunWasmFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_VMRunWasmFromBytes()` instead. + */ + WasmEdge_Result Res = WasmEdge_VMRunWasmFromBytes(VMCxt, Bytes, FuncName, + Params, 2, Returns, 1); + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_ModuleInstanceDelete(HostModCxt); + return 0; + } + ``` + + Then you can compile and run: (the result of 1234 + 5678 is 6912) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Host function "Add": 1234 + 5678 + Get the result: 6912 + ``` + +7. Host Data Example + + Developers can set a external data object to the `Function` context, and access to the object in the function body. Assume that a simple WASM from the WAT is as following: + + ```wasm + (module + (type $t0 (func (param i32 i32) (result i32))) + (import "extern" "func-add" (func $f-add (type $t0))) + (func (export "addTwo") (param i32 i32) (result i32) + local.get 0 + local.get 1 + call $f-add) + ) + ``` + + And the `test.c` is as following: + + ```c + #include + #include + + /* Host function body definition. */ + WasmEdge_Result Add(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + printf("Host function \"Add\": %d + %d\n", Val1, Val2); + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + /* Also set the result to the data. */ + int32_t *DataPtr = (int32_t *)Data; + *DataPtr = Val1 + Val2; + return WasmEdge_Result_Success; + } + + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The WASM module buffer. */ + uint8_t WASM[] = {/* WASM header */ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + /* Type section */ + 0x01, 0x07, 0x01, + /* function type {i32, i32} -> {i32} */ + 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, + /* Import section */ + 0x02, 0x13, 0x01, + /* module name: "extern" */ + 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, + /* extern name: "func-add" */ + 0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64, + /* import desc: func 0 */ + 0x00, 0x00, + /* Function section */ + 0x03, 0x02, 0x01, 0x00, + /* Export section */ + 0x07, 0x0A, 0x01, + /* export name: "addTwo" */ + 0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F, + /* export desc: func 0 */ + 0x00, 0x01, + /* Code section */ + 0x0A, 0x0A, 0x01, + /* code body */ + 0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B}; + + /* The external data object: an integer. */ + int32_t Data; + + /* Create the module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, &Data, 0); + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String HostFuncName = WasmEdge_StringCreateByCString("func-add"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, HostFuncName, HostFunc); + WasmEdge_StringDelete(HostFuncName); + + WasmEdge_VMRegisterModuleFromImport(VMCxt, HostModCxt); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[2] = {WasmEdge_ValueGenI32(1234), + WasmEdge_ValueGenI32(5678)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("addTwo"); + /* Run the WASM function from memory. */ + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(WASM, sizeof(WASM)); + /* + * Note: `WasmEdge_VMRunWasmFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_VMRunWasmFromBytes()` instead. + */ + WasmEdge_Result Res = WasmEdge_VMRunWasmFromBytes(VMCxt, Bytes, FuncName, + Params, 2, Returns, 1); + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + printf("Data value: %d\n", Data); + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_ModuleInstanceDelete(HostModCxt); + return 0; + } + ``` + + Then you can compile and run: (the result of 1234 + 5678 is 6912) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Host function "Add": 1234 + 5678 + Get the result: 6912 + Data value: 6912 + ``` + +8. Host Data in Module Instance with Finalizer + + Besides setting host data into a host function, developers can set and move ownership of host data into a `Module` instance context with its finalizer. This may be useful when implementing the plug-ins. + + ```c + /* Struct definition. */ + typedef struct Point { + int X; + int Y; + } Point; + + /* Host function body definition. */ + WasmEdge_Result Print(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + Point *P = (Point *)In; + printf("Point: (%d, %d)\n", P->X, P->Y); + return WasmEdge_Result_Success; + } + + /* Finalizer definition. */ + void PointFinalizer(void *Data) { + if (Data) { + free((Point *)Data); + } + } + + /* Create a module instance with host data and its finalizer. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("module"); + Point *Data = (Point *)malloc(sizeof(Point)); + Data->X = 5; + Data->Y = -5; + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreateWithData(ExportName, Data, PointFinalizer); + /* + * When the `HostModCxt` being destroyed, the finalizer will be invoked and the + * `Data` will be its argument. + */ + WasmEdge_StringDelete(ExportName); + ``` + +### Plug-ins + +The WasmEdge plug-ins are the shared libraries to provide the WasmEdge runtime to load and create host module instances. With the plug-ins, the WasmEdge runtime can be extended more easily. + +#### Load plug-ins from paths + +To use the plug-ins, developers should load the plug-ins from paths first. + +```c +WasmEdge_PluginLoadWithDefaultPaths(); +``` + +After calling this API, the plug-ins in the default paths will be loaded. The default paths are: + +1. The path given in the environment variable `WASMEDGE_PLUGIN_PATH`. +2. The `../plugin/` directory related to the WasmEdge installation path. +3. The `./wasmedge/` directory under the library path if the WasmEdge is installed under the system directory (such as `/usr` and `/usr/local`). + +To load the plug-ins from a specific path or under a specific directory, developers can use this API: + +```c +WasmEdge_PluginLoadFromPath("PATH_TO_PLUGIN/plugin.so"); +``` + +#### Get the plug-in by name + +After loading the plug-ins, developers can list the loaded plug-in names. + +```c +WasmEdge_PluginLoadWithDefaultPaths(); +printf("Number of loaded plug-ins: %d\n", WasmEdge_PluginListPluginsLength()); + +WasmEdge_String Names[20]; +uint32_t NumPlugins = WasmEdge_PluginListPlugins(Names, 20); +for (int I = 0; I < NumPlugins; I++) { + printf("plug-in %d name: %s\n", I, Names[I].Buf); +} +``` + +And developers can retrieve the plug-in context by its name. + +```c +/* Assume that wasi_crypto plug-in is installed in the default plug-in path. */ +WasmEdge_PluginLoadWithDefaultPaths(); + +const char PluginName[] = "wasi_crypto"; +WasmEdge_String NameString = + WasmEdge_StringWrap(PluginName, strlen(PluginName)); +const WasmEdge_PluginContext *PluginCxt = WasmEdge_PluginFind(NameString); +``` + +#### Create the module instance from a plug-in + +With the plug-in context, developers can create the module instances by the module name. + +```c +/* Assume that the `PluginCxt` is the context to the wasi_crypto plug-in. */ + +/* List the available host modules in the plug-in. */ +WasmEdge_String Names[20]; +uint32_t ModuleLen = WasmEdge_PluginListModule(PluginCxt, Names, 20); +for (uint32_t I = 0; I < ModuleLen; I++) { + /* Will print the available host module names in the plug-in. */ + printf("%s\n", Names[I].Buf); +} +/* + * Will print here for the WASI-Crypto plug-in here: + * wasi_ephemeral_crypto_asymmetric_common + * wasi_ephemeral_crypto_common + * wasi_ephemeral_crypto_kx + * wasi_ephemeral_crypto_signatures + * wasi_ephemeral_crypto_symmetric + */ + +/* Create a module instance from the plug-in by the module name. */ +const char ModuleName[] = "wasi_ephemeral_crypto_common"; +WasmEdge_String NameString = + WasmEdge_StringWrap(ModuleName, strlen(ModuleName)); +WasmEdge_ModuleInstance *ModCxt = + WasmEdge_PluginCreateModule(PluginCxt, NameString); + +WasmEdge_ModuleInstanceDelete(ModCxt); +``` + +## WasmEdge AOT Compiler + +In this partition, we will introduce the WasmEdge AOT compiler and the options. + +WasmEdge runs the WASM files in interpreter mode, and WasmEdge also supports the AOT (ahead-of-time) mode running without modifying any code. The WasmEdge AOT (ahead-of-time) compiler compiles the WASM files for running in AOT mode which is much faster than interpreter mode. Developers can compile the WASM files into the compiled-WASM files in shared library format for universal WASM format for the AOT mode execution. + +### Compilation Example + +Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```c +#include +#include +int main() { + /* Create the configure context. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* ... Adjust settings in the configure context. */ + /* Result. */ + WasmEdge_Result Res; + + /* Create the compiler context. The configure context can be NULL. */ + WasmEdge_CompilerContext *CompilerCxt = WasmEdge_CompilerCreate(ConfCxt); + /* Compile the WASM file with input and output paths. */ + Res = WasmEdge_CompilerCompile(CompilerCxt, "fibonacci.wasm", + "fibonacci-aot.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("Compilation failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + + WasmEdge_CompilerDelete(CompilerCxt); + WasmEdge_ConfigureDelete(ConfCxt); + return 0; +} +``` + +Then you can compile and run (the output file is "fibonacci-aot.wasm"): + +```bash +$ gcc test.c -lwasmedge +$ ./a.out +[2021-07-02 11:08:08.651] [info] compile start +[2021-07-02 11:08:08.653] [info] verify start +[2021-07-02 11:08:08.653] [info] optimize start +[2021-07-02 11:08:08.670] [info] codegen start +[2021-07-02 11:08:08.706] [info] compile done +``` + +### Compiler Options + +Developers can set options for AOT compilers such as optimization level and output format: + +```c +/// AOT compiler optimization level enumeration. +enum WasmEdge_CompilerOptimizationLevel { + /// Disable as many optimizations as possible. + WasmEdge_CompilerOptimizationLevel_O0 = 0, + /// Optimize quickly without destroying debuggability. + WasmEdge_CompilerOptimizationLevel_O1, + /// Optimize for fast execution as much as possible without triggering + /// significant incremental compile time or code size growth. + WasmEdge_CompilerOptimizationLevel_O2, + /// Optimize for fast execution as much as possible. + WasmEdge_CompilerOptimizationLevel_O3, + /// Optimize for small code size as much as possible without triggering + /// significant incremental compile time or execution time slowdowns. + WasmEdge_CompilerOptimizationLevel_Os, + /// Optimize for small code size as much as possible. + WasmEdge_CompilerOptimizationLevel_Oz +}; + +/// AOT compiler output binary format enumeration. +enum WasmEdge_CompilerOutputFormat { + /// Native dynamic library format. + WasmEdge_CompilerOutputFormat_Native = 0, + /// WebAssembly with AOT compiled codes in custom sections. + WasmEdge_CompilerOutputFormat_Wasm +}; +``` + +Please refer to the [AOT compiler options configuration](#configurations) for details. + +## WasmEdge CLI Tools + +In this partition, we will introduce the C API for triggering the WasmEdge CLI tools. + +Besides executing the `wasmedge` and `wasmedgec` CLI tools, developers can trigger the WasmEdge CLI tools by WasmEdge C API. The API arguments are the same as the command line arguments of the CLI tools. + +### Runtime CLI + +The `WasmEdge_Driver_Tool()` API presents the same function as running the [`wasmedge run` command](../../../start/build-and-run/run.md). + +Noticed that this API presents the old `wasmedge` CLI tool, which is the same as the `wasmedge run` command. For the current unified `wasmedge` CLI, please refer to the [API below](#unified-cli). + +```c +#include +#include +int main(int argc, const char *argv[]) { + /* Run the WasmEdge runtime tool. */ + return WasmEdge_Driver_Tool(argc, argv); +} +``` + +### Compiler CLI + +The `WasmEdge_Driver_Compiler()` API presents the same function as running the [`wasmedge compile` tool](../../../start/build-and-run/aot.md). + +Noticed that this API presents the old `wasmedgec` CLI tool, which is the same as the `wasmedge compile` command. For the current unified `wasmedge` CLI, please refer to the [API below](#unified-cli). + +```c +#include +#include +int main(int argc, const char *argv[]) { + /* Run the WasmEdge AOT compiler. */ + return WasmEdge_Driver_Compiler(argc, argv); +} +``` + +### Unified CLI + +The `WasmEdge_Driver_UniTool()` API presents the same function as running the [`wasmedge` tool](../../../start/build-and-run/cli.md). + +```c +#include +#include +int main(int argc, const char *argv[]) { + /* Run the WasmEdge unified tool. */ + /* (Within both runtime and AOT compiler) */ + return WasmEdge_Driver_UniTool(argc, argv); +} +``` + +### CLI Helpers for Windows + +On Windows platforms, developers can use the `WasmEdge_Driver_ArgvCreate()` and `WasmEdge_Driver_ArgvDelete()` APIs to convert and handle the `UTF-8` command line arguments, or use the `WasmEdge_Driver_SetConsoleOutputCPtoUTF8()` API to set the console output code page to `UTF-8`. diff --git a/docs/embed/c/reference/0.9.x.md b/docs/embed/c/reference/0.9.x.md index 97672b13..4db958e2 100644 --- a/docs/embed/c/reference/0.9.x.md +++ b/docs/embed/c/reference/0.9.x.md @@ -1,5 +1,5 @@ --- -sidebar_position: 11 +sidebar_position: 15 --- # C API 0.9.1 Documentation diff --git a/docs/embed/c/reference/latest.md b/docs/embed/c/reference/latest.md index cc7b45da..a0ec8e6b 100644 --- a/docs/embed/c/reference/latest.md +++ b/docs/embed/c/reference/latest.md @@ -2,7 +2,7 @@ sidebar_position: 1 --- -# C API 0.14.1 Documentation +# C API 0.16.1 Documentation [WasmEdge C API](https://github.com/WasmEdge/WasmEdge/blob/master/include/api/wasmedge/wasmedge.h) denotes an interface to access the WasmEdge runtime at version `{{ wasmedge_version }}`. The following are the guides to working with the C APIs of WasmEdge. @@ -79,9 +79,54 @@ printf("WasmEdge version patch: %u\n", WasmEdge_VersionGetPatch()); ### Logging Settings -The `WasmEdge_LogSetErrorLevel()` and `WasmEdge_LogSetDebugLevel()` APIs can set the logging system to debug level or error level. By default, the error level is set, and the debug info is hidden. +1. Setting logging levels -Developers can also use the `WasmEdge_LogOff()` API to disable all logging. + The `WasmEdge_LogSetErrorLevel()` and `WasmEdge_LogSetDebugLevel()` APIs can set the logging system to debug level or error level. By default, the error level is set, and the debug info is hidden. + + Developers can set the logging level by the `WasmEdge_LogSetLevel()` API with the level enumeration: + + ```c + typedef enum WasmEdge_LogLevel { + WasmEdge_LogLevel_Trace, + WasmEdge_LogLevel_Debug, + WasmEdge_LogLevel_Info, + WasmEdge_LogLevel_Warn, + WasmEdge_LogLevel_Error, + WasmEdge_LogLevel_Critical, + } WasmEdge_LogLevel; + ``` + + Developers can also use the `WasmEdge_LogOff()` API to disable all logging. + +2. Logging callback + + For getting the detailed result or error message, WasmEdge provides the callback interface to register the customized callback function into the logging sink. + + Developers will get the message struct via the callback argument: + + ```c + typedef struct WasmEdge_LogMessage { + WasmEdge_String Message; + WasmEdge_String LoggerName; + WasmEdge_LogLevel Level; + time_t Time; + uint64_t ThreadId; + } WasmEdge_LogMessage; + ``` + + Developers can register the callback by the `WasmEdge_LogSetCallback()` API to receive the message when logging occurs. + + ```c + #include + void callback(const WasmEdge_LogMessage *Message) { + printf("Message: %s, LoggerName: %s\n", Message->Message.Buf, Message->LoggerName.Buf); + } + + int main() { + WasmEdge_LogSetCallback(callback); + return 0; + } + ``` ### Value Types @@ -627,7 +672,53 @@ After calling the [asynchronous execution APIs](#asynchronous-execution), develo The configuration context, `WasmEdge_ConfigureContext`, manages the configurations for `Loader`, `Validator`, `Executor`, `VM`, and `Compiler` contexts. Developers can adjust the settings about the proposals, VM host pre-registrations (such as `WASI`), and AOT compiler options, and then apply the `Configure` context to create the runtime contexts. -1. Proposals +1. Standard + + WasmEdge supports the WebAssembly standards from the oldest `1.0` versions. Developers can use the `WasmEdge_ConfigureSetWASMStandard()` API to assign the WASM standard in the `Configure` context. After assigning the WASM standard, the corresponding WASM proposals will be enabled or disabled, and all of the proposal settings will be overwritten. + + The following WASM standards are supported: + + ```c + enum WasmEdge_Standard { + WasmEdge_Standard_WASM_1, // WASM 1.0 + WasmEdge_Standard_WASM_2, // WASM 2.0 + WasmEdge_Standard_WASM_3, // WASM 3.0, default + } + ``` + + ```c + /* By default, the standard is WASM 3.0. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + + /* The `IsMultiRet` will be `TRUE`. */ + bool IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + + /* Remove the Multi-value returns proposal, which is in WASM 2.0. */ + WasmEdge_ConfigureRemoveProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + + /* The `IsMultiRet` will be `FALSE`. */ + IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + + /* Set the standard to WASM 2.0. All proposal settings is reset. */ + WasmEdge_ConfigureSetWASMStandard(ConfCxt, WasmEdge_Standard_WASM_2); + + /* The `IsMultiRet` will be `TRUE`. */ + IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + + /* Set the standard to WASM 1.0. All proposal settings is reset. */ + WasmEdge_ConfigureSetWASMStandard(ConfCxt, WasmEdge_Standard_WASM_1); + + /* The `IsMultiRet` will be `FALSE`. */ + IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +2. Proposals WasmEdge supports turning on or off the WebAssembly proposals. This configuration is effective in any contexts created with the `Configure` context. @@ -645,11 +736,11 @@ The configuration context, `WasmEdge_ConfigureContext`, manages the configuratio WasmEdge_Proposal_FunctionReferences, WasmEdge_Proposal_GC, WasmEdge_Proposal_MultiMemories, - WasmEdge_Proposal_Threads, WasmEdge_Proposal_RelaxSIMD, - WasmEdge_Proposal_Annotations, - WasmEdge_Proposal_Memory64, + WasmEdge_Proposal_Annotations, // NOT IMPLEMENTED WasmEdge_Proposal_ExceptionHandling, + WasmEdge_Proposal_Memory64, // NOT IMPLEMENTED + WasmEdge_Proposal_Threads, WasmEdge_Proposal_Component, }; ``` @@ -659,35 +750,39 @@ The configuration context, `WasmEdge_ConfigureContext`, manages the configuratio ```c /* * By default, the following proposals have turned on initially: - * * Import/Export of mutable globals - * * Non-trapping float-to-int conversions - * * Sign-extension operators - * * Multi-value returns - * * Bulk memory operations - * * Reference types - * * Fixed-width SIMD + * * WASM 1.0 Proposals: + * * Import/Export of mutable globals + * * WASM 2.0 Proposals: + * * Non-trapping float-to-int conversions + * * Sign-extension operators + * * Multi-value returns + * * Bulk memory operations + * * Reference types + * * Fixed-width SIMD + * * WASM 3.0 Proposals: + * * Tail-call + * * Extended-const + * * Typed-function references + * * GC + * * Multiple memories + * * Relaxed SIMD + * * Exception handling (interpreter only) * * For the current WasmEdge version, the following proposals are supported * (turned off by default) additionally: - * * Tail-call - * * Extended-const - * * Typed-function references - * * GC (interpreter only) - * * Multiple memories * * Threads - * * Exception handling (interpreter only) * * Component model (loader phase only) */ WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); - WasmEdge_ConfigureAddProposal(ConfCxt, WasmEdge_Proposal_MultiMemories); - WasmEdge_ConfigureRemoveProposal(ConfCxt, WasmEdge_Proposal_ReferenceTypes); + WasmEdge_ConfigureAddProposal(ConfCxt, WasmEdge_Proposal_Threads); + WasmEdge_ConfigureRemoveProposal(ConfCxt, WasmEdge_Proposal_GC); bool IsBulkMem = WasmEdge_ConfigureHasProposal( ConfCxt, WasmEdge_Proposal_BulkMemoryOperations); /* The `IsBulkMem` will be `TRUE`. */ WasmEdge_ConfigureDelete(ConfCxt); ``` -2. Host registrations +3. Host registrations This configuration is used for the `VM` context to turn on the `WASI` supports and only effective in `VM` contexts. @@ -714,7 +809,7 @@ The configuration context, `WasmEdge_ConfigureContext`, manages the configuratio WasmEdge_ConfigureDelete(ConfCxt); ``` -3. Maximum memory pages +4. Maximum memory pages Developers can limit the page size of memory instances by this configuration. When growing the page size of memory instances in WASM execution and exceeding the limited size, the page growing will fail. This configuration is only effective in the `Executor` and `VM` contexts. @@ -732,7 +827,7 @@ The configuration context, `WasmEdge_ConfigureContext`, manages the configuratio WasmEdge_ConfigureDelete(ConfCxt); ``` -4. Forcibly interpreter mode +5. Forcibly interpreter mode If developers want to execute the WASM file or the AOT compiled WASM in interpreter mode forcibly, they can turn on the configuration. @@ -746,7 +841,7 @@ The configuration context, `WasmEdge_ConfigureContext`, manages the configuratio WasmEdge_ConfigureDelete(ConfCxt); ``` -5. AOT compiler options +6. AOT compiler options The AOT compiler options configure the behavior about optimization level, output format, dump IR, and generic binary. @@ -797,7 +892,7 @@ The configuration context, `WasmEdge_ConfigureContext`, manages the configuratio WasmEdge_ConfigureDelete(ConfCxt); ``` -6. Statistics options +7. Statistics options The statistics options configure the behavior about instruction counting, cost measuring, and time measuring in both runtime and AOT compiler. These configurations are effective in `Compiler`, `VM`, and `Executor` contexts. @@ -1316,6 +1411,50 @@ In WebAssembly, the instances in WASM modules can be exported and can be importe Get the result: 10946 ``` +3. Forcibly delete the registered WASM modules + + For instantiated and registered modules in VM context, developers can use the `WasmEdge_VMForceDeleteRegisteredModule()` API to forcibly delete and unregister the module instance by name. + + + :::note + This API doesn't check the module instance dependencies for exporting and importing. Developers should guarantee the module dependencies by theirselves when using this API. The safer API will be provided in the future. + ::: + + ```c + #include + #include + int main() { + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* Names. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Register the WASM module into VM. */ + Res = WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * The function "fib" in the "fibonacci.wasm" was exported with the module + * name "mod". As the same as host functions, other modules can import the + * function `"mod" "fib"`. + */ + + /* Forcibly delete the registered module. */ + WasmEdge_VMForceDeleteRegisteredModule(VMCxt, ModName); + + WasmEdge_StringDelete(ModName); + WasmEdge_StringDelete(FuncName); + WasmEdge_VMDelete(VMCxt); + return 0; + } + ``` + ### Asynchronous Execution 1. Asynchronously run WASM functions rapidly diff --git a/docs/embed/c/reference/upgrade_to_0.10.0.md b/docs/embed/c/reference/upgrade_to_0.10.0.md index c76cb059..4ccfeefa 100644 --- a/docs/embed/c/reference/upgrade_to_0.10.0.md +++ b/docs/embed/c/reference/upgrade_to_0.10.0.md @@ -1,5 +1,5 @@ --- -sidebar_position: 10 +sidebar_position: 14 --- # Upgrade to WasmEdge 0.10.0 diff --git a/docs/embed/c/reference/upgrade_to_0.11.0.md b/docs/embed/c/reference/upgrade_to_0.11.0.md index a35e6626..c5b3f14a 100644 --- a/docs/embed/c/reference/upgrade_to_0.11.0.md +++ b/docs/embed/c/reference/upgrade_to_0.11.0.md @@ -1,5 +1,5 @@ --- -sidebar_position: 8 +sidebar_position: 12 --- # Upgrade to WasmEdge 0.11.0 diff --git a/docs/embed/c/reference/upgrade_to_0.12.0.md b/docs/embed/c/reference/upgrade_to_0.12.0.md index 145cb438..2dbdf372 100644 --- a/docs/embed/c/reference/upgrade_to_0.12.0.md +++ b/docs/embed/c/reference/upgrade_to_0.12.0.md @@ -1,5 +1,5 @@ --- -sidebar_position: 6 +sidebar_position: 10 --- # Upgrade to WasmEdge 0.12.0 diff --git a/docs/embed/c/reference/upgrade_to_0.13.0.md b/docs/embed/c/reference/upgrade_to_0.13.0.md index 2af7211f..09622731 100644 --- a/docs/embed/c/reference/upgrade_to_0.13.0.md +++ b/docs/embed/c/reference/upgrade_to_0.13.0.md @@ -1,5 +1,5 @@ --- -sidebar_position: 4 +sidebar_position: 8 --- # Upgrade to WasmEdge 0.13.0 diff --git a/docs/embed/c/reference/upgrade_to_0.14.0.md b/docs/embed/c/reference/upgrade_to_0.14.0.md index 24b71144..9fefbc83 100644 --- a/docs/embed/c/reference/upgrade_to_0.14.0.md +++ b/docs/embed/c/reference/upgrade_to_0.14.0.md @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 6 --- # Upgrade to WasmEdge 0.14.0 diff --git a/docs/embed/c/reference/upgrade_to_0.15.0.md b/docs/embed/c/reference/upgrade_to_0.15.0.md new file mode 100644 index 00000000..7ed35c5e --- /dev/null +++ b/docs/embed/c/reference/upgrade_to_0.15.0.md @@ -0,0 +1,118 @@ +--- +sidebar_position: 4 +--- + +# Upgrade to WasmEdge 0.15.0 + +Due to the WasmEdge C API breaking changes, this document shows the guideline for programming with WasmEdge C API to upgrade from the `0.14.1` to the `0.15.0` version. + +## Concepts + +1. Introduced new APIs for logging. + + Besides the `WasmEdge_LogSetErrorLevel()` and `WasmEdge_LogSetDebugLevel()` APIs, developers can use the `WasmEdge_LogSetLevel()` API to set the logging level. + + On the other hand, developers can use the `WasmEdge_LogSetCallback()` API to set the callback to receive the message struct when logging occurs. + +2. Introduced new API for forcibly deleting registered modules. + + Developers can use the `WasmEdge_VMForceDeleteRegisteredModule()` API to delete the registered modules in the VM context. + + This API provides the force deletion of module instance. After invoking this API, the module instance will be deleted. Developers should consider the module dependency when using this API. + +## Logging Level and Callback Configuration + +Developers can set the logging level by the `WasmEdge_LogSetLevel()` API with the level enumeration: + +```c +typedef enum WasmEdge_LogLevel { + WasmEdge_LogLevel_Trace, + WasmEdge_LogLevel_Debug, + WasmEdge_LogLevel_Info, + WasmEdge_LogLevel_Warn, + WasmEdge_LogLevel_Error, + WasmEdge_LogLevel_Critical, +} WasmEdge_LogLevel; +``` + +For getting the detailed result or error message, WasmEdge provides the callback interface to register the customized callback function into the logging sink. Developers will get the message struct via the callback argument: + +```c +typedef struct WasmEdge_LogMessage { + WasmEdge_String Message; + WasmEdge_String LoggerName; + WasmEdge_LogLevel Level; + time_t Time; + uint64_t ThreadId; +} WasmEdge_LogMessage; +``` + +Developers can register the callback by the `WasmEdge_LogSetCallback()` API to receive the message when logging occurs. + +```c +#include +void callback(const WasmEdge_LogMessage *Message) { + printf("Message: %s, LoggerName: %s\n", Message->Message.Buf, Message->LoggerName.Buf); +} + +int main() { + WasmEdge_LogSetCallback(callback); + return 0; +} +``` + +## Module Instance Deletion in VM Context + +For instantiated and registered modules in VM context, developers can use the `WasmEdge_VMForceDeleteRegisteredModule()` API to forcibly delete and unregister the module instance by name. + + +:::note +This API doesn't check the module instance dependencies for exporting and importing. Developers should guarantee the module dependencies by theirselves when using this API. The safer API will be provided in the future. +::: + +Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```c +#include +#include +int main() { + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(20)}; + WasmEdge_Value Returns[1]; + /* Names. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Register the WASM module into VM. */ + Res = WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * The function "fib" in the "fibonacci.wasm" was exported with the module + * name "mod". As the same as host functions, other modules can import the + * function `"mod" "fib"`. + */ + + /* Forcibly delete the registered module. */ + WasmEdge_VMForceDeleteRegisteredModule(VMCxt, ModName); + + WasmEdge_StringDelete(ModName); + WasmEdge_StringDelete(FuncName); + WasmEdge_VMDelete(VMCxt); + return 0; +} +``` + +Noticed that this API will take the ownership of the module instance and delete it. If developers delete the module instance by this API which registered via the `WasmEdge_VMRegisterModuleFromImport()` API, the module instance should NOT be deleted again. diff --git a/docs/embed/c/reference/upgrade_to_0.16.0.md b/docs/embed/c/reference/upgrade_to_0.16.0.md new file mode 100644 index 00000000..b9ff0c34 --- /dev/null +++ b/docs/embed/c/reference/upgrade_to_0.16.0.md @@ -0,0 +1,83 @@ +--- +sidebar_position: 2 +--- + +# Upgrade to WasmEdge 0.16.0 + +Due to the WasmEdge C API breaking changes, this document shows the guideline for programming with WasmEdge C API to upgrade from the `0.15.1` to the `0.16.0` version. + +## Concepts + +1. Introduced new APIs for quickly assigning the WASM standards. + + Developers can use the `WasmEdge_ConfigureSetWASMStandard()` to quickly configure the WASM standard in the `Configure` context. + +## Set the WASM standards and proposals + +With the `WasmEdge_ConfigureSetWASMStandard()` API, the following WASM standards can be used for quickly configuration: + +```c +enum WasmEdge_Standard { + WasmEdge_Standard_WASM_1, // WASM 1.0 + WasmEdge_Standard_WASM_2, // WASM 2.0 + WasmEdge_Standard_WASM_3, // WASM 3.0, default +} +``` + +The `WASM 1.0` contains the basic WASM spec and the following proposal: + +* Import/Export of mutable globals + +The `WASM 2.0` contains the `WASM 1.0` and the following proposals: + +* Non-trapping float-to-int conversions +* Sign-extension operators +* Multi-value returns +* Bulk memory operations +* Reference types +* Fixed-width SIMD + +The `WASM 3.0` contains the `WASM 2.0` and the following proposals: + +* Tail-call +* Extended-const +* Typed-function references +* GC +* Multiple memories +* Relaxed SIMD +* Exception handling (interpreter only) +* Memory64 (not supported in WasmEdge yet) + +After assigning the WASM standard, the corresponding WASM proposals will be enabled or disabled, and all of the proposal settings will be overwritten. + +```c +/* By default, the standard is WASM 3.0. */ +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + +/* The `IsMultiRet` will be `TRUE`. */ +bool IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + +/* Remove the Multi-value returns proposal, which is in WASM 2.0. */ +WasmEdge_ConfigureRemoveProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + +/* The `IsMultiRet` will be `FALSE`. */ +IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + +/* Set the standard to WASM 2.0. All proposal settings is reset. */ +WasmEdge_ConfigureSetWASMStandard(ConfCxt, WasmEdge_Standard_WASM_2); + +/* The `IsMultiRet` will be `TRUE`. */ +IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + +/* Set the standard to WASM 1.0. All proposal settings is reset. */ +WasmEdge_ConfigureSetWASMStandard(ConfCxt, WasmEdge_Standard_WASM_1); + +/* The `IsMultiRet` will be `FALSE`. */ +IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + +WasmEdge_ConfigureDelete(ConfCxt); +``` diff --git a/docs/start/build-and-run/aot.md b/docs/start/build-and-run/aot.md index 657c1065..2ab2b3d5 100644 --- a/docs/start/build-and-run/aot.md +++ b/docs/start/build-and-run/aot.md @@ -34,6 +34,24 @@ The options of the `wasmedge compile` command are as follows. - Or use `--enable-all-statistics` to generate code for enabling all of the statistics. 5. _(Optional)_ `--generic-binary`: Generate the generic binary of the current host CPU architecture. 6. _(Optional)_ WebAssembly proposals: + - Use `--wasm-1` to set the compilation environment as WASM 1.0 standard. This standard includes the following proposals: + - [Import/Export of Mutable Globals](https://github.com/WebAssembly/mutable-global) + - Use `--wasm-2` to set the compilation environment as WASM 2.0 standard. This standard includes the WASM 1.0 and following proposals: + - [Non-Trapping Float-to-Int Conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) + - [Sign-Extension Operators](https://github.com/WebAssembly/sign-extension-ops) + - [Multi-value](https://github.com/WebAssembly/multi-value) + - [Bulk Memory Operations](https://github.com/WebAssembly/bulk-memory-operations) + - [Reference Types](https://github.com/WebAssembly/reference-types) + - [Fixed-width SIMD](https://github.com/webassembly/simd) + - Use `--wasm-3` to set the compilation environment as WASM 3.0 standard (Currently default since 0.16.0). This standard includes the WASM 2.0 and following proposals: + - [Tail call](https://github.com/WebAssembly/tail-call) + - [Extended Constant Expressions](https://github.com/WebAssembly/extended-const) + - [Typed-Function References](https://github.com/WebAssembly/function-references) + - [Garbage Collection](https://github.com/WebAssembly/gc) + - [Multiple Memories](https://github.com/WebAssembly/multi-memory) + - [Relaxed SIMD](https://github.com/webassembly/relaxed-simd) + - [Exception Handling (currently not implemented)](https://github.com/WebAssembly/exception-handling) + - [Memory64 (currently not implemented)](https://github.com/WebAssembly/memory64) - Use `--disable-import-export-mut-globals` to disable the [Import/Export of Mutable Globals](https://github.com/WebAssembly/mutable-global) proposal (Default `ON`). - Use `--disable-non-trap-float-to-int` to disable the [Non-Trapping Float-to-Int Conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) proposal (Default `ON`). - Use `--disable-sign-extension-operators` to disable the [Sign-Extension Operators](https://github.com/WebAssembly/sign-extension-ops) proposal (Default `ON`). @@ -41,11 +59,19 @@ The options of the `wasmedge compile` command are as follows. - Use `--disable-bulk-memory` to disable the [Bulk Memory Operations](https://github.com/WebAssembly/bulk-memory-operations) proposal (Default `ON`). - Use `--disable-reference-types` to disable the [Reference Types](https://github.com/WebAssembly/reference-types) proposal (Default `ON`). - Use `--disable-simd` to disable the [Fixed-width SIMD](https://github.com/webassembly/simd) proposal (Default `ON`). - - Use `--enable-multi-memory` to enable the [Multiple Memories](https://github.com/WebAssembly/multi-memory) proposal (Default `OFF`). - - Use `--enable-tail-call` to enable the [Tail call](https://github.com/WebAssembly/tail-call) proposal (Default `OFF`). - - Use `--enable-extended-const` to enable the [Extended Constant Expressions](https://github.com/WebAssembly/extended-const) proposal (Default `OFF`). + - Use `--disable-tail-call` to disable the [Tail call](https://github.com/WebAssembly/tail-call) proposal (Default `ON`). + - Use `--disable-extended-const` to disable the [Extended Constant Expressions](https://github.com/WebAssembly/extended-const) proposal (Default `ON`). + - Use `--disable-function-reference` to disable the [Typed-Function References](https://github.com/WebAssembly/function-references) proposal (Default `ON`). + - Use `--disable-gc` to disable the [Garbage Collection](https://github.com/WebAssembly/gc) proposal (Default `ON`). + - Use `--disable-multi-memory` to disable the [Multiple Memories](https://github.com/WebAssembly/multi-memory) proposal (Default `ON`). + - Use `--disable-relaxed-simd` to disable the [Relaxed SIMD](https://github.com/webassembly/relaxed-simd) proposal (Default `ON`). + - DEPRECATED: Use `--enable-tail-call` to enable the [Tail call](https://github.com/WebAssembly/tail-call) proposal. + - DEPRECATED: Use `--enable-extended-const` to enable the [Extended Constant Expressions](https://github.com/WebAssembly/extended-const) proposal. + - DEPRECATED: Use `--enable-function-reference` to enable the [Typed-Function References](https://github.com/WebAssembly/function-references) proposal. + - DEPRECATED: Use `--enable-gc` to enable the [GC](https://github.com/WebAssembly/gc) proposal. + - DEPRECATED: Use `--enable-multi-memory` to enable the [Multiple Memories](https://github.com/WebAssembly/multi-memory) proposal. + - DEPRECATED: Use `--enable-relaxed-simd` to enable the [Relaxed SIMD](https://github.com/webassembly/relaxed-simd) proposal. - Use `--enable-threads` to enable the [Threads](https://github.com/webassembly/threads) proposal (Default `OFF`). - - Use `--enable-function-reference` to enable the [Typed-Function References](https://github.com/WebAssembly/function-references) proposal (Default `OFF`). - Use `--enable-all` to enable ALL proposals above. 7. _(Optional)_ `--optimize`: Select the LLVM optimization level. - Use `--optimize LEVEL` to set the optimization level. The `LEVEL` should be one of `0`, `1`, `2`, `3`, `s`, or `z`. diff --git a/docs/start/build-and-run/cli.md b/docs/start/build-and-run/cli.md index 508a7ee5..e578ceac 100644 --- a/docs/start/build-and-run/cli.md +++ b/docs/start/build-and-run/cli.md @@ -62,6 +62,24 @@ The options of the `wasmedge` CLI tool are as follows: - Use `--force-interpreter` to forcibly run WASM in interpreter mode. - Use `--enable-jit` to enable Just-In-Time compiler for running WASM. 9. _(Optional)_ WebAssembly proposals: + - Use `--wasm-1` to set the execution environment as WASM 1.0 standard. This standard includes the following proposals: + - [Import/Export of Mutable Globals](https://github.com/WebAssembly/mutable-global) + - Use `--wasm-2` to set the execution environment as WASM 2.0 standard. This standard includes the WASM 1.0 and following proposals: + - [Non-Trapping Float-to-Int Conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) + - [Sign-Extension Operators](https://github.com/WebAssembly/sign-extension-ops) + - [Multi-value](https://github.com/WebAssembly/multi-value) + - [Bulk Memory Operations](https://github.com/WebAssembly/bulk-memory-operations) + - [Reference Types](https://github.com/WebAssembly/reference-types) + - [Fixed-width SIMD](https://github.com/webassembly/simd) + - Use `--wasm-3` to set the execution environment as WASM 3.0 standard (Currently default since 0.16.0). This standard includes the WASM 2.0 and following proposals: + - [Tail call](https://github.com/WebAssembly/tail-call) + - [Extended Constant Expressions](https://github.com/WebAssembly/extended-const) + - [Typed-Function References](https://github.com/WebAssembly/function-references) + - [Garbage Collection](https://github.com/WebAssembly/gc) + - [Multiple Memories](https://github.com/WebAssembly/multi-memory) + - [Relaxed SIMD](https://github.com/webassembly/relaxed-simd) + - [Exception Handling](https://github.com/WebAssembly/exception-handling) + - [Memory64 (currently not implemented)](https://github.com/WebAssembly/memory64) - Use `--disable-import-export-mut-globals` to disable the [Import/Export of Mutable Globals](https://github.com/WebAssembly/mutable-global) proposal (Default `ON`). - Use `--disable-non-trap-float-to-int` to disable the [Non-Trapping Float-to-Int Conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) proposal (Default `ON`). - Use `--disable-sign-extension-operators` to disable the [Sign-Extension Operators](https://github.com/WebAssembly/sign-extension-ops) proposal (Default `ON`). @@ -69,13 +87,21 @@ The options of the `wasmedge` CLI tool are as follows: - Use `--disable-bulk-memory` to disable the [Bulk Memory Operations](https://github.com/WebAssembly/bulk-memory-operations) proposal (Default `ON`). - Use `--disable-reference-types` to disable the [Reference Types](https://github.com/WebAssembly/reference-types) proposal (Default `ON`). - Use `--disable-simd` to disable the [Fixed-width SIMD](https://github.com/webassembly/simd) proposal (Default `ON`). - - Use `--enable-multi-memory` to enable the [Multiple Memories](https://github.com/WebAssembly/multi-memory) proposal (Default `OFF`). - - Use `--enable-tail-call` to enable the [Tail call](https://github.com/WebAssembly/tail-call) proposal (Default `OFF`). - - Use `--enable-extended-const` to enable the [Extended Constant Expressions](https://github.com/WebAssembly/extended-const) proposal (Default `OFF`). + - Use `--disable-tail-call` to disable the [Tail call](https://github.com/WebAssembly/tail-call) proposal (Default `ON`). + - Use `--disable-extended-const` to disable the [Extended Constant Expressions](https://github.com/WebAssembly/extended-const) proposal (Default `ON`). + - Use `--disable-function-reference` to disable the [Typed-Function References](https://github.com/WebAssembly/function-references) proposal (Default `ON`). + - Use `--disable-gc` to disable the [Garbage Collection](https://github.com/WebAssembly/gc) proposal (Default `ON`). + - Use `--disable-multi-memory` to disable the [Multiple Memories](https://github.com/WebAssembly/multi-memory) proposal (Default `ON`). + - Use `--disable-relaxed-simd` to disable the [Relaxed SIMD](https://github.com/webassembly/relaxed-simd) proposal (Default `ON`). + - Use `--disable-exception-handling` to disable the [Exception Handling](https://github.com/WebAssembly/exception-handling) proposal (Default `ON`, interpreter mode only). + - DEPRECATED: Use `--enable-tail-call` to enable the [Tail call](https://github.com/WebAssembly/tail-call) proposal. + - DEPRECATED: Use `--enable-extended-const` to enable the [Extended Constant Expressions](https://github.com/WebAssembly/extended-const) proposal. + - DEPRECATED: Use `--enable-function-reference` to enable the [Typed-Function References](https://github.com/WebAssembly/function-references) proposal. + - DEPRECATED: Use `--enable-gc` to enable the [GC](https://github.com/WebAssembly/gc) proposal. + - DEPRECATED: Use `--enable-multi-memory` to enable the [Multiple Memories](https://github.com/WebAssembly/multi-memory) proposal. + - DEPRECATED: Use `--enable-relaxed-simd` to enable the [Relaxed SIMD](https://github.com/webassembly/relaxed-simd) proposal. + - DEPRECATED: Use `--enable-exception-handling` to enable the [Exception Handling](https://github.com/WebAssembly/exception-handling) proposal. - Use `--enable-threads` to enable the [Threads](https://github.com/webassembly/threads) proposal (Default `OFF`). - - Use `--enable-function-reference` to enable the [Typed-Function References](https://github.com/WebAssembly/function-references) proposal (Default `OFF`). - - Use `--enable-gc` to enable the [GC](https://github.com/WebAssembly/gc) proposal (Default `OFF`, interpreter mode only). - - Use `--enable-exception-handling` to enable the [Exception Handling](https://github.com/WebAssembly/exception-handling) proposal (Default `OFF`, interpreter mode only). - Use `--enable-component` to enable the [Component Model](https://github.com/WebAssembly/component-model) proposal (Default `OFF`, loader phase only). - Use `--enable-all` to enable ALL proposals above. 10. WASM file (`/path/to/wasm/file`). diff --git a/docs/start/wasmedge/component_model.md b/docs/start/wasmedge/component_model.md index f8948c21..5a934540 100644 --- a/docs/start/wasmedge/component_model.md +++ b/docs/start/wasmedge/component_model.md @@ -6,6 +6,6 @@ sidebar_position: 4 The component model for WASM would dramatically improve WASM module’s reusability and composability. It will allow better access from one WASM module to other modules and systems, including the operating system APIs (e.g., networking). -WasmEdge is already committed to supporting and implementing [the component model proposal](https://github.com/WebAssembly/component-model). See the related issue [here](https://github.com/WasmEdge/WasmEdge/issues/1892). +WasmEdge is already committed to supporting and implementing [the component model proposal](https://github.com/WebAssembly/component-model). See the related issue [here](https://github.com/WasmEdge/WasmEdge/issues/4236). After the support for the component model is done, WasmEdge could be integrated by Spin and Spiderlightning. diff --git a/docs/start/wasmedge/extensions/proposals.md b/docs/start/wasmedge/extensions/proposals.md index 1e2a778e..5f1996ec 100644 --- a/docs/start/wasmedge/extensions/proposals.md +++ b/docs/start/wasmedge/extensions/proposals.md @@ -17,19 +17,20 @@ WasmEdge supports the following [WebAssembly proposals](https://github.com/WebAs | [Reference Types][] | `--disable-reference-types` | `WasmEdge_Proposal_ReferenceTypes` | ✓ (since `0.8.2`) | ✓ | ✓ | | [Bulk memory operations][] | `--disable-bulk-memory` | `WasmEdge_Proposal_BulkMemoryOperations` | ✓ (since `0.8.2`) | ✓ | ✓ | | [Fixed-width SIMD][] | `--disable-simd` | `WasmEdge_Proposal_SIMD` | ✓ (since `0.9.0`) | ✓ (since `0.8.2`) | ✓ (since `0.8.2`) | -| [Tail call][] | `--enable-tail-call` | `WasmEdge_Proposal_TailCall` | | ✓ (since `0.10.0`) | ✓ (since `0.10.0`) | -| [Extended Constant Expressions][] | `--enable-extended-const` | `WasmEdge_Proposal_ExtendedConst` | | ✓ (since `0.10.0`) | ✓ (since `0.10.0`) | -| [Typed Function References][] | `--enable-function-reference` | `WasmEdge_Proposal_FunctionReferences` | | ✓ (since `0.14.0`) | ✓ (since `0.14.0`) | -| [Garbage collection][] | `--enable-gc` | `WasmEdge_Proposal_GC` | | ✓ (since `0.14.0`) | | -| [Multiple memories][] | `--enable-multi-memory` | `WasmEdge_Proposal_MultiMemories` | | ✓ (since `0.9.1`) | ✓ (since `0.9.1`) | +| [Tail call][] | `--disable-tail-call` | `WasmEdge_Proposal_TailCall` | ✓ (since `0.16.0`) | ✓ (since `0.10.0`) | ✓ (since `0.10.0`) | +| [Extended Constant Expressions][] | `--disable-extended-const` | `WasmEdge_Proposal_ExtendedConst` | ✓ (since `0.16.0`) | ✓ (since `0.10.0`) | ✓ (since `0.10.0`) | +| [Typed Function References][] | `--disable-function-reference` | `WasmEdge_Proposal_FunctionReferences` | ✓ (since `0.16.0`) | ✓ (since `0.14.0`) | ✓ (since `0.14.0`) | +| [Garbage collection][] | `--disable-gc` | `WasmEdge_Proposal_GC` | ✓ (since `0.16.0`) | ✓ (since `0.14.0`) | ✓ (since `0.15.0`) | +| [Multiple memories][] | `--disable-multi-memory` | `WasmEdge_Proposal_MultiMemories` | ✓ (since `0.16.0`) | ✓ (since `0.9.1`) | ✓ (since `0.9.1`) | +| [Relaxed SIMD][] | `--disable-relaxed-simd` | `WasmEdge_Proposal_RelaxSIMD` | ✓ (since `0.16.0`) | ✓ (since `0.14.1`) | ✓ (since `0.14.1`) | +| [Exception handling][] | `--disable-exception-handling` | `WasmEdge_Proposal_ExceptionHandling` | ✓ (since `0.16.0`) | ✓ (since `0.14.0`) | | +| [Memory64][] | | | | | | | [Threads][] | `--enable-threads` | `WasmEdge_Proposal_Threads` | | ✓ (since `0.10.1`) | ✓ (since `0.10.1`) | -| [Exception handling][] | `--enable-exception-handling` | `WasmEdge_Proposal_ExceptionHandling` | | ✓ (since `0.14.0`) | | | [Component Model][] | `--enable-component` | `WasmEdge_Proposal_Component` | | Loader only (since `0.14.0`) | | The following proposals are under development and may be supported in the future: -- [Exception handling][] -- [Relaxed SIMD][] +- [Exception handling][] (AOT mode) - [Memory64][] - [WebAssembly C and C++ API][] diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/intro.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/intro.md index d39e87b7..4c48cc23 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/intro.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/intro.md @@ -121,7 +121,9 @@ sys 0m0.011s ## API References -- [0.14.1](reference/latest.md) +- [0.16.1](reference/latest.md) +- [0.15.1](reference/0.15.x.md) +- [0.14.1](reference/0.14.x.md) - [0.13.5](reference/0.13.x.md) - [0.12.1](reference/0.12.x.md) - [0.11.2](reference/0.11.x.md) diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.10.x.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.10.x.md index c25208fb..ae706550 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.10.x.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.10.x.md @@ -1,5 +1,5 @@ --- -sidebar_position: 9 +sidebar_position: 13 --- # C API 0.10.1 Documentation diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.11.x.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.11.x.md index a3708cbe..8269f8bb 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.11.x.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.11.x.md @@ -1,5 +1,5 @@ --- -sidebar_position: 7 +sidebar_position: 11 --- # C API 0.11.2 Documentation diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.12.x.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.12.x.md index 33e8df49..e6dfa214 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.12.x.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.12.x.md @@ -1,5 +1,5 @@ --- -sidebar_position: 5 +sidebar_position: 9 --- # C API 0.12.1 Documentation diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.13.x.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.13.x.md index 714ac119..ea4aaad7 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.13.x.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.13.x.md @@ -1,11 +1,13 @@ --- -sidebar_position: 3 +sidebar_position: 7 --- # C API 0.13.5 Documentation [WasmEdge C API](https://github.com/WasmEdge/WasmEdge/blob/master/include/api/wasmedge/wasmedge.h) denotes an interface to access the WasmEdge runtime at version `0.13.5`. The following are the guides to working with the C APIs of WasmEdge. +**Developers can refer to [here to upgrade to v0.14.0](upgrade_to_0.14.0).** + ## WasmEdge Installation ### Download And Install diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.14.x.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.14.x.md new file mode 100644 index 00000000..3a00ec5a --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.14.x.md @@ -0,0 +1,3206 @@ +--- +sidebar_position: 5 +--- + +# C API 0.14.1 Documentation + +[WasmEdge C API](https://github.com/WasmEdge/WasmEdge/blob/master/include/api/wasmedge/wasmedge.h) denotes an interface to access the WasmEdge runtime at version `0.14.1`. The following are the guides to working with the C APIs of WasmEdge. + +**Developers can refer to [here to upgrade to v0.15.0](upgrade_to_0.15.0).** + +## WasmEdge Installation + +### Download And Install + +The easiest way to install WasmEdge is to run the following command. Your system should have `git` and `wget` as prerequisites. + +```bash +curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -v 0.14.1 +``` + +For more details, please refer to the [Installation Guide](../../../start/install.md#install) for the WasmEdge installation. + +### Compile Sources + +After the installation of WasmEdge, the following guide can help you to test for the availability of the WasmEdge C API. + +1. Prepare the test C file (and assumed saved as `test.c`): + + ```c + #include + #include + int main() { + printf("WasmEdge version: %s\n", WasmEdge_VersionGet()); + return 0; + } + ``` + +2. Compile the file with `gcc` or `clang`. + + ```bash + gcc test.c -lwasmedge + ``` + +3. Run and get the expected output. + + ```bash + $ ./a.out + WasmEdge version: 0.14.1 + ``` + +### ABI Compatibility + +WasmEdge C API introduces SONAME and SOVERSION since the `0.11.0` release to present the compatibility between different C API versions. + +The releases before 0.11.0 are all unversioned. Please make sure the library version is the same as the corresponding C API version you used. + +| WasmEdge Version | WasmEdge C API Library Name | WasmEdge C API SONAME | WasmEdge C API SOVERSION | +| --- | --- | --- | --- | +| < 0.11.0 | libwasmedge_c.so | Unversioned | Unversioned | +| 0.11.0 to 0.11.1 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.0 | +| 0.11.2 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.1 | +| 0.12.0 to 0.12.1 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.2 | +| 0.13.0 to 0.13.5 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.3 | +| Since 0.14.0 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.1.0 | + +## WasmEdge Basics + +In this part, we will introduce the utilities and concepts of WasmEdge shared library. + +### Version + +The `Version` related APIs provide developers to check for the WasmEdge shared library version. + +```c +#include +printf("WasmEdge version: %s\n", WasmEdge_VersionGet()); +printf("WasmEdge version major: %u\n", WasmEdge_VersionGetMajor()); +printf("WasmEdge version minor: %u\n", WasmEdge_VersionGetMinor()); +printf("WasmEdge version patch: %u\n", WasmEdge_VersionGetPatch()); +``` + +### Logging Settings + +The `WasmEdge_LogSetErrorLevel()` and `WasmEdge_LogSetDebugLevel()` APIs can set the logging system to debug level or error level. By default, the error level is set, and the debug info is hidden. + +Developers can also use the `WasmEdge_LogOff()` API to disable all logging. + +### Value Types + +To describe the value types in WASM, WasmEdge uses the `WasmEdge_ValType` struct to encode the value types. + +1. Number types: `i32`, `i64`, `f32`, `f64`, and `v128` for the `SIMD` proposal + + ```c + WasmEdge_ValType ValType; + ValType = WasmEdge_ValTypeGenI32(); + bool IsTypeI32 = WasmEdge_ValTypeIsI32(ValType); + /* The `IsTypeI32` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenI64(); + bool IsTypeI64 = WasmEdge_ValTypeIsI64(ValType); + /* The `IsTypeI64` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenF32(); + bool IsTypeF32 = WasmEdge_ValTypeIsF32(ValType); + /* The `IsTypeF32` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenF64(); + bool IsTypeF64 = WasmEdge_ValTypeIsF64(ValType); + /* The `IsTypeF64` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenV128(); + bool IsTypeV128 = WasmEdge_ValTypeIsV128(ValType); + /* The `IsTypeV128` will be `TRUE`. */ + ``` + +2. Reference types: `funcref` and `externref` for the `Reference-Types` or `Typed-Function References` proposal + + ```c + WasmEdge_ValType ValType; + + ValType = WasmEdge_ValTypeGenFuncRef(); + /* The nullable funcref type is generated. */ + bool IsTypeFuncRef = WasmEdge_ValTypeIsFuncRef(ValType); + /* The `IsTypeFuncRef` will be `TRUE`. */ + bool IsTypeRef = WasmEdge_ValTypeIsRef(ValType); + /* The `IsTypeRef` will be `TRUE`. */ + bool IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(ValType); + /* The `IsTypeNullableRef` will be `TRUE`. */ + + ValType = WasmEdge_ValTypeGenExternRef(); + /* The nullable externref type is generated. */ + bool IsTypeExternRef = WasmEdge_ValTypeIsExternRef(ValType); + /* The `IsTypeExternRef` will be `TRUE`. */ + IsTypeRef = WasmEdge_ValTypeIsRef(ValType); + /* The `IsTypeRef` will be `TRUE`. */ + IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(ValType); + /* The `IsTypeNullableRef` will be `TRUE`. */ + ``` + +### Values + +In WasmEdge, developers should convert the values to `WasmEdge_Value` objects through APIs for matching to the WASM values for the arguments or returns. With the APIs, the output `WasmEdge_Value` objects will record the correct value types with values. + +1. Number types: `i32`, `i64`, `f32`, `f64`, and `v128` for the `SIMD` proposal + + ```c + WasmEdge_Value Val; + + Val = WasmEdge_ValueGenI32(123456); + bool IsTypeI32 = WasmEdge_ValTypeIsI32(Val.Type); + /* The `IsTypeI32` will be `TRUE`. */ + printf("%d\n", WasmEdge_ValueGetI32(Val)); + /* Will print "123456" */ + + Val = WasmEdge_ValueGenI64(1234567890123LL); + bool IsTypeI64 = WasmEdge_ValTypeIsI64(Val.Type); + /* The `IsTypeI64` will be `TRUE`. */ + printf("%ld\n", WasmEdge_ValueGetI64(Val)); + /* Will print "1234567890123" */ + + Val = WasmEdge_ValueGenF32(123.456f); + bool IsTypeF32 = WasmEdge_ValTypeIsF32(Val.Type); + /* The `IsTypeF32` will be `TRUE`. */ + printf("%f\n", WasmEdge_ValueGetF32(Val)); + /* Will print "123.456001" */ + + Val = WasmEdge_ValueGenF64(123456.123456789); + bool IsTypeF64 = WasmEdge_ValTypeIsF64(Val.Type); + /* The `IsTypeF64` will be `TRUE`. */ + printf("%.10f\n", WasmEdge_ValueGetF64(Val)); + /* Will print "123456.1234567890" */ + ``` + +2. Reference types: `funcref` and `externref` for the `Reference-Types` or `Typed-Function References` proposal + + ```c + WasmEdge_Value Val; + void *Ptr; + uint32_t Num = 10; + /* Generate an externref to NULL. */ + Val = WasmEdge_ValueGenExternRef(NULL); + bool IsNull = WasmEdge_ValueIsNullRef(Val); + /* The `IsNull` will be `TRUE`. */ + bool IsTypeExternRef = WasmEdge_ValTypeIsExternRef(Val.Type); + /* The `IsTypeExternRef` will be `TRUE`. */ + bool IsTypeRef = WasmEdge_ValTypeIsRef(Val.Type); + /* The `IsTypeRef` will be `TRUE`. */ + bool IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(Val.Type); + /* The `IsTypeNullableRef` will be `TRUE`. */ + Ptr = WasmEdge_ValueGetExternRef(Val); + /* The `Ptr` will be `NULL`. */ + + /* Get the function instance by creation or from module instance. */ + const WasmEdge_FunctionInstanceContext *FuncCxt = ...; + /* Generate a funcref with the given function instance context. */ + Val = WasmEdge_ValueGenFuncRef(FuncCxt); + bool IsTypeFuncRef = WasmEdge_ValTypeIsFuncRef(Val.Type); + /* The `IsTypeFuncRef` will be `TRUE`. */ + IsTypeRef = WasmEdge_ValTypeIsRef(Val.Type); + /* The `IsTypeRef` will be `TRUE`. */ + IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(Val.Type); + /* The `IsTypeNullableRef` will be `TRUE`. */ + const WasmEdge_FunctionInstanceContext *GotFuncCxt = + WasmEdge_ValueGetFuncRef(Val); + /* The `GotFuncCxt` will be the same as `FuncCxt`. */ + + /* Generate a externref to `Num`. */ + Val = WasmEdge_ValueGenExternRef(&Num); + Ptr = WasmEdge_ValueGetExternRef(Val); + /* The `Ptr` will be `&Num`. */ + printf("%u\n", *(uint32_t *)Ptr); + /* Will print "10" */ + Num += 55; + printf("%u\n", *(uint32_t *)Ptr); + /* Will print "65" */ + ``` + +### Buffers + +The `WasmEdge_Bytes` object is for the input buffer of loading or compiling module from memory, or the output buffer of serializing a module. + + +:::note +This object is designed for replacing raw buffer as input and output of WasmEdge C API. We recommand developers to use the `WasmEdge_Bytes` related APIs than the raw buffer, such as using `WasmEdge_LoaderParseFromBytes()` instead of `WasmEdge_LoaderParseFromBuffer()`. +::: + +1. Create a `WasmEdge_Bytes` from a buffer with length. + + ```c + uint8_t Buf[4] = {1, 2, 3, 4}; + WasmEdge_Bytes Bytes = WasmEdge_BytesCreate(Buf, 4); + /* The objects should be deleted by `WasmEdge_BytesDelete()`. */ + WasmEdge_BytesDelete(Bytes); + ``` + +2. Wrap a `WasmEdge_Bytes` to a buffer with length. + + The content will not be copied, and the caller should guarantee the life cycle of the input buffer. + + ```c + uint8_t Buf[4] = {1, 2, 3, 4}; + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(Buf, 4); + /* The object should __NOT__ be deleted by `WasmEdge_BytesDelete()`. */ + ``` + +### Strings + +The `WasmEdge_String` object is for the instance names when invoking a WASM function or finding the contexts of instances. + +1. Create a `WasmEdge_String` from a C string (`const char *` with NULL termination) or a buffer with length. + + The content of the C string or buffer will be copied into the `WasmEdge_String` object. + + ```c + char Buf[4] = {50, 55, 60, 65}; + WasmEdge_String Str1 = WasmEdge_StringCreateByCString("test"); + WasmEdge_String Str2 = WasmEdge_StringCreateByBuffer(Buf, 4); + /* The objects should be deleted by `WasmEdge_StringDelete()`. */ + WasmEdge_StringDelete(Str1); + WasmEdge_StringDelete(Str2); + ``` + +2. Wrap a `WasmEdge_String` to a buffer with length. + + The content will not be copied, and the caller should guarantee the life cycle of the input buffer. + + ```c + const char CStr[] = "test"; + WasmEdge_String Str = WasmEdge_StringWrap(CStr, 4); + /* The object should __NOT__ be deleted by `WasmEdge_StringDelete()`. */ + ``` + +3. String comparison + + ```c + const char CStr[] = "abcd"; + char Buf[4] = {0x61, 0x62, 0x63, 0x64}; + WasmEdge_String Str1 = WasmEdge_StringWrap(CStr, 4); + WasmEdge_String Str2 = WasmEdge_StringCreateByBuffer(Buf, 4); + bool IsEq = WasmEdge_StringIsEqual(Str1, Str2); + /* The `IsEq` will be `TRUE`. */ + WasmEdge_StringDelete(Str2); + ``` + +4. Convert to C string + + ```c + char Buf[256]; + WasmEdge_String Str = + WasmEdge_StringCreateByCString("test_wasmedge_string"); + uint32_t StrLength = WasmEdge_StringCopy(Str, Buf, sizeof(Buf)); + /* StrLength will be 20 */ + printf("String: %s\n", Buf); + /* Will print "test_wasmedge_string". */ + ``` + +### Results + +The `WasmEdge_Result` object specifies the execution status. APIs about WASM execution will return the `WasmEdge_Result` to denote the status. + +```c +WasmEdge_Result Res = WasmEdge_Result_Success; +bool IsSucceeded = WasmEdge_ResultOK(Res); +/* The `IsSucceeded` will be `TRUE`. */ +uint32_t Code = WasmEdge_ResultGetCode(Res); +/* The `Code` will be 0. */ +const char *Msg = WasmEdge_ResultGetMessage(Res); +/* The `Msg` will be "success". */ +enum WasmEdge_ErrCategory Category = WasmEdge_ResultGetCategory(Res); +/* The `Category` will be WasmEdge_ErrCategory_WASM. */ + +Res = WasmEdge_ResultGen(WasmEdge_ErrCategory_UserLevelError, 123); +/* Generate the user-defined result with code. */ +Code = WasmEdge_ResultGetCode(Res); +/* The `Code` will be 123. */ +Category = WasmEdge_ResultGetCategory(Res); +/* The `Category` will be WasmEdge_ErrCategory_UserLevelError. */ +``` + +### Contexts + +The objects, such as `VM`, `Store`, and `Function`, are composed of `Context`s. All of the contexts can be created by calling the corresponding creation APIs and should be destroyed by calling the corresponding deletion APIs. Developers have responsibilities to manage the contexts for memory management. + +```c +/* Create the configure context. */ +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); +/* Delete the configure context. */ +WasmEdge_ConfigureDelete(ConfCxt); +``` + +The details of other contexts will be introduced later. + +### WASM Data Structures + +The WASM data structures are used for creating instances or can be queried from instance contexts. The details of instances creation will be introduced in the [Instances](#instances). + +1. Limit + + The `WasmEdge_Limit` struct is defined in the header: + + ```c + /// Struct of WASM limit. + typedef struct WasmEdge_Limit { + /// Boolean to describe has max value or not. + bool HasMax; + /// Boolean to describe is shared memory or not. + bool Shared; + /// Minimum value. + uint32_t Min; + /// Maximum value. Will be ignored if the `HasMax` is false. + uint32_t Max; + } WasmEdge_Limit; + ``` + + Developers can initialize the struct by assigning it's value, and the `Max` value is needed to be larger or equal to the `Min` value. The API `WasmEdge_LimitIsEqual()` is provided to compare with 2 `WasmEdge_Limit` structs. + +2. Function type context + + The `Function Type` context is used for the `Function` creation, checking the value types of a `Function` instance, or getting the function type with function name from VM. Developers can use the `Function Type` context APIs to get the parameter or return value types information. + + ```c + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI64()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenFuncRef()}; + WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + + WasmEdge_ValType Buf[16]; + uint32_t ParamLen = WasmEdge_FunctionTypeGetParametersLength(FuncTypeCxt); + /* `ParamLen` will be 2. */ + uint32_t GotParamLen = WasmEdge_FunctionTypeGetParameters(FuncTypeCxt, Buf, 16); + /* + * `GotParamLen` will be 2, and `Buf[0]` and `Buf[1]` will be the same as + * `ParamList`. + */ + uint32_t ReturnLen = WasmEdge_FunctionTypeGetReturnsLength(FuncTypeCxt); + /* `ReturnLen` will be 1. */ + uint32_t GotReturnLen = WasmEdge_FunctionTypeGetReturns(FuncTypeCxt, Buf, 16); + /* + * `GotReturnLen` will be 1, and `Buf[0]` will be the same as `ReturnList`. + */ + + WasmEdge_FunctionTypeDelete(FuncTypeCxt); + ``` + +3. Table type context + + The `Table Type` context is used for `Table` instance creation or getting information from `Table` instances. + + ```c + WasmEdge_Limit TabLim = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_TableTypeCreate(WasmEdge_ValTypeGenExternRef(), TabLim); + + WasmEdge_ValType GotRefType = WasmEdge_TableTypeGetRefType(TabTypeCxt); + bool IsTypeExternRef = WasmEdge_ValTypeIsExternRef(GotRefType); + /* `IsTypeExternRef` will be `TRUE`. */ + bool IsTypeRef = WasmEdge_ValTypeIsRef(GotRefType); + /* `IsTypeRef` will be `TRUE`. */ + bool IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(GotRefType); + /* `IsTypeNullableRef` will be `TRUE`. */ + WasmEdge_Limit GotTabLim = WasmEdge_TableTypeGetLimit(TabTypeCxt); + /* `GotTabLim` will be the same value as `TabLim`. */ + + WasmEdge_TableTypeDelete(TabTypeCxt); + ``` + +4. Memory type context + + The `Memory Type` context is used for `Memory` instance creation or getting information from `Memory` instances. + + ```c + WasmEdge_Limit MemLim = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + WasmEdge_MemoryTypeContext *MemTypeCxt = WasmEdge_MemoryTypeCreate(MemLim); + + WasmEdge_Limit GotMemLim = WasmEdge_MemoryTypeGetLimit(MemTypeCxt); + /* `GotMemLim` will be the same value as `MemLim`. */ + + WasmEdge_MemoryTypeDelete(MemTypeCxt) + ``` + +5. Global type context + + The `Global Type` context is used for `Global` instance creation or getting information from `Global` instances. + + ```c + WasmEdge_GlobalTypeContext *GlobTypeCxt = WasmEdge_GlobalTypeCreate( + WasmEdge_ValTypeGenF64(), WasmEdge_Mutability_Var); + + WasmEdge_ValType GotValType = WasmEdge_GlobalTypeGetValType(GlobTypeCxt); + bool IsTypeF64 = WasmEdge_ValTypeIsF64(GotValType); + /* `IsTypeF64` will be `TRUE`. */ + WasmEdge_Mutability GotValMut = + WasmEdge_GlobalTypeGetMutability(GlobTypeCxt); + /* `GotValMut` will be WasmEdge_Mutability_Var. */ + + WasmEdge_GlobalTypeDelete(GlobTypeCxt); + ``` + +6. Tag type context + + The `Tag Type` context is used for getting information from `Tag` instances. + This will only usable if the `Exception Handling` proposal turned on. + + ```c + /* Get the tag type from a tag instance. */ + const WasmEdge_TagTypeContext *TagTypeCxt = WasmEdge_TagInstanceGetTagType(...); + + const WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_TagTypeGetFunctionType(TagTypeCxt); + ``` + +7. Import type context + + The `Import Type` context is used for getting the imports information from a [AST Module](#ast-module). Developers can get the external type (`function`, `table`, `memory`, `tag`, or `global`), import module name, and external name from an `Import Type` context. The details about querying `Import Type` contexts will be introduced in the [AST Module](#ast-module). + + ```c + WasmEdge_ASTModuleContext *ASTCxt = ...; + /* + * Assume that `ASTCxt` is returned by the `WasmEdge_LoaderContext` for the + * result of loading a WASM file. + */ + const WasmEdge_ImportTypeContext *ImpType = ...; + /* Assume that `ImpType` is queried from the `ASTCxt` for the import. */ + + enum WasmEdge_ExternalType ExtType = + WasmEdge_ImportTypeGetExternalType(ImpType); + /* + * The `ExtType` can be one of `WasmEdge_ExternalType_Function`, + * `WasmEdge_ExternalType_Table`, `WasmEdge_ExternalType_Memory`, + * `WasmEdge_ExternalType_Tag`, or `WasmEdge_ExternalType_Global`. + */ + WasmEdge_String ModName = WasmEdge_ImportTypeGetModuleName(ImpType); + WasmEdge_String ExtName = WasmEdge_ImportTypeGetExternalName(ImpType); + /* + * The `ModName` and `ExtName` should not be destroyed and the string + * buffers are binded into the `ASTCxt`. + */ + const WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_ImportTypeGetFunctionType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Function`, the + * `FuncTypeCxt` will be NULL. + */ + const WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_ImportTypeGetTableType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Table`, the `TabTypeCxt` + * will be NULL. + */ + const WasmEdge_MemoryTypeContext *MemTypeCxt = + WasmEdge_ImportTypeGetMemoryType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Memory`, the `MemTypeCxt` + * will be NULL. + */ + const WasmEdge_TagTypeContext *TagTypeCxt = + WasmEdge_ImportTypeGetTagType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Tag`, the `TagTypeCxt` + * will be NULL. + */ + const WasmEdge_GlobalTypeContext *GlobTypeCxt = + WasmEdge_ImportTypeGetGlobalType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Global`, the `GlobTypeCxt` + * will be NULL. + */ + ``` + +8. Export type context + + The `Export Type` context is used for getting the exports information from a [AST Module](#ast-module). Developers can get the external type (`function`, `table`, `memory`, `tag`, or `global`) and external name from an `Export Type` context. The details about querying `Export Type` contexts will be introduced in the [AST Module](#ast-module). + + ```c + WasmEdge_ASTModuleContext *ASTCxt = ...; + /* + * Assume that `ASTCxt` is returned by the `WasmEdge_LoaderContext` for the + * result of loading a WASM file. + */ + const WasmEdge_ExportTypeContext *ExpType = ...; + /* Assume that `ExpType` is queried from the `ASTCxt` for the export. */ + + enum WasmEdge_ExternalType ExtType = + WasmEdge_ExportTypeGetExternalType(ExpType); + /* + * The `ExtType` can be one of `WasmEdge_ExternalType_Function`, + * `WasmEdge_ExternalType_Table`, `WasmEdge_ExternalType_Memory`, + * `WasmEdge_ExternalType_Tag`, or `WasmEdge_ExternalType_Global`. + */ + WasmEdge_String ExtName = WasmEdge_ExportTypeGetExternalName(ExpType); + /* + * The `ExtName` should not be destroyed and the string buffer is binded + * into the `ASTCxt`. + */ + const WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_ExportTypeGetFunctionType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Function`, the + * `FuncTypeCxt` will be NULL. + */ + const WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_ExportTypeGetTableType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Table`, the `TabTypeCxt` + * will be NULL. + */ + const WasmEdge_MemoryTypeContext *MemTypeCxt = + WasmEdge_ExportTypeGetMemoryType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Memory`, the `MemTypeCxt` + * will be NULL. + */ + const WasmEdge_TagTypeContext *TagTypeCxt = + WasmEdge_ExportTypeGetTagType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Tag`, the `TagTypeCxt` + * will be NULL. + */ + const WasmEdge_GlobalTypeContext *GlobTypeCxt = + WasmEdge_ExportTypeGetGlobalType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Global`, the `GlobTypeCxt` + * will be NULL. + */ + ``` + +### Async + +After calling the [asynchronous execution APIs](#asynchronous-execution), developers will get the `WasmEdge_Async` object. Developers own the object and should call the `WasmEdge_AsyncDelete()` API to destroy it. + +1. Wait for the asynchronous execution + + Developers can wait the execution until finished: + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* Blocking and waiting for the execution. */ + WasmEdge_AsyncWait(Async); + WasmEdge_AsyncDelete(Async); + ``` + + Or developers can wait for a time limit. If the time limit exceeded, developers can choose to cancel the execution. For the interruptible execution in AOT mode, developers should set `TRUE` through the `WasmEdge_ConfigureCompilerSetInterruptible()` API into the configure context for the AOT compiler. + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* Blocking and waiting for the execution for 1 second. */ + bool IsEnd = WasmEdge_AsyncWaitFor(Async, 1000); + if (IsEnd) { + /* The execution finished. Developers can get the result. */ + WasmEdge_Result Res = WasmEdge_AsyncGet(/* ... Ignored */); + } else { + /* + * The time limit exceeded. Developers can keep waiting or cancel the + * execution. + */ + WasmEdge_AsyncCancel(Async); + WasmEdge_Result Res = WasmEdge_AsyncGet(Async, 0, NULL); + /* The result error code will be `WasmEdge_ErrCode_Interrupted`. */ + } + WasmEdge_AsyncDelete(Async); + ``` + +2. Get the execution result of the asynchronous execution + + Developers can use the `WasmEdge_AsyncGetReturnsLength()` API to get the return value list length. This function will block and wait for the execution. If the execution has finished, this function will return the length immediately. If the execution failed, this function will return `0`. This function can help the developers to create the buffer to get the return values. If developers have already known the buffer length, they can skip this function and use the `WasmEdge_AsyncGet()` API to get the result. + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* + * Blocking and waiting for the execution and get the return value list + * length. + */ + uint32_t Arity = WasmEdge_AsyncGetReturnsLength(Async); + WasmEdge_AsyncDelete(Async); + ``` + + The `WasmEdge_AsyncGet()` API will block and wait for the execution. If the execution has finished, this function will fill the return values into the buffer and return the execution result immediately. + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* Blocking and waiting for the execution and get the return values. */ + const uint32_t BUF_LEN = 256; + WasmEdge_Value Buf[BUF_LEN]; + WasmEdge_Result Res = WasmEdge_AsyncGet(Async, Buf, BUF_LEN); + WasmEdge_AsyncDelete(Async); + ``` + +### Configurations + +The configuration context, `WasmEdge_ConfigureContext`, manages the configurations for `Loader`, `Validator`, `Executor`, `VM`, and `Compiler` contexts. Developers can adjust the settings about the proposals, VM host pre-registrations (such as `WASI`), and AOT compiler options, and then apply the `Configure` context to create the runtime contexts. + +1. Proposals + + WasmEdge supports turning on or off the WebAssembly proposals. This configuration is effective in any contexts created with the `Configure` context. + + ```c + enum WasmEdge_Proposal { + WasmEdge_Proposal_ImportExportMutGlobals = 0, + WasmEdge_Proposal_NonTrapFloatToIntConversions, + WasmEdge_Proposal_SignExtensionOperators, + WasmEdge_Proposal_MultiValue, + WasmEdge_Proposal_BulkMemoryOperations, + WasmEdge_Proposal_ReferenceTypes, + WasmEdge_Proposal_SIMD, + WasmEdge_Proposal_TailCall, + WasmEdge_Proposal_ExtendedConst, + WasmEdge_Proposal_FunctionReferences, + WasmEdge_Proposal_GC, + WasmEdge_Proposal_MultiMemories, + WasmEdge_Proposal_Threads, + WasmEdge_Proposal_RelaxSIMD, + WasmEdge_Proposal_Annotations, + WasmEdge_Proposal_Memory64, + WasmEdge_Proposal_ExceptionHandling, + WasmEdge_Proposal_Component, + }; + ``` + + Developers can add or remove the proposals into the `Configure` context. + + ```c + /* + * By default, the following proposals have turned on initially: + * * Import/Export of mutable globals + * * Non-trapping float-to-int conversions + * * Sign-extension operators + * * Multi-value returns + * * Bulk memory operations + * * Reference types + * * Fixed-width SIMD + * + * For the current WasmEdge version, the following proposals are supported + * (turned off by default) additionally: + * * Tail-call + * * Extended-const + * * Typed-function references + * * GC (interpreter only) + * * Multiple memories + * * Relaxed SIMD (`0.14.1` or upper only) + * * Threads + * * Exception handling (interpreter only) + * * Component model (loader phase only) + */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddProposal(ConfCxt, WasmEdge_Proposal_MultiMemories); + WasmEdge_ConfigureRemoveProposal(ConfCxt, WasmEdge_Proposal_ReferenceTypes); + bool IsBulkMem = WasmEdge_ConfigureHasProposal( + ConfCxt, WasmEdge_Proposal_BulkMemoryOperations); + /* The `IsBulkMem` will be `TRUE`. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +2. Host registrations + + This configuration is used for the `VM` context to turn on the `WASI` supports and only effective in `VM` contexts. + + The element of this enum is reserved for the other built-in host functions (such as `wasi-socket`) in the future. + + ```c + enum WasmEdge_HostRegistration { + WasmEdge_HostRegistration_Wasi = 0 + }; + ``` + + The details will be introduced in the [preregistrations of VM context](#built-in-host-modules-and-plug-in-preregistrations). + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + bool IsHostWasi = WasmEdge_ConfigureHasHostRegistration( + ConfCxt, WasmEdge_HostRegistration_Wasi); + /* The `IsHostWasi` will be `FALSE`. */ + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + IsHostWasi = WasmEdge_ConfigureHasHostRegistration( + ConfCxt, WasmEdge_HostRegistration_Wasi); + /* The `IsHostWasi` will be `TRUE`. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +3. Maximum memory pages + + Developers can limit the page size of memory instances by this configuration. When growing the page size of memory instances in WASM execution and exceeding the limited size, the page growing will fail. This configuration is only effective in the `Executor` and `VM` contexts. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + uint32_t PageSize = WasmEdge_ConfigureGetMaxMemoryPage(ConfCxt); + /* By default, the maximum memory page size is 65536. */ + WasmEdge_ConfigureSetMaxMemoryPage(ConfCxt, 1024); + /* + * Limit the memory size of each memory instance with not larger than 1024 + * pages (64 MiB). + */ + PageSize = WasmEdge_ConfigureGetMaxMemoryPage(ConfCxt); + /* The `PageSize` will be 1024. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +4. Forcibly interpreter mode + + If developers want to execute the WASM file or the AOT compiled WASM in interpreter mode forcibly, they can turn on the configuration. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + bool IsForceInterp = WasmEdge_ConfigureIsForceInterpreter(ConfCxt); + /* By default, The `IsForceInterp` will be `FALSE`. */ + WasmEdge_ConfigureSetForceInterpreter(ConfCxt, TRUE); + IsForceInterp = WasmEdge_ConfigureIsForceInterpreter(ConfCxt); + /* The `IsForceInterp` will be `TRUE`. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +5. AOT compiler options + + The AOT compiler options configure the behavior about optimization level, output format, dump IR, and generic binary. + + ```c + enum WasmEdge_CompilerOptimizationLevel { + // Disable as many optimizations as possible. + WasmEdge_CompilerOptimizationLevel_O0 = 0, + // Optimize quickly without destroying debuggability. + WasmEdge_CompilerOptimizationLevel_O1, + // Optimize for fast execution as much as possible without triggering + // significant incremental compile time or code size growth. + WasmEdge_CompilerOptimizationLevel_O2, + // Optimize for fast execution as much as possible. + WasmEdge_CompilerOptimizationLevel_O3, + // Optimize for small code size as much as possible without triggering + // significant incremental compile time or execution time slowdowns. + WasmEdge_CompilerOptimizationLevel_Os, + // Optimize for small code size as much as possible. + WasmEdge_CompilerOptimizationLevel_Oz + }; + + enum WasmEdge_CompilerOutputFormat { + // Native dynamic library format. + WasmEdge_CompilerOutputFormat_Native = 0, + // WebAssembly with AOT compiled codes in custom section. + WasmEdge_CompilerOutputFormat_Wasm + }; + ``` + + These configurations are only effective in `Compiler` contexts. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* By default, the optimization level is O3. */ + WasmEdge_ConfigureCompilerSetOptimizationLevel( + ConfCxt, WasmEdge_CompilerOptimizationLevel_O2); + /* By default, the output format is universal WASM. */ + WasmEdge_ConfigureCompilerSetOutputFormat( + ConfCxt, WasmEdge_CompilerOutputFormat_Native); + /* By default, the dump IR is `FALSE`. */ + WasmEdge_ConfigureCompilerSetDumpIR(ConfCxt, TRUE); + /* By default, the generic binary is `FALSE`. */ + WasmEdge_ConfigureCompilerSetGenericBinary(ConfCxt, TRUE); + /* By default, the interruptible is `FALSE`. + /* Set this option to `TRUE` to support the interruptible execution in AOT + mode. */ + WasmEdge_ConfigureCompilerSetInterruptible(ConfCxt, TRUE); + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +6. Statistics options + + The statistics options configure the behavior about instruction counting, cost measuring, and time measuring in both runtime and AOT compiler. These configurations are effective in `Compiler`, `VM`, and `Executor` contexts. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* + * By default, the instruction counting is `FALSE` when running a + * compiled-WASM or a pure-WASM. + */ + WasmEdge_ConfigureStatisticsSetInstructionCounting(ConfCxt, TRUE); + /* + * By default, the cost measurement is `FALSE` when running a compiled-WASM + * or a pure-WASM. + */ + WasmEdge_ConfigureStatisticsSetCostMeasuring(ConfCxt, TRUE); + /* + * By default, the time measurement is `FALSE` when running a compiled-WASM + * or a pure-WASM. + */ + WasmEdge_ConfigureStatisticsSetTimeMeasuring(ConfCxt, TRUE); + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +### Statistics + +The statistics context, `WasmEdge_StatisticsContext`, provides the instruction counter, cost summation, and cost limitation at runtime. + +Before using statistics, the statistics configuration must be set. Otherwise, the return values of calling statistics are undefined behaviour. + +1. Instruction counter + + The instruction counter can help developers to profile the performance of WASM running. Developers can retrieve the `Statistics` context from the `VM` context, or create a new one for the `Executor` creation. The details will be introduced in the next partitions. + + ```c + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * ... + * After running the WASM functions with the `Statistics` context + */ + uint32_t Count = WasmEdge_StatisticsGetInstrCount(StatCxt); + double IPS = WasmEdge_StatisticsGetInstrPerSecond(StatCxt); + WasmEdge_StatisticsDelete(StatCxt); + ``` + +2. Cost table + + The cost table is to accumulate the cost of instructions with their weights. Developers can set the cost table array (the indices are the byte code value of instructions, and the values are the cost of instructions) into the `Statistics` context. If the cost limit value is set, the execution will return the `cost limit exceeded` error immediately when exceeds the cost limit in runtime. + + ```c + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + uint64_t CostTable[16] = { + 0, 0, + 10, /* 0x02: Block */ + 11, /* 0x03: Loop */ + 12, /* 0x04: If */ + 12, /* 0x05: Else */ + 0, 0, 0, 0, 0, 0, + 20, /* 0x0C: Br */ + 21, /* 0x0D: Br_if */ + 22, /* 0x0E: Br_table */ + 0 + }; + /* + * Developers can set the costs of each instruction. The value not + * covered will be 0. + */ + WasmEdge_StatisticsSetCostTable(StatCxt, CostTable, 16); + WasmEdge_StatisticsSetCostLimit(StatCxt, 5000000); + /* + * ... + * After running the WASM functions with the `Statistics` context + */ + uint64_t Cost = WasmEdge_StatisticsGetTotalCost(StatCxt); + WasmEdge_StatisticsDelete(StatCxt); + ``` + +## WasmEdge VM + +In this partition, we will introduce the functions of `WasmEdge_VMContext` object and show examples of executing WASM functions. + +### WASM Execution Example With VM Context + +The following shows the example of running the WASM for getting the Fibonacci. This example uses the [fibonacci.wat](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat). + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```wasm +(module + (export "fib" (func $fib)) + (func $fib (param $n i32) (result i32) + (if + (i32.lt_s (get_local $n)(i32.const 2)) + (return (i32.const 1)) + ) + (return + (i32.add + (call $fib (i32.sub (get_local $n)(i32.const 2))) + (call $fib (i32.sub (get_local $n)(i32.const 1))) + ) + ) + ) +) +``` + +1. Run WASM functions rapidly + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + #include + #include + int main() { + /* Create the configure context and add the WASI support. */ + /* This step is not necessary unless you need WASI support. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + /* The configure and store context to the VM creation can be NULL. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(5)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Run the WASM function from file. */ + WasmEdge_Result Res = WasmEdge_VMRunWasmFromFile( + VMCxt, "fibonacci.wasm", FuncName, Params, 1, Returns, 1); + /* + * Developers can run the WASM binary from buffer with the + * `WasmEdge_VMRunWasmFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMRunWasmFromASTModule()` API. + */ + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_ConfigureDelete(ConfCxt); + WasmEdge_StringDelete(FuncName); + return 0; + } + ``` + + Then you can compile and run: (the 5th Fibonacci number is 8 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 8 + ``` + +2. Instantiate and run WASM functions manually + + Besides the above example, developers can run the WASM functions step-by-step with `VM` context APIs: + + ```c + #include + #include + int main() { + /* Create the configure context and add the WASI support. */ + /* This step is not necessary unless you need the WASI support. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + /* The configure and store context to the VM creation can be NULL. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(10)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Step 1: Load WASM file. */ + Res = WasmEdge_VMLoadWasmFromFile(VMCxt, "fibonacci.wasm"); + /* + * Developers can load the WASM binary from buffer with the + * `WasmEdge_VMLoadWasmFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMLoadWasmFromASTModule()` API. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 2: Validate the WASM module. */ + Res = WasmEdge_VMValidate(VMCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 3: Instantiate the WASM module. */ + Res = WasmEdge_VMInstantiate(VMCxt); + /* + * Developers can load, validate, and instantiate another WASM module to + * replace the instantiated one. In this case, the old module will be + * cleared, but the registered modules are still kept. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Instantiation phase failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * Step 4: Execute WASM functions. You can execute functions repeatedly + * after instantiation. + */ + Res = WasmEdge_VMExecute(VMCxt, FuncName, Params, 1, Returns, 1); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_ConfigureDelete(ConfCxt); + WasmEdge_StringDelete(FuncName); + return 0; + } + ``` + + Then you can compile and run: (the 10th Fibonacci number is 89 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 89 + ``` + + The following graph explains the status of the `VM` context. + + ```text + |========================| + |------->| VM: Initiated | + | |========================| + | | + | LoadWasm + | | + | v + | |========================| + |--------| VM: Loaded |<-------| + | |========================| | + | | ^ | + | Validate | | + Cleanup | LoadWasm | + | v | LoadWasm + | |========================| | + |--------| VM: Validated | | + | |========================| | + | | ^ | + | Instantiate | | + | | RegisterModule | + | v | | + | |========================| | + |--------| VM: Instantiated |--------| + |========================| + | ^ + | | + -------------- + Instantiate, Execute, ExecuteRegistered + ``` + + The status of the `VM` context would be `Inited` when created. After loading WASM successfully, the status will be `Loaded`. After validating WASM successfully, the status will be `Validated`. After instantiating WASM successfully, the status will be `Instantiated`, and developers can invoke functions. Developers can register WASM or module instances in any status, but they should instantiate WASM again. Developers can also load WASM in any status, and they should validate and instantiate the WASM module before function invocation. When in the `Instantiated` status, developers can instantiate the WASM module again to reset the old WASM runtime structures. + +### VM Creations + +The `VM` creation API accepts the `Configure` context and the `Store` context. If developers only need the default settings, just pass `NULL` to the creation API. The details of the `Store` context will be introduced in [Store](#store). + +```c +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); +WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); +WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, StoreCxt); +/* The caller should guarantee the life cycle if the store context. */ +WasmEdge_StatisticsContext *StatCxt = WasmEdge_VMGetStatisticsContext(VMCxt); +/* + * The VM context already contains the statistics context and can be retrieved + * by this API. + */ +/* + * Note that the retrieved store and statistics contexts from the VM contexts by + * VM APIs should __NOT__ be destroyed and owned by the VM contexts. + */ +WasmEdge_VMDelete(VMCxt); +WasmEdge_StoreDelete(StoreCxt); +WasmEdge_ConfigureDelete(ConfCxt); +``` + +### Built-in Host Modules and Plug-in Preregistrations + +WasmEdge provides the following built-in host modules and plug-in pre-registrations. + +1. [WASI (WebAssembly System Interface)](https://github.com/WebAssembly/WASI) + + Developers can turn on the WASI support for VM in the `Configure` context. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + WasmEdge_ConfigureDelete(ConfCxt); + /* + * The following API can retrieve the built-in registered module instances + * from the VM context. + */ + /* + * This API will return `NULL` if the corresponding configuration is not set + * when creating the VM context. + */ + WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_VMGetImportModuleContext(VMCxt, + WasmEdge_HostRegistration_Wasi); + /* Initialize the WASI. */ + WasmEdge_ModuleInstanceInitWASI(WasiModule, /* ... ignored */); + WasmEdge_VMDelete(VMCxt); + ``` + + And also can create the WASI module instance from API. The details will be introduced in the [Host Functions](#host-functions) and the [Host Module Registrations](#host-module-registrations). + +2. Plug-ins + + There may be several plug-ins in the default plug-in paths if users [installed WasmEdge plug-ins by the installer](../../../start/install.md#install-wasmedge-plug-ins-and-dependencies). + + Before using the plug-ins, developers should [load the plug-ins from paths](#load-plug-ins-from-paths). + + The `VM` context will automatically create and register the module of the loaded plug-ins when creation. Furthermore, the following host modules will be mocked if the plug-in not loaded: + + - `wasi_ephemeral_crypto_asymmetric_common` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_common` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_kx` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_signatures` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_symmetric` (for the `WASI-Crypto`) + - `wasi_ephemeral_nn` + - `wasi_snapshot_preview1` + - `wasmedge_httpsreq` + - `wasmedge_process` + + When the WASM want to invoke these host functions but the corresponding plug-in not installed, WasmEdge will print the error message and return an error. + + ```c + /* Load the plug-ins in the default paths first. */ + WasmEdge_PluginLoadWithDefaultPaths(); + /* Create the configure context and add the WASI configuration. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + WasmEdge_ConfigureDelete(ConfCxt); + /* + * The following API can retrieve the registered modules in the VM context, + * includes the built-in WASI and the plug-ins. + */ + /* + * This API will return `NULL` if the module instance not found. + */ + WasmEdge_String WasiName = + WasmEdge_StringCreateByCString("wasi_snapshot_preview1"); + /* The `WasiModule` will not be `NULL` because the configuration was set. */ + const WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_VMGetRegisteredModule(VMCxt, WasiName); + WasmEdge_StringDelete(WasiName); + WasmEdge_String WasiNNName = + WasmEdge_StringCreateByCString("wasi_ephemeral_nn"); + /* + * The `WasiNNModule` will not be `NULL` even if the wasi_nn plug-in is not + * installed, because the VM context will mock and register the host + * modules. + */ + const WasmEdge_ModuleInstanceContext *WasiNNModule = + WasmEdge_VMGetRegisteredModule(VMCxt, WasiNNName); + WasmEdge_StringDelete(WasiNNName); + + WasmEdge_VMDelete(VMCxt); + ``` + +### Host Module Registrations + +[Host functions](https://webassembly.github.io/spec/core/exec/runtime.html#syntax-hostfunc) are functions outside WebAssembly and passed to WASM modules as imports. In WasmEdge, the host functions are composed into host modules as `WasmEdge_ModuleInstanceContext` objects with module names. Please refer to the [Host Functions in WasmEdge Runtime](#host-functions) for the details. + +In this chapter, we show the example for registering the host modules into a `VM` context. Noticed that the developers should guarantee the availability of the registered module instance, and should delete the module instance when it will not be used. + +```c +WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); +WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_ModuleInstanceCreateWASI(/* ... ignored ... */); +/* You can also create and register the WASI host modules by this API. */ +WasmEdge_Result Res = WasmEdge_VMRegisterModuleFromImport(VMCxt, WasiModule); +/* The result status should be checked. */ + +/* ... */ + +WasmEdge_VMDelete(VMCxt); +WasmEdge_ModuleInstanceDelete(WasiModule); +/* + * The created module instances should be deleted by the developers when the VM + * deallocation. + */ +``` + +### WASM Registrations And Executions + +In WebAssembly, the instances in WASM modules can be exported and can be imported by other WASM modules. WasmEdge VM provides APIs for developers to register and export any WASM modules, and execute the functions or host functions in the registered WASM modules. + +1. Register the WASM modules with exported module names + + Unless the module instances have already contained the module names, every WASM module should be named uniquely when registering. + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_Result Res = + WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + /* + * Developers can register the WASM module from buffer with the + * `WasmEdge_VMRegisterModuleFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMRegisterModuleFromASTModule()` API. + */ + /* + * The result status should be checked. + * The error will occur if the WASM module instantiation failed or the + * module name conflicts. + */ + WasmEdge_StringDelete(ModName); + WasmEdge_VMDelete(VMCxt); + ``` + +2. Execute the functions in registered WASM modules + + Assume that the C file `test.c` is as follows: + + ```c + #include + #include + int main() { + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(20)}; + WasmEdge_Value Returns[1]; + /* Names. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Register the WASM module into VM. */ + Res = WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + /* + * Developers can register the WASM module from buffer with the + * `WasmEdge_VMRegisterModuleFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMRegisterModuleFromASTModule()` API. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * The function "fib" in the "fibonacci.wasm" was exported with the module + * name "mod". As the same as host functions, other modules can import the + * function `"mod" "fib"`. + */ + + /* + * Execute WASM functions in registered modules. + * Unlike the execution of functions, the registered functions can be + * invoked without `WasmEdge_VMInstantiate()` because the WASM module was + * instantiated when registering. Developers can also invoke the host + * functions directly with this API. + */ + Res = WasmEdge_VMExecuteRegistered(VMCxt, ModName, FuncName, Params, 1, + Returns, 1); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + WasmEdge_StringDelete(ModName); + WasmEdge_StringDelete(FuncName); + WasmEdge_VMDelete(VMCxt); + return 0; + } + ``` + + Then you can compile and run: (the 20th Fibonacci number is 89 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 10946 + ``` + +### Asynchronous Execution + +1. Asynchronously run WASM functions rapidly + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + #include + #include + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(20)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Asynchronously run the WASM function from file and get the + * `WasmEdge_Async` object. */ + WasmEdge_Async *Async = WasmEdge_VMAsyncRunWasmFromFile( + VMCxt, "fibonacci.wasm", FuncName, Params, 1); + /* + * Developers can run the WASM binary from buffer with the + * `WasmEdge_VMAsyncRunWasmFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMAsyncRunWasmFromASTModule()` API. + */ + + /* Wait for the execution. */ + WasmEdge_AsyncWait(Async); + /* + * Developers can also use the `WasmEdge_AsyncGetReturnsLength()` or + * `WasmEdge_AsyncGet()` APIs to wait for the asynchronous execution. + * These APIs will wait until the execution finished. + */ + + /* Check the return values length. */ + uint32_t Arity = WasmEdge_AsyncGetReturnsLength(Async); + /* The `Arity` should be 1. Developers can skip this step if they have + * known the return arity. */ + + /* Get the result. */ + WasmEdge_Result Res = WasmEdge_AsyncGet(Async, Returns, Arity); + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_AsyncDelete(Async); + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + return 0; + } + ``` + + Then you can compile and run: (the 20th Fibonacci number is 10946 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 10946 + ``` + +2. Instantiate and asynchronously run WASM functions manually + + Besides the above example, developers can run the WASM functions step-by-step with `VM` context APIs: + + ```c + #include + #include + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(25)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Step 1: Load WASM file. */ + Res = WasmEdge_VMLoadWasmFromFile(VMCxt, "fibonacci.wasm"); + /* + * Developers can load the WASM binary from buffer with the + * `WasmEdge_VMLoadWasmFromBytes()` API, or from `WasmEdge_ASTModuleContext` + * object with the `WasmEdge_VMLoadWasmFromASTModule()` API. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 2: Validate the WASM module. */ + Res = WasmEdge_VMValidate(VMCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 3: Instantiate the WASM module. */ + Res = WasmEdge_VMInstantiate(VMCxt); + /* + * Developers can load, validate, and instantiate another WASM module to + * replace the instantiated one. In this case, the old module will be + * cleared, but the registered modules are still kept. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Instantiation phase failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 4: Asynchronously execute the WASM function and get the + * `WasmEdge_Async` object. */ + WasmEdge_Async *Async = + WasmEdge_VMAsyncExecute(VMCxt, FuncName, Params, 1); + /* + * Developers can execute functions repeatedly after instantiation. + * For invoking the registered functions, you can use the + * `WasmEdge_VMAsyncExecuteRegistered()` API. + */ + + /* Wait and check the return values length. */ + uint32_t Arity = WasmEdge_AsyncGetReturnsLength(Async); + /* The `Arity` should be 1. Developers can skip this step if they have + * known the return arity. */ + + /* Get the result. */ + Res = WasmEdge_AsyncGet(Async, Returns, Arity); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_AsyncDelete(Async); + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + } + ``` + + Then you can compile and run: (the 25th Fibonacci number is 121393 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 121393 + ``` + +### Instance Tracing + +Sometimes the developers may have requirements to get the instances of the WASM runtime. The `VM` context supplies the APIs to retrieve the instances. + +1. Store + + If the `VM` context is created without assigning a `Store` context, the `VM` context will allocate and own a `Store` context. + + ```c + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + WasmEdge_StoreContext *StoreCxt = WasmEdge_VMGetStoreContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_StoreDelete()`. */ + WasmEdge_VMDelete(VMCxt); + ``` + + Developers can also create the `VM` context with a `Store` context. In this case, developers should guarantee the life cycle of the `Store` context. Please refer to the [Store Contexts](#store) for the details about the `Store` context APIs. + + ```c + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, StoreCxt); + WasmEdge_StoreContext *StoreCxtMock = WasmEdge_VMGetStoreContext(VMCxt); + /* The `StoreCxt` and the `StoreCxtMock` are the same. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StoreDelete(StoreCxt); + ``` + +2. List exported functions + + After the WASM module instantiation, developers can use the `WasmEdge_VMExecute()` API to invoke the exported WASM functions. For this purpose, developers may need information about the exported WASM function list. Please refer to the [Instances in runtime](#instances) for the details about the function types. + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + #include + #include + int main() { + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, StoreCxt); + + WasmEdge_VMLoadWasmFromFile(VMCxt, "fibonacci.wasm"); + WasmEdge_VMValidate(VMCxt); + WasmEdge_VMInstantiate(VMCxt); + + /* List the exported functions. */ + /* Get the number of exported functions. */ + uint32_t FuncNum = WasmEdge_VMGetFunctionListLength(VMCxt); + /* Create the name buffers and the function type buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String FuncNames[BUF_LEN]; + WasmEdge_FunctionTypeContext *FuncTypes[BUF_LEN]; + /* + * Get the export function list. + * If the function list length is larger than the buffer length, the + * overflowed data will be discarded. The `FuncNames` and `FuncTypes` can + * be NULL if developers don't need them. + */ + uint32_t RealFuncNum = + WasmEdge_VMGetFunctionList(VMCxt, FuncNames, FuncTypes, BUF_LEN); + + for (uint32_t I = 0; I < RealFuncNum && I < BUF_LEN; I++) { + char Buf[BUF_LEN]; + uint32_t Size = WasmEdge_StringCopy(FuncNames[I], Buf, sizeof(Buf)); + printf("Get exported function string length: %u, name: %s\n", Size, + Buf); + /* + * The function names should be __NOT__ destroyed. + * The returned function type contexts should __NOT__ be destroyed. + */ + } + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_VMDelete(VMCxt); + return 0; + } + ``` + + Then you can compile and run: (the only exported function in `fibonacci.wasm` is `fib`) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get exported function string length: 3, name: fib + ``` + + If developers want to get the exported function names in the registered WASM modules, please retrieve the `Store` context from the `VM` context and refer to the APIs of [Store Contexts](#store) to list the registered functions by the module name. + +3. Get function types + + The `VM` context provides APIs to find the function type by function name. Please refer to the [Instances in runtime](#instances) for the details about the function types. + + ```c + /* + * ... + * Assume that a WASM module is instantiated in `VMCxt`. + */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + const WasmEdge_FunctionTypeContext *FuncType = + WasmEdge_VMGetFunctionType(VMCxt, FuncName); + /* + * Developers can get the function types of functions in the registered + * modules via the `WasmEdge_VMGetFunctionTypeRegistered()` API with the + * module name. If the function is not found, these APIs will return `NULL`. + * The returned function type contexts should __NOT__ be destroyed. + */ + WasmEdge_StringDelete(FuncName); + ``` + +4. Get the active module + + After the WASM module instantiation, an anonymous module is instantiated and owned by the `VM` context. Developers may need to retrieve it to get the instances beyond the module. Then developers can use the `WasmEdge_VMGetActiveModule()` API to get that anonymous module instance. Please refer to the [Module instance](#instances) for the details about the module instance APIs. + + ```c + /* + * ... + * Assume that a WASM module is instantiated in `VMCxt`. + */ + const WasmEdge_ModuleInstanceContext *ModCxt = + WasmEdge_VMGetActiveModule(VMCxt); + /* + * If there's no WASM module instantiated, this API will return `NULL`. + * The returned module instance context should __NOT__ be destroyed. + */ + ``` + +5. List and get the registered modules + + To list and retrieve the registered modules in the `VM` context, besides accessing the `store` context of the `VM`, developers can use the following APIs. + + ```c + /* + * ... + * Assume that the `VMCxt` is created. + */ + WasmEdge_String Names[32]; + uint32_t ModuleLen = WasmEdge_VMListRegisteredModule(VMCxt, Names, 32); + for (uint32_t I = 0; I < ModuleLen; I++) { + /* Will print the registered module names in the VM context. */ + printf("%s\n", Names[I].Buf); + } + + WasmEdge_String WasiName = + WasmEdge_StringCreateByCString("wasi_snapshot_preview1"); + /* The `WasiModule` will not be `NULL` because the configuration was set. */ + const WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_VMGetRegisteredModule(VMCxt, WasiName); + WasmEdge_StringDelete(WasiName); + ``` + +6. Get the components + + The `VM` context is composed by the `Loader`, `Validator`, and `Executor` contexts. For the developers who want to use these contexts without creating another instances, these APIs can help developers to get them from the `VM` context. The get contexts are owned by the `VM` context, and developers should not call their delete functions. + + ```c + WasmEdge_LoaderContext *LoadCxt = WasmEdge_VMGetLoaderContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_LoaderDelete()`. */ + WasmEdge_ValidatorContext *ValidCxt = WasmEdge_VMGetValidatorContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_ValidatorDelete()`. */ + WasmEdge_ExecutorContext *ExecCxt = WasmEdge_VMGetExecutorContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_ExecutorDelete()`. */ + ``` + +## WasmEdge Runtime + +In this partition, we will introduce the objects of WasmEdge runtime manually. + +### WASM Execution Example Step-By-Step + +Besides the WASM execution through the [`VM` context](#wasmedge-vm), developers can execute the WASM functions or instantiate WASM modules step-by-step with the `Loader`, `Validator`, `Executor`, and `Store` contexts. + +Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```c +#include +#include +int main() { + /* + * Create the configure context. This step is not necessary because we didn't + * adjust any setting. + */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* + * Create the statistics context. This step is not necessary if the statistics + * in runtime is not needed. + */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + /* Result. */ + WasmEdge_Result Res; + + /* Create the loader context. The configure context can be NULL. */ + WasmEdge_LoaderContext *LoadCxt = WasmEdge_LoaderCreate(ConfCxt); + /* Create the validator context. The configure context can be NULL. */ + WasmEdge_ValidatorContext *ValidCxt = WasmEdge_ValidatorCreate(ConfCxt); + /* + * Create the executor context. The configure context and the statistics + * context can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + + /* + * Load the WASM file or the compiled-WASM file and convert into the AST + * module context. + */ + WasmEdge_ASTModuleContext *ASTCxt = NULL; + Res = WasmEdge_LoaderParseFromFile(LoadCxt, &ASTCxt, "fibonacci.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Validate the WASM module. */ + Res = WasmEdge_ValidatorValidate(ValidCxt, ASTCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Instantiate the WASM module into store context. */ + WasmEdge_ModuleInstanceContext *ModCxt = NULL; + Res = WasmEdge_ExecutorInstantiate(ExecCxt, &ModCxt, StoreCxt, ASTCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Instantiation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + + /* Try to list the exported functions of the instantiated WASM module. */ + uint32_t FuncNum = WasmEdge_ModuleInstanceListFunctionLength(ModCxt); + /* Create the name buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String FuncNames[BUF_LEN]; + /* + * If the list length is larger than the buffer length, the overflowed data + * will be discarded. + */ + uint32_t RealFuncNum = + WasmEdge_ModuleInstanceListFunction(ModCxt, FuncNames, BUF_LEN); + for (uint32_t I = 0; I < RealFuncNum && I < BUF_LEN; I++) { + char Buf[BUF_LEN]; + uint32_t Size = WasmEdge_StringCopy(FuncNames[I], Buf, sizeof(Buf)); + printf("Get exported function string length: %u, name: %s\n", Size, Buf); + /* The function names should __NOT__ be destroyed. */ + } + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(18)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Find the exported function by function name. */ + WasmEdge_FunctionInstanceContext *FuncCxt = + WasmEdge_ModuleInstanceFindFunction(ModCxt, FuncName); + if (FuncCxt == NULL) { + printf("Function `fib` not found.\n"); + return 1; + } + /* Invoke the WASM function. */ + Res = WasmEdge_ExecutorInvoke(ExecCxt, FuncCxt, Params, 1, Returns, 1); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_StringDelete(FuncName); + WasmEdge_ASTModuleDelete(ASTCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + WasmEdge_LoaderDelete(LoadCxt); + WasmEdge_ValidatorDelete(ValidCxt); + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_ConfigureDelete(ConfCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_StatisticsDelete(StatCxt); + return 0; +} +``` + +Then you can compile and run: (the 18th Fibonacci number is 4181 in 0-based index) + +```bash +$ gcc test.c -lwasmedge +$ ./a.out +Get exported function string length: 3, name: fib +Get the result: 4181 +``` + +### Loader + +The `Loader` context loads the WASM binary from files or buffers. Both the WASM and the compiled-WASM from the [WasmEdge AOT Compiler](#wasmedge-aot-compiler) are supported. + +```c +uint8_t Buf[4096]; +/* ... Read the WASM code to the buffer. */ +uint32_t FileSize = ...; +/* The `FileSize` is the length of the WASM code. */ + +/* Developers can adjust settings in the configure context. */ +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); +/* Create the loader context. The configure context can be NULL. */ +WasmEdge_LoaderContext *LoadCxt = WasmEdge_LoaderCreate(ConfCxt); + +WasmEdge_ASTModuleContext *ASTCxt = NULL; +WasmEdge_Result Res; + +/* Load WASM or compiled-WASM from the file. */ +Res = WasmEdge_LoaderParseFromFile(LoadCxt, &ASTCxt, "fibonacci.wasm"); +if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} +/* The output AST module context should be destroyed. */ +WasmEdge_ASTModuleDelete(ASTCxt); + +/* Load WASM or compiled-WASM from the buffer. */ +WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(Buf, FileSize); +Res = WasmEdge_LoaderParseFromBytes(LoadCxt, &ASTCxt, Bytes); +/* + * Note: `WasmEdge_LoaderParseFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_LoaderParseFromBytes()` instead. + */ +if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} +/* The output AST module context should be destroyed. */ +WasmEdge_ASTModuleDelete(ASTCxt); + +WasmEdge_LoaderDelete(LoadCxt); +WasmEdge_ConfigureDelete(ConfCxt); +``` + +### Validator + +The `Validator` context can validate the WASM module. Every WASM module should be validated before instantiation. + +```c +/* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context. + * Assume that the `ConfCxt` is the configure context. + */ +/* Create the validator context. The configure context can be NULL. */ +WasmEdge_ValidatorContext *ValidCxt = WasmEdge_ValidatorCreate(ConfCxt); +WasmEdge_Result Res = WasmEdge_ValidatorValidate(ValidCxt, ASTCxt); +if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} +WasmEdge_ValidatorDelete(ValidCxt); +``` + +### Executor + +The `Executor` context is the executor for both WASM and compiled-WASM. This object should work base on the `Store` context. For the details of the `Store` context, please refer to the [next chapter](#store). + +1. Instantiate and register an `AST module` as a named `Module` instance + + As the same of [registering host modules](#host-module-registrations) or [importing WASM modules](#wasm-registrations-and-executions) in `VM` contexts, developers can instantiate an `AST module` contexts into a named `Module` instance, and register it into the `Store` context. After the registration, the result `Module` instance is exported to the `Store` with the given module name and can be linked when instantiating another module. + + For the details about the `Module` instances APIs, please refer to the [Instances](#instances). The `Store` context is only the linker for searching and linking the exported modules when instantiation. Developers should delete the output `Module` instance when it will no longer be used. When the `Module` instance being deleted, it will automatically unlink to all linked `Store` contexts. + + ```c + /* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context and has passed the validation. Assume that the `ConfCxt` is the + * configure context. + */ + /* Create the statistics context. This step is not necessary. */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the executor context. The configure and the statistics contexts + * can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = + WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + /* Result. */ + WasmEdge_Result Res; + + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + /* The output module instance. */ + WasmEdge_ModuleInstanceContext *ModCxt = NULL; + /* + * Register the WASM module into the store with the export module name + * "mod". + */ + Res = + WasmEdge_ExecutorRegister(ExecCxt, &ModCxt, StoreCxt, ASTCxt, ModName); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return -1; + } + WasmEdge_StringDelete(ModName); + + /* ... */ + + /* After the execution, the resources should be released. */ + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_StatisticsDelete(StatCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + ``` + +2. Register an existing `Module` instance and export the module name + + Besides instantiating and registering an `AST module` contexts, developers can register an existing `Module` instance into the store with exporting the module name (which is in the `Module` instance already). This case occurs when developers create a `Module` instance for the host functions and want to register it for linking. For the details about the construction of host functions in `Module` instances, please refer to the [Host Functions](#host-functions). + + ```c + /* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context and has passed the validation. Assume that the `ConfCxt` is the + * configure context. + */ + /* Create the statistics context. This step is not necessary. */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the executor context. The configure and the statistics contexts + * can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = + WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + /* Result. */ + WasmEdge_Result Res; + + /* Create a module instance for host functions. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("host-module"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ModName); + WasmEdge_StringDelete(ModName); + /* + * ... + * Create and add the host functions, tables, memories, and globals into the + * module instance. + */ + + /* Register the module instance into store with the exported module name. */ + /* The export module name is in the module instance already. */ + Res = WasmEdge_ExecutorRegisterImport(ExecCxt, StoreCxt, HostModCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return -1; + } + + /* ... */ + + /* After the execution, the resources should be released. */ + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_StatisticsDelete(StatCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + ``` + +3. Instantiate an `AST module` to an anonymous `Module` instance + + WASM or compiled-WASM modules should be instantiated before the function invocation. Before instantiating a WASM module, please check the [import section](https://webassembly.github.io/spec/core/syntax/modules.html#syntax-import) for ensuring the imports are registered into the `Store` context for linking. + + ```c + /* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context and has passed the validation. Assume that the `ConfCxt` is the + * configure context. + */ + /* Create the statistics context. This step is not necessary. */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the executor context. The configure and the statistics contexts + * can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = + WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + + /* The output module instance. */ + WasmEdge_ModuleInstanceContext *ModCxt = NULL; + /* Instantiate the WASM module. */ + WasmEdge_Result Res = + WasmEdge_ExecutorInstantiate(ExecCxt, &ModCxt, StoreCxt, ASTCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM instantiation failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return -1; + } + + /* ... */ + + /* After the execution, the resources should be released. */ + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_StatisticsDelete(StatCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + ``` + +4. Invoke functions + + After registering or instantiating and get the result `Module` instance, developers can retrieve the exported `Function` instances from the `Module` instance for invocation. For the details about the `Module` instances APIs, please refer to the [Instances](#instances). Please refer to the [example above](#wasm-execution-example-step-by-step) for the `Function` instance invocation with the `WasmEdge_ExecutorInvoke()` API. + +5. Asynchronously invoke functions + + Such as [executing WASM functions in VM asynchronously](#asynchronous-execution), developers can also invoke a function asynchronously by `Executor` contexts API. + + After getting the `Function` instance, developers will get the `Async` context by calling the `WasmEdge_ExecutorAsyncInvoke()` API. Please refer to the [Async](#async) chapter to work with this context for getting the results. + +### AST Module + +The `AST Module` context presents the loaded structure from a WASM file or buffer. Developer will get this object after loading a WASM file or buffer from [Loader](#loader). Before instantiation, developers can also query the imports and exports of an `AST Module` context. + +```c +WasmEdge_ASTModuleContext *ASTCxt = ...; +/* Assume that a WASM is loaded into an AST module context. */ + +/* Create the import type context buffers. */ +const uint32_t BUF_LEN = 256; +const WasmEdge_ImportTypeContext *ImpTypes[BUF_LEN]; +uint32_t ImportNum = WasmEdge_ASTModuleListImportsLength(ASTCxt); +/* + * If the list length is larger than the buffer length, the overflowed data will + * be discarded. + */ +uint32_t RealImportNum = + WasmEdge_ASTModuleListImports(ASTCxt, ImpTypes, BUF_LEN); +for (uint32_t I = 0; I < RealImportNum && I < BUF_LEN; I++) { + /* Working with the import type `ImpTypes[I]` ... */ +} + +/* Create the export type context buffers. */ +const WasmEdge_ExportTypeContext *ExpTypes[BUF_LEN]; +uint32_t ExportNum = WasmEdge_ASTModuleListExportsLength(ASTCxt); +/* + * If the list length is larger than the buffer length, the overflowed data will + * be discarded. + */ +uint32_t RealExportNum = + WasmEdge_ASTModuleListExports(ASTCxt, ExpTypes, BUF_LEN); +for (uint32_t I = 0; I < RealExportNum && I < BUF_LEN; I++) { + /* Working with the export type `ExpTypes[I]` ... */ +} + +WasmEdge_ASTModuleDelete(ASTCxt); +/* + * After deletion of `ASTCxt`, all data queried from the `ASTCxt` should not be + * accessed. + */ +``` + +### Serializer + +As the reversion of loading WASM file or buffer into a `AST Module`, the `Loader` context also provide the serializer to serialze the `AST Module` back into a WASM buffer. + +```c +WasmEdge_ASTModuleContext *ASTCxt = ...; +/* Assume that a WASM is loaded into an AST module context. */ + +WasmEdge_LoaderContext *LoadCxt = ...; +/* Assume that a loader context is created with configuration. */ + +WasmEdbe_Bytes Bytes; +/* Serialize the AST module back into WASM binary format. */ +Res = WasmEdge_LoaderSerializeASTModule(LoadCxt, ASTCxt, &Bytes); +if (!WasmEdge_ResultOK(Res)) { + printf("Serialization failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} + +/* The output WasmEdge_Bytes should be destroyed. */ +WasmEdge_BytesDelete(Bytes); +``` + +### Store + +[Store](https://webassembly.github.io/spec/core/exec/runtime.html#store) is the runtime structure for the representation of all global state that can be manipulated by WebAssembly programs. The `Store` context in WasmEdge is an object which present the linker to provide the instance exporting and importing when instantiating WASM modules. Developers can retrieve the named modules from the `Store` context, and should delete the `Module` instances registered into the `Store` context if they will not be used anymore. + +When the `Store` context being deleted, the linked `Module` instances will automatically unlink to this `Store` context. When a `Module` instance being deleted, it will automatically unlink to all the linked `Store` contexts. + +```c +WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + +/* + * ... + * Register a WASM module via the executor context. + */ + +/* Try to list the registered WASM modules. */ +uint32_t ModNum = WasmEdge_StoreListModuleLength(StoreCxt); +/* Create the name buffers. */ +const uint32_t BUF_LEN = 256; +WasmEdge_String ModNames[BUF_LEN]; +/* + * If the list length is larger than the buffer length, the overflowed data will + * be discarded. + */ +uint32_t RealModNum = WasmEdge_StoreListModule(StoreCxt, ModNames, BUF_LEN); +for (uint32_t I = 0; I < RealModNum && I < BUF_LEN; I++) { + /* Working with the module name `ModNames[I]` ... */ + /* The module names should __NOT__ be destroyed. */ +} + +/* Find named module by name. */ +WasmEdge_String ModName = WasmEdge_StringCreateByCString("module"); +const WasmEdge_ModuleInstanceContext *ModCxt = + WasmEdge_StoreFindModule(StoreCxt, ModName); +/* If the module with name not found, the `ModCxt` will be NULL. */ +WasmEdge_StringDelete(ModName); +``` + +### Instances + +The instances are the runtime structures of WASM. Developers can retrieve the `Module` instances from the `Store` contexts, and retrieve the other instances from the `Module` instances. A single instance can be allocated by its creation function. Developers can construct instances into an `Module` instance for registration. Please refer to the [Host Functions](#host-functions) for details. The instances created by their creation functions should be destroyed by developers, EXCEPT they are added into an `Module` instance. + +1. Module instance + + After instantiating or registering an `AST module` context, developers will get a `Module` instance as the result, and have the responsibility to destroy it when not in use. A `Module` instance can also be created for the host module. Please refer to the [host function](#host-functions) for the details. `Module` instance provides APIs to list and find the exported instances in the module. + + ```c + /* + * ... + * Instantiate a WASM module via the executor context and get the `ModCxt` + * as the output module instance. + */ + + /* Try to list the exported instance of the instantiated WASM module. */ + /* Take the function instances for example here. */ + uint32_t FuncNum = WasmEdge_ModuleInstanceListFunctionLength(ModCxt); + /* Create the name buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String FuncNames[BUF_LEN]; + /* + * If the list length is larger than the buffer length, the overflowed data + * will be discarded. + */ + uint32_t RealFuncNum = + WasmEdge_ModuleInstanceListFunction(ModCxt, FuncNames, BUF_LEN); + for (uint32_t I = 0; I < RealFuncNum && I < BUF_LEN; I++) { + /* Working with the function name `FuncNames[I]` ... */ + /* The function names should __NOT__ be destroyed. */ + } + + /* Try to find the exported instance of the instantiated WASM module. */ + /* Take the function instances for example here. */ + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + WasmEdge_FunctionInstanceContext *FuncCxt = + WasmEdge_ModuleInstanceFindFunction(ModCxt, FuncName); + /* `FuncCxt` will be `NULL` if the function not found. */ + /* + * The returned instance is owned by the module instance context and should + * __NOT__ be destroyed. + */ + WasmEdge_StringDelete(FuncName); + ``` + +2. Function instance + + [Host functions](https://webassembly.github.io/spec/core/exec/runtime.html#syntax-hostfunc) are functions outside WebAssembly and passed to WASM modules as imports. In WasmEdge, developers can create the `Function` contexts for host functions and add them into an `Module` instance context for registering into a `VM` or a `Store`. Developers can retrieve the `Function Type` from the `Function` contexts through the API. For the details of the `Host Function` guide, please refer to the [next chapter](#host-functions). + + ```c + /* Retrieve the function instance from the module instance context. */ + WasmEdge_FunctionInstanceContext *FuncCxt = ...; + WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_FunctionInstanceGetFunctionType(FuncCxt); + /* + * The `FuncTypeCxt` is owned by the `FuncCxt` and should __NOT__ be + * destroyed. + */ + + /* + * For the function instance creation, please refer to the `Host Function` + * guide. + */ + ``` + +3. Table instance + + In WasmEdge, developers can create the `Table` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. The `Table` contexts supply APIs to control the data in table instances. + + ```c + WasmEdge_Limit TabLimit = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + /* Create the table type with limit and the `FuncRef` element type. */ + WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_TableTypeCreate(WasmEdge_ValTypeGenFuncRef(), TabLimit); + /* Create the table instance with table type. */ + /* + * Developers can also use the `WasmEdge_TableInstanceCreateWithInit()` API to + * create the table instance with default reference values. + */ + WasmEdge_TableInstanceContext *HostTable = + WasmEdge_TableInstanceCreate(TabTypeCxt); + /* Delete the table type. */ + WasmEdge_TableTypeDelete(TabTypeCxt); + WasmEdge_Result Res; + WasmEdge_Value Data; + + const WasmEdge_TableTypeContext *GotTabTypeCxt = + WasmEdge_TableInstanceGetTableType(HostTable); + /* + * The `GotTabTypeCxt` got from table instance is owned by the `HostTable` and + * should __NOT__ be destroyed. + */ + WasmEdge_ValType RefType = WasmEdge_TableTypeGetRefType(GotGlobTypeCxt); + bool IsTypeFuncRef = WasmEdge_ValTypeIsFuncRef(RefType); + /* `IsTypeFuncRef` will be `TRUE`. */ + Data = WasmEdge_ValueGenFuncRef(5); + Res = WasmEdge_TableInstanceSetData(HostTable, Data, 3); + /* Set the function index 5 to the table[3]. */ + /* + * This will get an "out of bounds table access" error + * because the position (13) is out of the table size (10): + * Res = WasmEdge_TableInstanceSetData(HostTable, Data, 13); + */ + Res = WasmEdge_TableInstanceGetData(HostTable, &Data, 3); + /* Get the FuncRef value of the table[3]. */ + /* + * This will get an "out of bounds table access" error + * because the position (13) is out of the table size (10): + * Res = WasmEdge_TableInstanceGetData(HostTable, &Data, 13); + */ + + uint32_t Size = WasmEdge_TableInstanceGetSize(HostTable); + /* `Size` will be 10. */ + Res = WasmEdge_TableInstanceGrow(HostTable, 6); + /* Grow the table size of 6, the table size will be 16. */ + /* + * This will get an "out of bounds table access" error because + * the size (16 + 6) will reach the table limit(20): + * Res = WasmEdge_TableInstanceGrow(HostTable, 6); + */ + + WasmEdge_TableInstanceDelete(HostTable); + ``` + +4. Memory instance + + In WasmEdge, developers can create the `Memory` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. The `Memory` contexts supply APIs to control the data in memory instances. + + ```c + WasmEdge_Limit MemLimit = { + .HasMax = true, .Shared = false, .Min = 1, .Max = 5}; + /* Create the memory type with limit. The memory page size is 64KiB. */ + WasmEdge_MemoryTypeContext *MemTypeCxt = + WasmEdge_MemoryTypeCreate(MemLimit); + /* Create the memory instance with memory type. */ + WasmEdge_MemoryInstanceContext *HostMemory = + WasmEdge_MemoryInstanceCreate(MemTypeCxt); + /* Delete the memory type. */ + WasmEdge_MemoryTypeDelete(MemTypeCxt); + WasmEdge_Result Res; + uint8_t Buf[256]; + + Buf[0] = 0xAA; + Buf[1] = 0xBB; + Buf[2] = 0xCC; + Res = WasmEdge_MemoryInstanceSetData(HostMemory, Buf, 0x1000, 3); + /* Set the data[0:2] to the memory[4096:4098]. */ + /* + * This will get an "out of bounds memory access" error + * because [65535:65537] is out of 1 page size (65536): + * Res = WasmEdge_MemoryInstanceSetData(HostMemory, Buf, 0xFFFF, 3); + */ + Buf[0] = 0; + Buf[1] = 0; + Buf[2] = 0; + Res = WasmEdge_MemoryInstanceGetData(HostMemory, Buf, 0x1000, 3); + /* Get the memory[4096:4098]. Buf[0:2] will be `{0xAA, 0xBB, 0xCC}`. */ + /* + * This will get an "out of bounds memory access" error + * because [65535:65537] is out of 1 page size (65536): + * Res = WasmEdge_MemoryInstanceSetData(HostMemory, Buf, 0xFFFF, 3); + */ + + uint32_t PageSize = WasmEdge_MemoryInstanceGetPageSize(HostMemory); + /* `PageSize` will be 1. */ + Res = WasmEdge_MemoryInstanceGrowPage(HostMemory, 2); + /* Grow the page size of 2, the page size of the memory instance will be 3. */ + /* + * This will get an "out of bounds memory access" error because + * the page size (3 + 3) will reach the memory limit(5): + * Res = WasmEdge_MemoryInstanceGrowPage(HostMemory, 3); + */ + + WasmEdge_MemoryInstanceDelete(HostMemory); + ``` + +5. Tag instance + + Unlike the other instances, the `Tag` contexts are only available and can be retrieved from a `Module` instance context when turning on the `Exception Handling` proposal. Developers can retrieve the `Tag Type` from the instance. + + ```c + /* + * ... + * Instantiate a WASM module with exception handling instructions via the + * executor context and get the `ModCxt` as the output module instance. + */ + + /* Try to list the exported tag instance of the instantiated WASM module. */ + uint32_t TagNum = WasmEdge_ModuleInstanceListTagLength(ModCxt); + /* Create the name buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String TagNames[BUF_LEN]; + /* + * If the list length is larger than the buffer length, the overflowed data + * will be discarded. + */ + uint32_t RealTagNum = WasmEdge_ModuleInstanceListTag(ModCxt, TagNames, BUF_LEN); + for (uint32_t I = 0; I < RealTagNum && I < BUF_LEN; I++) { + /* Working with the tag name `TagNames[I]` ... */ + /* The function names should __NOT__ be destroyed. */ + } + + /* Try to find the exported tag instance of the instantiated WASM module. */ + WasmEdge_String TagName = WasmEdge_StringCreateByCString("tag-1"); + WasmEdge_TagInstanceContext *TagCxt = + WasmEdge_ModuleInstanceFindTag(ModCxt, TagName); + /* `TagCxt` will be `NULL` if the tag not found. */ + /* + * The returned instance is owned by the module instance context and should + * __NOT__ be destroyed. + */ + + /* Try to retrieve the tag type from the tag instance. */ + const WasmEdge_TagTypeContext *TagTypeCxt = + WasmEdge_TagInstanceGetTagType(TagCxt); + /* + * The returned tag type context is owned by the tag instance context and should + * __NOT__ be destroyed. + */ + + WasmEdge_StringDelete(TagName); + ``` + +6. Global instance + + In WasmEdge, developers can create the `Global` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. The `Global` contexts supply APIs to control the value in global instances. + + ```c + WasmEdge_Value Val = WasmEdge_ValueGenI64(1000); + /* Create the global type with value type and mutation. */ + WasmEdge_GlobalTypeContext *GlobTypeCxt = WasmEdge_GlobalTypeCreate( + WasmEdge_ValTypeGenI64(), WasmEdge_Mutability_Var); + /* Create the global instance with value and global type. */ + WasmEdge_GlobalInstanceContext *HostGlobal = + WasmEdge_GlobalInstanceCreate(GlobTypeCxt, Val); + /* Delete the global type. */ + WasmEdge_GlobalTypeDelete(GlobTypeCxt); + WasmEdge_Result Res; + + const WasmEdge_GlobalTypeContext *GotGlobTypeCxt = + WasmEdge_GlobalInstanceGetGlobalType(HostGlobal); + /* + * The `GotGlobTypeCxt` got from global instance is owned by the `HostGlobal` + * and should __NOT__ be destroyed. + */ + WasmEdge_ValType ValType = WasmEdge_GlobalTypeGetValType(GotGlobTypeCxt); + bool IsTypeF64 = WasmEdge_ValTypeIsI64(ValType); + /* `ValType` will be `TRUE`. */ + enum WasmEdge_Mutability ValMut = + WasmEdge_GlobalTypeGetMutability(GotGlobTypeCxt); + /* `ValMut` will be `WasmEdge_Mutability_Var`. */ + + Res = WasmEdge_GlobalInstanceSetValue(HostGlobal, WasmEdge_ValueGenI64(888)); + /* + * Set the value u64(888) to the global. + * This function will return error if the value type mismatched or + * the global mutability is `WasmEdge_Mutability_Const`. + */ + WasmEdge_Value GlobVal = WasmEdge_GlobalInstanceGetValue(HostGlobal); + /* Get the value (888 now) of the global context. */ + + WasmEdge_GlobalInstanceDelete(HostGlobal); + ``` + +### Host Functions + +[Host functions](https://webassembly.github.io/spec/core/exec/runtime.html#syntax-hostfunc) are functions outside WebAssembly and passed to WASM modules as imports. In WasmEdge, developers can create the `Function`, `Memory`, `Table`, and `Global` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. + +1. Host function allocation + + Developers can define C functions with the following function signature as the host function body: + + ```c + typedef WasmEdge_Result (*WasmEdge_HostFunc_t)( + void *Data, const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *Params, WasmEdge_Value *Returns); + ``` + + The example of an `add` host function to add 2 `i32` values: + + ```c + WasmEdge_Result Add(void *, const WasmEdge_CallingFrameContext *, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + /* + * Params: {i32, i32} + * Returns: {i32} + * Developers should take care about the function type. + */ + /* Retrieve the value 1. */ + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + /* Retrieve the value 2. */ + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + /* Output value 1 is Val1 + Val2. */ + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + /* Return the status of success. */ + return WasmEdge_Result_Success; + } + ``` + + Then developers can create `Function` context with the host function body and the function type: + + ```c + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + /* Create a function type: {i32, i32} -> {i32}. */ + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + /* + * Create a function context with the function type and host function body. + * The `Cost` parameter can be 0 if developers do not need the cost + * measuring. + */ + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, NULL, 0); + /* + * The third parameter is the pointer to the additional data. + * Developers should guarantee the life cycle of the data, and it can be + * `NULL` if the external data is not needed. + */ + WasmEdge_FunctionTypeDelete(HostType); + + /* + * If the function instance is __NOT__ added into a module instance context, + * it should be deleted. + */ + WasmEdge_FunctionInstanceDelete(HostFunc); + ``` + +2. Calling frame context + + The `WasmEdge_CallingFrameContext` is the context to provide developers to access the module instance of the [frame on the top of the calling stack](https://webassembly.github.io/spec/core/exec/runtime.html#activations-and-frames). According to the [WASM spec](https://webassembly.github.io/spec/core/exec/instructions.html#function-calls), a frame with the module instance is pushed into the stack when invoking a function. Therefore, the host functions can access the module instance of the top frame to retrieve the memory instances to read/write data. + + ```c + WasmEdge_Result LoadOffset(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + /* Function type: {i32} -> {} */ + uint32_t Offset = (uint32_t)WasmEdge_ValueGetI32(In[0]); + uint32_t Num = 0; + + /* + * Get the 0-th memory instance of the module instance of the top frame on + * stack. + */ + WasmEdge_MemoryInstanceContext *MemCxt = + WasmEdge_CallingFrameGetMemoryInstance(CallFrameCxt, 0); + + WasmEdge_Result Res = + WasmEdge_MemoryInstanceGetData(MemCxt, (uint8_t *)(&Num), Offset, 4); + if (WasmEdge_ResultOK(Res)) { + printf("u32 at memory[%lu]: %lu\n", Offset, Num); + } else { + return Res; + } + return WasmEdge_Result_Success; + } + ``` + + Besides using the `WasmEdge_CallingFrameGetMemoryInstance()` API to get the memory instance by index in the module instance, developers can use the `WasmEdge_CallingFrameGetModuleInstance()` to get the module instance directly. Therefore, developers can retrieve the exported contexts by the `WasmEdge_ModuleInstanceContext` APIs. And also, developers can use the `WasmEdge_CallingFrameGetExecutor()` API to get the currently used executor context. + +3. User-defined error code of the host functions + + In host functions, WasmEdge provides `WasmEdge_Result_Success` to return success, `WasmEdge_Result_Terminate` to terminate the WASM execution, and `WasmEdge_Result_Fail` to return fail. WasmEdge also provides the usage of returning the user-specified codes. Developers can use the `WasmEdge_ResultGen()` API to generate the `WasmEdge_Result` with error code, and use the `WasmEdge_ResultGetCode()` API to get the error code. + + > Notice: The error code only supports 24-bit integer (0 ~ 16777216 in `uint32_t`). The values larger than 24-bit will be truncated. + + Assume that a simple WASM from the WAT is as following: + + ```wasm + (module + (type $t0 (func (param i32))) + (import "extern" "trap" (func $f-trap (type $t0))) + (func (export "trap") (param i32) + local.get 0 + call $f-trap) + ) + ``` + + And the `test.c` is as following: + + ```c + #include + #include + + /* Host function body definition. */ + WasmEdge_Result Trap(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val = WasmEdge_ValueGetI32(In[0]); + /* Return the error code from the param[0]. */ + return WasmEdge_ResultGen(WasmEdge_ErrCategory_UserLevelError, Val); + } + + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The WASM module buffer. */ + uint8_t WASM[] = {/* WASM header */ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + /* Type section */ + 0x01, 0x05, 0x01, + /* function type {i32} -> {} */ + 0x60, 0x01, 0x7F, 0x00, + /* Import section */ + 0x02, 0x0F, 0x01, + /* module name: "extern" */ + 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, + /* extern name: "trap" */ + 0x04, 0x74, 0x72, 0x61, 0x70, + /* import desc: func 0 */ + 0x00, 0x00, + /* Function section */ + 0x03, 0x02, 0x01, 0x00, + /* Export section */ + 0x07, 0x08, 0x01, + /* export name: "trap" */ + 0x04, 0x74, 0x72, 0x61, 0x70, + /* export desc: func 0 */ + 0x00, 0x01, + /* Code section */ + 0x0A, 0x08, 0x01, + /* code body */ + 0x06, 0x00, 0x20, 0x00, 0x10, 0x00, 0x0B}; + + /* Create the module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + WasmEdge_ValType ParamList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 1, NULL, 0); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Trap, NULL, 0); + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String HostFuncName = WasmEdge_StringCreateByCString("trap"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, HostFuncName, HostFunc); + WasmEdge_StringDelete(HostFuncName); + + WasmEdge_VMRegisterModuleFromImport(VMCxt, HostModCxt); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(5566)}; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("trap"); + /* Run the WASM function from memory. */ + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(WASM, sizeof(WASM)); + /* + * Note: `WasmEdge_VMRunWasmFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_VMRunWasmFromBytes()` instead. + */ + WasmEdge_Result Res = + WasmEdge_VMRunWasmFromBytes(VMCxt, Bytes, FuncName, Params, 1, NULL, 0); + + /* Get the result code and print. */ + printf("Get the error code: %u\n", WasmEdge_ResultGetCode(Res)); + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_ModuleInstanceDelete(HostModCxt); + return 0; + } + ``` + + Then you can compile and run: (giving the expected error code `5566`) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + [2022-08-26 15:06:40.384] [error] user defined failed: user defined error code, Code: 0x15be + [2022-08-26 15:06:40.384] [error] When executing function name: "trap" + Get the error code: 5566 + ``` + +4. Construct a module instance with host instances + + Besides creating a `Module` instance by registering or instantiating a WASM module, developers can create a `Module` instance with a module name and add the `Function`, `Memory`, `Table`, and `Global` instances into it with their exporting names. + + ```c + /* Host function body definition. */ + WasmEdge_Result Add(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + return WasmEdge_Result_Success; + } + + /* Create a module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("module"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + /* + * Developers can also use the WasmEdge_ModuleInstanceCreateWithData() to + * create the module instance with the data and its finalizer. It will be + * introduced later. + */ + WasmEdge_StringDelete(ExportName); + + /* Create and add a function instance into the module instance. */ + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, NULL, 0); + /* + * The third parameter is the pointer to the additional data object. + * Developers should guarantee the life cycle of the data, and it can be + * `NULL` if the external data is not needed. + */ + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("add"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, FuncName, HostFunc); + WasmEdge_StringDelete(FuncName); + + /* Create and add a table instance into the import object. */ + WasmEdge_Limit TableLimit = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + WasmEdge_TableTypeContext *HostTType = + WasmEdge_TableTypeCreate(WasmEdge_ValTypeGenFuncRef(), TableLimit); + WasmEdge_TableInstanceContext *HostTable = + WasmEdge_TableInstanceCreate(HostTType); + WasmEdge_TableTypeDelete(HostTType); + WasmEdge_String TableName = WasmEdge_StringCreateByCString("table"); + WasmEdge_ModuleInstanceAddTable(HostModCxt, TableName, HostTable); + WasmEdge_StringDelete(TableName); + + /* Create and add a memory instance into the import object. */ + WasmEdge_Limit MemoryLimit = { + .HasMax = true, .Shared = false, .Min = 1, .Max = 2}; + WasmEdge_MemoryTypeContext *HostMType = + WasmEdge_MemoryTypeCreate(MemoryLimit); + WasmEdge_MemoryInstanceContext *HostMemory = + WasmEdge_MemoryInstanceCreate(HostMType); + WasmEdge_MemoryTypeDelete(HostMType); + WasmEdge_String MemoryName = WasmEdge_StringCreateByCString("memory"); + WasmEdge_ModuleInstanceAddMemory(HostModCxt, MemoryName, HostMemory); + WasmEdge_StringDelete(MemoryName); + + /* Create and add a global instance into the module instance. */ + WasmEdge_GlobalTypeContext *HostGType = WasmEdge_GlobalTypeCreate( + WasmEdge_ValTypeGenI32(), WasmEdge_Mutability_Var); + WasmEdge_GlobalInstanceContext *HostGlobal = + WasmEdge_GlobalInstanceCreate(HostGType, WasmEdge_ValueGenI32(666)); + WasmEdge_GlobalTypeDelete(HostGType); + WasmEdge_String GlobalName = WasmEdge_StringCreateByCString("global"); + WasmEdge_ModuleInstanceAddGlobal(HostModCxt, GlobalName, HostGlobal); + WasmEdge_StringDelete(GlobalName); + + /* + * The module instance should be deleted. + * Developers should __NOT__ destroy the instances added into the module + * instance contexts. + */ + WasmEdge_ModuleInstanceDelete(HostModCxt); + ``` + +5. Specified module instance + + `WasmEdge_ModuleInstanceCreateWASI()` API can create and initialize the `WASI` module instance. + + Developers can create these module instance contexts and register them into the `Store` or `VM` contexts rather than adjust the settings in the `Configure` contexts. + + ```c + WasmEdge_ModuleInstanceContext *WasiModCxt = + WasmEdge_ModuleInstanceCreateWASI(/* ... ignored */); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + /* Register the WASI and WasmEdge_Process into the VM context. */ + WasmEdge_VMRegisterModuleFromImport(VMCxt, WasiModCxt); + /* Get the WASI exit code. */ + uint32_t ExitCode = WasmEdge_ModuleInstanceWASIGetExitCode(WasiModCxt); + /* + * The `ExitCode` will be EXIT_SUCCESS if the execution has no error. + * Otherwise, it will return with the related exit code. + */ + WasmEdge_VMDelete(VMCxt); + /* The module instances should be deleted. */ + WasmEdge_ModuleInstanceDelete(WasiModCxt); + ``` + +6. Example + + Assume that a simple WASM from the WAT is as following: + + ```wasm + (module + (type $t0 (func (param i32 i32) (result i32))) + (import "extern" "func-add" (func $f-add (type $t0))) + (func (export "addTwo") (param i32 i32) (result i32) + local.get 0 + local.get 1 + call $f-add) + ) + ``` + + And the `test.c` is as following: + + ```c + #include + #include + + /* Host function body definition. */ + WasmEdge_Result Add(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + printf("Host function \"Add\": %d + %d\n", Val1, Val2); + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + return WasmEdge_Result_Success; + } + + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The WASM module buffer. */ + uint8_t WASM[] = {/* WASM header */ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + /* Type section */ + 0x01, 0x07, 0x01, + /* function type {i32, i32} -> {i32} */ + 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, + /* Import section */ + 0x02, 0x13, 0x01, + /* module name: "extern" */ + 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, + /* extern name: "func-add" */ + 0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64, + /* import desc: func 0 */ + 0x00, 0x00, + /* Function section */ + 0x03, 0x02, 0x01, 0x00, + /* Export section */ + 0x07, 0x0A, 0x01, + /* export name: "addTwo" */ + 0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F, + /* export desc: func 0 */ + 0x00, 0x01, + /* Code section */ + 0x0A, 0x0A, 0x01, + /* code body */ + 0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B}; + + /* Create the module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, NULL, 0); + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String HostFuncName = WasmEdge_StringCreateByCString("func-add"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, HostFuncName, HostFunc); + WasmEdge_StringDelete(HostFuncName); + + WasmEdge_VMRegisterModuleFromImport(VMCxt, HostModCxt); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[2] = {WasmEdge_ValueGenI32(1234), + WasmEdge_ValueGenI32(5678)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("addTwo"); + /* Run the WASM function from memory. */ + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(WASM, sizeof(WASM)); + /* + * Note: `WasmEdge_VMRunWasmFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_VMRunWasmFromBytes()` instead. + */ + WasmEdge_Result Res = WasmEdge_VMRunWasmFromBytes(VMCxt, Bytes, FuncName, + Params, 2, Returns, 1); + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_ModuleInstanceDelete(HostModCxt); + return 0; + } + ``` + + Then you can compile and run: (the result of 1234 + 5678 is 6912) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Host function "Add": 1234 + 5678 + Get the result: 6912 + ``` + +7. Host Data Example + + Developers can set a external data object to the `Function` context, and access to the object in the function body. Assume that a simple WASM from the WAT is as following: + + ```wasm + (module + (type $t0 (func (param i32 i32) (result i32))) + (import "extern" "func-add" (func $f-add (type $t0))) + (func (export "addTwo") (param i32 i32) (result i32) + local.get 0 + local.get 1 + call $f-add) + ) + ``` + + And the `test.c` is as following: + + ```c + #include + #include + + /* Host function body definition. */ + WasmEdge_Result Add(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + printf("Host function \"Add\": %d + %d\n", Val1, Val2); + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + /* Also set the result to the data. */ + int32_t *DataPtr = (int32_t *)Data; + *DataPtr = Val1 + Val2; + return WasmEdge_Result_Success; + } + + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The WASM module buffer. */ + uint8_t WASM[] = {/* WASM header */ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + /* Type section */ + 0x01, 0x07, 0x01, + /* function type {i32, i32} -> {i32} */ + 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, + /* Import section */ + 0x02, 0x13, 0x01, + /* module name: "extern" */ + 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, + /* extern name: "func-add" */ + 0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64, + /* import desc: func 0 */ + 0x00, 0x00, + /* Function section */ + 0x03, 0x02, 0x01, 0x00, + /* Export section */ + 0x07, 0x0A, 0x01, + /* export name: "addTwo" */ + 0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F, + /* export desc: func 0 */ + 0x00, 0x01, + /* Code section */ + 0x0A, 0x0A, 0x01, + /* code body */ + 0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B}; + + /* The external data object: an integer. */ + int32_t Data; + + /* Create the module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, &Data, 0); + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String HostFuncName = WasmEdge_StringCreateByCString("func-add"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, HostFuncName, HostFunc); + WasmEdge_StringDelete(HostFuncName); + + WasmEdge_VMRegisterModuleFromImport(VMCxt, HostModCxt); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[2] = {WasmEdge_ValueGenI32(1234), + WasmEdge_ValueGenI32(5678)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("addTwo"); + /* Run the WASM function from memory. */ + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(WASM, sizeof(WASM)); + /* + * Note: `WasmEdge_VMRunWasmFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_VMRunWasmFromBytes()` instead. + */ + WasmEdge_Result Res = WasmEdge_VMRunWasmFromBytes(VMCxt, Bytes, FuncName, + Params, 2, Returns, 1); + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + printf("Data value: %d\n", Data); + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_ModuleInstanceDelete(HostModCxt); + return 0; + } + ``` + + Then you can compile and run: (the result of 1234 + 5678 is 6912) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Host function "Add": 1234 + 5678 + Get the result: 6912 + Data value: 6912 + ``` + +8. Host Data in Module Instance with Finalizer + + Besides setting host data into a host function, developers can set and move ownership of host data into a `Module` instance context with its finalizer. This may be useful when implementing the plug-ins. + + ```c + /* Struct definition. */ + typedef struct Point { + int X; + int Y; + } Point; + + /* Host function body definition. */ + WasmEdge_Result Print(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + Point *P = (Point *)In; + printf("Point: (%d, %d)\n", P->X, P->Y); + return WasmEdge_Result_Success; + } + + /* Finalizer definition. */ + void PointFinalizer(void *Data) { + if (Data) { + free((Point *)Data); + } + } + + /* Create a module instance with host data and its finalizer. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("module"); + Point *Data = (Point *)malloc(sizeof(Point)); + Data->X = 5; + Data->Y = -5; + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreateWithData(ExportName, Data, PointFinalizer); + /* + * When the `HostModCxt` being destroyed, the finalizer will be invoked and the + * `Data` will be its argument. + */ + WasmEdge_StringDelete(ExportName); + ``` + +### Plug-ins + +The WasmEdge plug-ins are the shared libraries to provide the WasmEdge runtime to load and create host module instances. With the plug-ins, the WasmEdge runtime can be extended more easily. + +#### Load plug-ins from paths + +To use the plug-ins, developers should load the plug-ins from paths first. + +```c +WasmEdge_PluginLoadWithDefaultPaths(); +``` + +After calling this API, the plug-ins in the default paths will be loaded. The default paths are: + +1. The path given in the environment variable `WASMEDGE_PLUGIN_PATH`. +2. The `../plugin/` directory related to the WasmEdge installation path. +3. The `./wasmedge/` directory under the library path if the WasmEdge is installed under the system directory (such as `/usr` and `/usr/local`). + +To load the plug-ins from a specific path or under a specific directory, developers can use this API: + +```c +WasmEdge_PluginLoadFromPath("PATH_TO_PLUGIN/plugin.so"); +``` + +#### Get the plug-in by name + +After loading the plug-ins, developers can list the loaded plug-in names. + +```c +WasmEdge_PluginLoadWithDefaultPaths(); +printf("Number of loaded plug-ins: %d\n", WasmEdge_PluginListPluginsLength()); + +WasmEdge_String Names[20]; +uint32_t NumPlugins = WasmEdge_PluginListPlugins(Names, 20); +for (int I = 0; I < NumPlugins; I++) { + printf("plug-in %d name: %s\n", I, Names[I].Buf); +} +``` + +And developers can retrieve the plug-in context by its name. + +```c +/* Assume that wasi_crypto plug-in is installed in the default plug-in path. */ +WasmEdge_PluginLoadWithDefaultPaths(); + +const char PluginName[] = "wasi_crypto"; +WasmEdge_String NameString = + WasmEdge_StringWrap(PluginName, strlen(PluginName)); +const WasmEdge_PluginContext *PluginCxt = WasmEdge_PluginFind(NameString); +``` + +#### Create the module instance from a plug-in + +With the plug-in context, developers can create the module instances by the module name. + +```c +/* Assume that the `PluginCxt` is the context to the wasi_crypto plug-in. */ + +/* List the available host modules in the plug-in. */ +WasmEdge_String Names[20]; +uint32_t ModuleLen = WasmEdge_PluginListModule(PluginCxt, Names, 20); +for (uint32_t I = 0; I < ModuleLen; I++) { + /* Will print the available host module names in the plug-in. */ + printf("%s\n", Names[I].Buf); +} +/* + * Will print here for the WASI-Crypto plug-in here: + * wasi_ephemeral_crypto_asymmetric_common + * wasi_ephemeral_crypto_common + * wasi_ephemeral_crypto_kx + * wasi_ephemeral_crypto_signatures + * wasi_ephemeral_crypto_symmetric + */ + +/* Create a module instance from the plug-in by the module name. */ +const char ModuleName[] = "wasi_ephemeral_crypto_common"; +WasmEdge_String NameString = + WasmEdge_StringWrap(ModuleName, strlen(ModuleName)); +WasmEdge_ModuleInstance *ModCxt = + WasmEdge_PluginCreateModule(PluginCxt, NameString); + +WasmEdge_ModuleInstanceDelete(ModCxt); +``` + +## WasmEdge AOT Compiler + +In this partition, we will introduce the WasmEdge AOT compiler and the options. + +WasmEdge runs the WASM files in interpreter mode, and WasmEdge also supports the AOT (ahead-of-time) mode running without modifying any code. The WasmEdge AOT (ahead-of-time) compiler compiles the WASM files for running in AOT mode which is much faster than interpreter mode. Developers can compile the WASM files into the compiled-WASM files in shared library format for universal WASM format for the AOT mode execution. + +### Compilation Example + +Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```c +#include +#include +int main() { + /* Create the configure context. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* ... Adjust settings in the configure context. */ + /* Result. */ + WasmEdge_Result Res; + + /* Create the compiler context. The configure context can be NULL. */ + WasmEdge_CompilerContext *CompilerCxt = WasmEdge_CompilerCreate(ConfCxt); + /* Compile the WASM file with input and output paths. */ + Res = WasmEdge_CompilerCompile(CompilerCxt, "fibonacci.wasm", + "fibonacci-aot.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("Compilation failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + + WasmEdge_CompilerDelete(CompilerCxt); + WasmEdge_ConfigureDelete(ConfCxt); + return 0; +} +``` + +Then you can compile and run (the output file is "fibonacci-aot.wasm"): + +```bash +$ gcc test.c -lwasmedge +$ ./a.out +[2021-07-02 11:08:08.651] [info] compile start +[2021-07-02 11:08:08.653] [info] verify start +[2021-07-02 11:08:08.653] [info] optimize start +[2021-07-02 11:08:08.670] [info] codegen start +[2021-07-02 11:08:08.706] [info] compile done +``` + +### Compiler Options + +Developers can set options for AOT compilers such as optimization level and output format: + +```c +/// AOT compiler optimization level enumeration. +enum WasmEdge_CompilerOptimizationLevel { + /// Disable as many optimizations as possible. + WasmEdge_CompilerOptimizationLevel_O0 = 0, + /// Optimize quickly without destroying debuggability. + WasmEdge_CompilerOptimizationLevel_O1, + /// Optimize for fast execution as much as possible without triggering + /// significant incremental compile time or code size growth. + WasmEdge_CompilerOptimizationLevel_O2, + /// Optimize for fast execution as much as possible. + WasmEdge_CompilerOptimizationLevel_O3, + /// Optimize for small code size as much as possible without triggering + /// significant incremental compile time or execution time slowdowns. + WasmEdge_CompilerOptimizationLevel_Os, + /// Optimize for small code size as much as possible. + WasmEdge_CompilerOptimizationLevel_Oz +}; + +/// AOT compiler output binary format enumeration. +enum WasmEdge_CompilerOutputFormat { + /// Native dynamic library format. + WasmEdge_CompilerOutputFormat_Native = 0, + /// WebAssembly with AOT compiled codes in custom sections. + WasmEdge_CompilerOutputFormat_Wasm +}; +``` + +Please refer to the [AOT compiler options configuration](#configurations) for details. + +## WasmEdge CLI Tools + +In this partition, we will introduce the C API for triggering the WasmEdge CLI tools. + +Besides executing the `wasmedge` and `wasmedgec` CLI tools, developers can trigger the WasmEdge CLI tools by WasmEdge C API. The API arguments are the same as the command line arguments of the CLI tools. + +### Runtime CLI + +The `WasmEdge_Driver_Tool()` API presents the same function as running the [`wasmedge run` command](../../../start/build-and-run/run.md). + +Noticed that this API presents the old `wasmedge` CLI tool, which is the same as the `wasmedge run` command. For the current unified `wasmedge` CLI, please refer to the [API below](#unified-cli). + +```c +#include +#include +int main(int argc, const char *argv[]) { + /* Run the WasmEdge runtime tool. */ + return WasmEdge_Driver_Tool(argc, argv); +} +``` + +### Compiler CLI + +The `WasmEdge_Driver_Compiler()` API presents the same function as running the [`wasmedge compile` tool](../../../start/build-and-run/aot.md). + +Noticed that this API presents the old `wasmedgec` CLI tool, which is the same as the `wasmedge compile` command. For the current unified `wasmedge` CLI, please refer to the [API below](#unified-cli). + +```c +#include +#include +int main(int argc, const char *argv[]) { + /* Run the WasmEdge AOT compiler. */ + return WasmEdge_Driver_Compiler(argc, argv); +} +``` + +### Unified CLI + +The `WasmEdge_Driver_UniTool()` API presents the same function as running the [`wasmedge` tool](../../../start/build-and-run/cli.md). + +```c +#include +#include +int main(int argc, const char *argv[]) { + /* Run the WasmEdge unified tool. */ + /* (Within both runtime and AOT compiler) */ + return WasmEdge_Driver_UniTool(argc, argv); +} +``` + +### CLI Helpers for Windows + +On Windows platforms, developers can use the `WasmEdge_Driver_ArgvCreate()` and `WasmEdge_Driver_ArgvDelete()` APIs to convert and handle the `UTF-8` command line arguments, or use the `WasmEdge_Driver_SetConsoleOutputCPtoUTF8()` API to set the console output code page to `UTF-8`. diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.15.x.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.15.x.md new file mode 100644 index 00000000..ac201d6b --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.15.x.md @@ -0,0 +1,3295 @@ +--- +sidebar_position: 3 +--- + +# C API 0.15.1 Documentation + +[WasmEdge C API](https://github.com/WasmEdge/WasmEdge/blob/master/include/api/wasmedge/wasmedge.h) denotes an interface to access the WasmEdge runtime at version `0.15.1`. The following are the guides to working with the C APIs of WasmEdge. + +**Developers can refer to [here to upgrade to v0.16.0](upgrade_to_0.16.0).** + +## WasmEdge Installation + +### Download And Install + +The easiest way to install WasmEdge is to run the following command. Your system should have `git` and `wget` as prerequisites. + +```bash +curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -v 0.15.1 +``` + +For more details, please refer to the [Installation Guide](../../../start/install.md#install) for the WasmEdge installation. + +### Compile Sources + +After the installation of WasmEdge, the following guide can help you to test for the availability of the WasmEdge C API. + +1. Prepare the test C file (and assumed saved as `test.c`): + + ```c + #include + #include + int main() { + printf("WasmEdge version: %s\n", WasmEdge_VersionGet()); + return 0; + } + ``` + +2. Compile the file with `gcc` or `clang`. + + ```bash + gcc test.c -lwasmedge + ``` + +3. Run and get the expected output. + + ```bash + $ ./a.out + WasmEdge version: 0.15.1 + ``` + +### ABI Compatibility + +WasmEdge C API introduces SONAME and SOVERSION since the `0.11.0` release to present the compatibility between different C API versions. + +The releases before 0.11.0 are all unversioned. Please make sure the library version is the same as the corresponding C API version you used. + +| WasmEdge Version | WasmEdge C API Library Name | WasmEdge C API SONAME | WasmEdge C API SOVERSION | +| --- | --- | --- | --- | +| < 0.11.0 | libwasmedge_c.so | Unversioned | Unversioned | +| 0.11.0 to 0.11.1 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.0 | +| 0.11.2 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.1 | +| 0.12.0 to 0.12.1 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.2 | +| 0.13.0 to 0.13.5 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.0.3 | +| Since 0.14.0 | libwasmedge.so | libwasmedge.so.0 | libwasmedge.so.0.1.0 | + +## WasmEdge Basics + +In this part, we will introduce the utilities and concepts of WasmEdge shared library. + +### Version + +The `Version` related APIs provide developers to check for the WasmEdge shared library version. + +```c +#include +printf("WasmEdge version: %s\n", WasmEdge_VersionGet()); +printf("WasmEdge version major: %u\n", WasmEdge_VersionGetMajor()); +printf("WasmEdge version minor: %u\n", WasmEdge_VersionGetMinor()); +printf("WasmEdge version patch: %u\n", WasmEdge_VersionGetPatch()); +``` + +### Logging Settings + +1. Setting logging levels + + The `WasmEdge_LogSetErrorLevel()` and `WasmEdge_LogSetDebugLevel()` APIs can set the logging system to debug level or error level. By default, the error level is set, and the debug info is hidden. + + Developers can set the logging level by the `WasmEdge_LogSetLevel()` API with the level enumeration: + + ```c + typedef enum WasmEdge_LogLevel { + WasmEdge_LogLevel_Trace, + WasmEdge_LogLevel_Debug, + WasmEdge_LogLevel_Info, + WasmEdge_LogLevel_Warn, + WasmEdge_LogLevel_Error, + WasmEdge_LogLevel_Critical, + } WasmEdge_LogLevel; + ``` + + Developers can also use the `WasmEdge_LogOff()` API to disable all logging. + +2. Logging callback + + For getting the detailed result or error message, WasmEdge provides the callback interface to register the customized callback function into the logging sink. + + Developers will get the message struct via the callback argument: + + ```c + typedef struct WasmEdge_LogMessage { + WasmEdge_String Message; + WasmEdge_String LoggerName; + WasmEdge_LogLevel Level; + time_t Time; + uint64_t ThreadId; + } WasmEdge_LogMessage; + ``` + + Developers can register the callback by the `WasmEdge_LogSetCallback()` API to receive the message when logging occurs. + + ```c + #include + void callback(const WasmEdge_LogMessage *Message) { + printf("Message: %s, LoggerName: %s\n", Message->Message.Buf, Message->LoggerName.Buf); + } + + int main() { + WasmEdge_LogSetCallback(callback); + return 0; + } + ``` + +### Value Types + +To describe the value types in WASM, WasmEdge uses the `WasmEdge_ValType` struct to encode the value types. + +1. Number types: `i32`, `i64`, `f32`, `f64`, and `v128` for the `SIMD` proposal + + ```c + WasmEdge_ValType ValType; + ValType = WasmEdge_ValTypeGenI32(); + bool IsTypeI32 = WasmEdge_ValTypeIsI32(ValType); + /* The `IsTypeI32` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenI64(); + bool IsTypeI64 = WasmEdge_ValTypeIsI64(ValType); + /* The `IsTypeI64` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenF32(); + bool IsTypeF32 = WasmEdge_ValTypeIsF32(ValType); + /* The `IsTypeF32` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenF64(); + bool IsTypeF64 = WasmEdge_ValTypeIsF64(ValType); + /* The `IsTypeF64` will be `TRUE`. */ + ValType = WasmEdge_ValTypeGenV128(); + bool IsTypeV128 = WasmEdge_ValTypeIsV128(ValType); + /* The `IsTypeV128` will be `TRUE`. */ + ``` + +2. Reference types: `funcref` and `externref` for the `Reference-Types` or `Typed-Function References` proposal + + ```c + WasmEdge_ValType ValType; + + ValType = WasmEdge_ValTypeGenFuncRef(); + /* The nullable funcref type is generated. */ + bool IsTypeFuncRef = WasmEdge_ValTypeIsFuncRef(ValType); + /* The `IsTypeFuncRef` will be `TRUE`. */ + bool IsTypeRef = WasmEdge_ValTypeIsRef(ValType); + /* The `IsTypeRef` will be `TRUE`. */ + bool IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(ValType); + /* The `IsTypeNullableRef` will be `TRUE`. */ + + ValType = WasmEdge_ValTypeGenExternRef(); + /* The nullable externref type is generated. */ + bool IsTypeExternRef = WasmEdge_ValTypeIsExternRef(ValType); + /* The `IsTypeExternRef` will be `TRUE`. */ + IsTypeRef = WasmEdge_ValTypeIsRef(ValType); + /* The `IsTypeRef` will be `TRUE`. */ + IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(ValType); + /* The `IsTypeNullableRef` will be `TRUE`. */ + ``` + +### Values + +In WasmEdge, developers should convert the values to `WasmEdge_Value` objects through APIs for matching to the WASM values for the arguments or returns. With the APIs, the output `WasmEdge_Value` objects will record the correct value types with values. + +1. Number types: `i32`, `i64`, `f32`, `f64`, and `v128` for the `SIMD` proposal + + ```c + WasmEdge_Value Val; + + Val = WasmEdge_ValueGenI32(123456); + bool IsTypeI32 = WasmEdge_ValTypeIsI32(Val.Type); + /* The `IsTypeI32` will be `TRUE`. */ + printf("%d\n", WasmEdge_ValueGetI32(Val)); + /* Will print "123456" */ + + Val = WasmEdge_ValueGenI64(1234567890123LL); + bool IsTypeI64 = WasmEdge_ValTypeIsI64(Val.Type); + /* The `IsTypeI64` will be `TRUE`. */ + printf("%ld\n", WasmEdge_ValueGetI64(Val)); + /* Will print "1234567890123" */ + + Val = WasmEdge_ValueGenF32(123.456f); + bool IsTypeF32 = WasmEdge_ValTypeIsF32(Val.Type); + /* The `IsTypeF32` will be `TRUE`. */ + printf("%f\n", WasmEdge_ValueGetF32(Val)); + /* Will print "123.456001" */ + + Val = WasmEdge_ValueGenF64(123456.123456789); + bool IsTypeF64 = WasmEdge_ValTypeIsF64(Val.Type); + /* The `IsTypeF64` will be `TRUE`. */ + printf("%.10f\n", WasmEdge_ValueGetF64(Val)); + /* Will print "123456.1234567890" */ + ``` + +2. Reference types: `funcref` and `externref` for the `Reference-Types` or `Typed-Function References` proposal + + ```c + WasmEdge_Value Val; + void *Ptr; + uint32_t Num = 10; + /* Generate an externref to NULL. */ + Val = WasmEdge_ValueGenExternRef(NULL); + bool IsNull = WasmEdge_ValueIsNullRef(Val); + /* The `IsNull` will be `TRUE`. */ + bool IsTypeExternRef = WasmEdge_ValTypeIsExternRef(Val.Type); + /* The `IsTypeExternRef` will be `TRUE`. */ + bool IsTypeRef = WasmEdge_ValTypeIsRef(Val.Type); + /* The `IsTypeRef` will be `TRUE`. */ + bool IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(Val.Type); + /* The `IsTypeNullableRef` will be `TRUE`. */ + Ptr = WasmEdge_ValueGetExternRef(Val); + /* The `Ptr` will be `NULL`. */ + + /* Get the function instance by creation or from module instance. */ + const WasmEdge_FunctionInstanceContext *FuncCxt = ...; + /* Generate a funcref with the given function instance context. */ + Val = WasmEdge_ValueGenFuncRef(FuncCxt); + bool IsTypeFuncRef = WasmEdge_ValTypeIsFuncRef(Val.Type); + /* The `IsTypeFuncRef` will be `TRUE`. */ + IsTypeRef = WasmEdge_ValTypeIsRef(Val.Type); + /* The `IsTypeRef` will be `TRUE`. */ + IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(Val.Type); + /* The `IsTypeNullableRef` will be `TRUE`. */ + const WasmEdge_FunctionInstanceContext *GotFuncCxt = + WasmEdge_ValueGetFuncRef(Val); + /* The `GotFuncCxt` will be the same as `FuncCxt`. */ + + /* Generate a externref to `Num`. */ + Val = WasmEdge_ValueGenExternRef(&Num); + Ptr = WasmEdge_ValueGetExternRef(Val); + /* The `Ptr` will be `&Num`. */ + printf("%u\n", *(uint32_t *)Ptr); + /* Will print "10" */ + Num += 55; + printf("%u\n", *(uint32_t *)Ptr); + /* Will print "65" */ + ``` + +### Buffers + +The `WasmEdge_Bytes` object is for the input buffer of loading or compiling module from memory, or the output buffer of serializing a module. + + +:::note +This object is designed for replacing raw buffer as input and output of WasmEdge C API. We recommand developers to use the `WasmEdge_Bytes` related APIs than the raw buffer, such as using `WasmEdge_LoaderParseFromBytes()` instead of `WasmEdge_LoaderParseFromBuffer()`. +::: + +1. Create a `WasmEdge_Bytes` from a buffer with length. + + ```c + uint8_t Buf[4] = {1, 2, 3, 4}; + WasmEdge_Bytes Bytes = WasmEdge_BytesCreate(Buf, 4); + /* The objects should be deleted by `WasmEdge_BytesDelete()`. */ + WasmEdge_BytesDelete(Bytes); + ``` + +2. Wrap a `WasmEdge_Bytes` to a buffer with length. + + The content will not be copied, and the caller should guarantee the life cycle of the input buffer. + + ```c + uint8_t Buf[4] = {1, 2, 3, 4}; + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(Buf, 4); + /* The object should __NOT__ be deleted by `WasmEdge_BytesDelete()`. */ + ``` + +### Strings + +The `WasmEdge_String` object is for the instance names when invoking a WASM function or finding the contexts of instances. + +1. Create a `WasmEdge_String` from a C string (`const char *` with NULL termination) or a buffer with length. + + The content of the C string or buffer will be copied into the `WasmEdge_String` object. + + ```c + char Buf[4] = {50, 55, 60, 65}; + WasmEdge_String Str1 = WasmEdge_StringCreateByCString("test"); + WasmEdge_String Str2 = WasmEdge_StringCreateByBuffer(Buf, 4); + /* The objects should be deleted by `WasmEdge_StringDelete()`. */ + WasmEdge_StringDelete(Str1); + WasmEdge_StringDelete(Str2); + ``` + +2. Wrap a `WasmEdge_String` to a buffer with length. + + The content will not be copied, and the caller should guarantee the life cycle of the input buffer. + + ```c + const char CStr[] = "test"; + WasmEdge_String Str = WasmEdge_StringWrap(CStr, 4); + /* The object should __NOT__ be deleted by `WasmEdge_StringDelete()`. */ + ``` + +3. String comparison + + ```c + const char CStr[] = "abcd"; + char Buf[4] = {0x61, 0x62, 0x63, 0x64}; + WasmEdge_String Str1 = WasmEdge_StringWrap(CStr, 4); + WasmEdge_String Str2 = WasmEdge_StringCreateByBuffer(Buf, 4); + bool IsEq = WasmEdge_StringIsEqual(Str1, Str2); + /* The `IsEq` will be `TRUE`. */ + WasmEdge_StringDelete(Str2); + ``` + +4. Convert to C string + + ```c + char Buf[256]; + WasmEdge_String Str = + WasmEdge_StringCreateByCString("test_wasmedge_string"); + uint32_t StrLength = WasmEdge_StringCopy(Str, Buf, sizeof(Buf)); + /* StrLength will be 20 */ + printf("String: %s\n", Buf); + /* Will print "test_wasmedge_string". */ + ``` + +### Results + +The `WasmEdge_Result` object specifies the execution status. APIs about WASM execution will return the `WasmEdge_Result` to denote the status. + +```c +WasmEdge_Result Res = WasmEdge_Result_Success; +bool IsSucceeded = WasmEdge_ResultOK(Res); +/* The `IsSucceeded` will be `TRUE`. */ +uint32_t Code = WasmEdge_ResultGetCode(Res); +/* The `Code` will be 0. */ +const char *Msg = WasmEdge_ResultGetMessage(Res); +/* The `Msg` will be "success". */ +enum WasmEdge_ErrCategory Category = WasmEdge_ResultGetCategory(Res); +/* The `Category` will be WasmEdge_ErrCategory_WASM. */ + +Res = WasmEdge_ResultGen(WasmEdge_ErrCategory_UserLevelError, 123); +/* Generate the user-defined result with code. */ +Code = WasmEdge_ResultGetCode(Res); +/* The `Code` will be 123. */ +Category = WasmEdge_ResultGetCategory(Res); +/* The `Category` will be WasmEdge_ErrCategory_UserLevelError. */ +``` + +### Contexts + +The objects, such as `VM`, `Store`, and `Function`, are composed of `Context`s. All of the contexts can be created by calling the corresponding creation APIs and should be destroyed by calling the corresponding deletion APIs. Developers have responsibilities to manage the contexts for memory management. + +```c +/* Create the configure context. */ +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); +/* Delete the configure context. */ +WasmEdge_ConfigureDelete(ConfCxt); +``` + +The details of other contexts will be introduced later. + +### WASM Data Structures + +The WASM data structures are used for creating instances or can be queried from instance contexts. The details of instances creation will be introduced in the [Instances](#instances). + +1. Limit + + The `WasmEdge_Limit` struct is defined in the header: + + ```c + /// Struct of WASM limit. + typedef struct WasmEdge_Limit { + /// Boolean to describe has max value or not. + bool HasMax; + /// Boolean to describe is shared memory or not. + bool Shared; + /// Minimum value. + uint32_t Min; + /// Maximum value. Will be ignored if the `HasMax` is false. + uint32_t Max; + } WasmEdge_Limit; + ``` + + Developers can initialize the struct by assigning it's value, and the `Max` value is needed to be larger or equal to the `Min` value. The API `WasmEdge_LimitIsEqual()` is provided to compare with 2 `WasmEdge_Limit` structs. + +2. Function type context + + The `Function Type` context is used for the `Function` creation, checking the value types of a `Function` instance, or getting the function type with function name from VM. Developers can use the `Function Type` context APIs to get the parameter or return value types information. + + ```c + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI64()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenFuncRef()}; + WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + + WasmEdge_ValType Buf[16]; + uint32_t ParamLen = WasmEdge_FunctionTypeGetParametersLength(FuncTypeCxt); + /* `ParamLen` will be 2. */ + uint32_t GotParamLen = WasmEdge_FunctionTypeGetParameters(FuncTypeCxt, Buf, 16); + /* + * `GotParamLen` will be 2, and `Buf[0]` and `Buf[1]` will be the same as + * `ParamList`. + */ + uint32_t ReturnLen = WasmEdge_FunctionTypeGetReturnsLength(FuncTypeCxt); + /* `ReturnLen` will be 1. */ + uint32_t GotReturnLen = WasmEdge_FunctionTypeGetReturns(FuncTypeCxt, Buf, 16); + /* + * `GotReturnLen` will be 1, and `Buf[0]` will be the same as `ReturnList`. + */ + + WasmEdge_FunctionTypeDelete(FuncTypeCxt); + ``` + +3. Table type context + + The `Table Type` context is used for `Table` instance creation or getting information from `Table` instances. + + ```c + WasmEdge_Limit TabLim = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_TableTypeCreate(WasmEdge_ValTypeGenExternRef(), TabLim); + + WasmEdge_ValType GotRefType = WasmEdge_TableTypeGetRefType(TabTypeCxt); + bool IsTypeExternRef = WasmEdge_ValTypeIsExternRef(GotRefType); + /* `IsTypeExternRef` will be `TRUE`. */ + bool IsTypeRef = WasmEdge_ValTypeIsRef(GotRefType); + /* `IsTypeRef` will be `TRUE`. */ + bool IsTypeNullableRef = WasmEdge_ValTypeIsRefNull(GotRefType); + /* `IsTypeNullableRef` will be `TRUE`. */ + WasmEdge_Limit GotTabLim = WasmEdge_TableTypeGetLimit(TabTypeCxt); + /* `GotTabLim` will be the same value as `TabLim`. */ + + WasmEdge_TableTypeDelete(TabTypeCxt); + ``` + +4. Memory type context + + The `Memory Type` context is used for `Memory` instance creation or getting information from `Memory` instances. + + ```c + WasmEdge_Limit MemLim = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + WasmEdge_MemoryTypeContext *MemTypeCxt = WasmEdge_MemoryTypeCreate(MemLim); + + WasmEdge_Limit GotMemLim = WasmEdge_MemoryTypeGetLimit(MemTypeCxt); + /* `GotMemLim` will be the same value as `MemLim`. */ + + WasmEdge_MemoryTypeDelete(MemTypeCxt) + ``` + +5. Global type context + + The `Global Type` context is used for `Global` instance creation or getting information from `Global` instances. + + ```c + WasmEdge_GlobalTypeContext *GlobTypeCxt = WasmEdge_GlobalTypeCreate( + WasmEdge_ValTypeGenF64(), WasmEdge_Mutability_Var); + + WasmEdge_ValType GotValType = WasmEdge_GlobalTypeGetValType(GlobTypeCxt); + bool IsTypeF64 = WasmEdge_ValTypeIsF64(GotValType); + /* `IsTypeF64` will be `TRUE`. */ + WasmEdge_Mutability GotValMut = + WasmEdge_GlobalTypeGetMutability(GlobTypeCxt); + /* `GotValMut` will be WasmEdge_Mutability_Var. */ + + WasmEdge_GlobalTypeDelete(GlobTypeCxt); + ``` + +6. Tag type context + + The `Tag Type` context is used for getting information from `Tag` instances. + This will only usable if the `Exception Handling` proposal turned on. + + ```c + /* Get the tag type from a tag instance. */ + const WasmEdge_TagTypeContext *TagTypeCxt = WasmEdge_TagInstanceGetTagType(...); + + const WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_TagTypeGetFunctionType(TagTypeCxt); + ``` + +7. Import type context + + The `Import Type` context is used for getting the imports information from a [AST Module](#ast-module). Developers can get the external type (`function`, `table`, `memory`, `tag`, or `global`), import module name, and external name from an `Import Type` context. The details about querying `Import Type` contexts will be introduced in the [AST Module](#ast-module). + + ```c + WasmEdge_ASTModuleContext *ASTCxt = ...; + /* + * Assume that `ASTCxt` is returned by the `WasmEdge_LoaderContext` for the + * result of loading a WASM file. + */ + const WasmEdge_ImportTypeContext *ImpType = ...; + /* Assume that `ImpType` is queried from the `ASTCxt` for the import. */ + + enum WasmEdge_ExternalType ExtType = + WasmEdge_ImportTypeGetExternalType(ImpType); + /* + * The `ExtType` can be one of `WasmEdge_ExternalType_Function`, + * `WasmEdge_ExternalType_Table`, `WasmEdge_ExternalType_Memory`, + * `WasmEdge_ExternalType_Tag`, or `WasmEdge_ExternalType_Global`. + */ + WasmEdge_String ModName = WasmEdge_ImportTypeGetModuleName(ImpType); + WasmEdge_String ExtName = WasmEdge_ImportTypeGetExternalName(ImpType); + /* + * The `ModName` and `ExtName` should not be destroyed and the string + * buffers are binded into the `ASTCxt`. + */ + const WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_ImportTypeGetFunctionType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Function`, the + * `FuncTypeCxt` will be NULL. + */ + const WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_ImportTypeGetTableType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Table`, the `TabTypeCxt` + * will be NULL. + */ + const WasmEdge_MemoryTypeContext *MemTypeCxt = + WasmEdge_ImportTypeGetMemoryType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Memory`, the `MemTypeCxt` + * will be NULL. + */ + const WasmEdge_TagTypeContext *TagTypeCxt = + WasmEdge_ImportTypeGetTagType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Tag`, the `TagTypeCxt` + * will be NULL. + */ + const WasmEdge_GlobalTypeContext *GlobTypeCxt = + WasmEdge_ImportTypeGetGlobalType(ASTCxt, ImpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Global`, the `GlobTypeCxt` + * will be NULL. + */ + ``` + +8. Export type context + + The `Export Type` context is used for getting the exports information from a [AST Module](#ast-module). Developers can get the external type (`function`, `table`, `memory`, `tag`, or `global`) and external name from an `Export Type` context. The details about querying `Export Type` contexts will be introduced in the [AST Module](#ast-module). + + ```c + WasmEdge_ASTModuleContext *ASTCxt = ...; + /* + * Assume that `ASTCxt` is returned by the `WasmEdge_LoaderContext` for the + * result of loading a WASM file. + */ + const WasmEdge_ExportTypeContext *ExpType = ...; + /* Assume that `ExpType` is queried from the `ASTCxt` for the export. */ + + enum WasmEdge_ExternalType ExtType = + WasmEdge_ExportTypeGetExternalType(ExpType); + /* + * The `ExtType` can be one of `WasmEdge_ExternalType_Function`, + * `WasmEdge_ExternalType_Table`, `WasmEdge_ExternalType_Memory`, + * `WasmEdge_ExternalType_Tag`, or `WasmEdge_ExternalType_Global`. + */ + WasmEdge_String ExtName = WasmEdge_ExportTypeGetExternalName(ExpType); + /* + * The `ExtName` should not be destroyed and the string buffer is binded + * into the `ASTCxt`. + */ + const WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_ExportTypeGetFunctionType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Function`, the + * `FuncTypeCxt` will be NULL. + */ + const WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_ExportTypeGetTableType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Table`, the `TabTypeCxt` + * will be NULL. + */ + const WasmEdge_MemoryTypeContext *MemTypeCxt = + WasmEdge_ExportTypeGetMemoryType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Memory`, the `MemTypeCxt` + * will be NULL. + */ + const WasmEdge_TagTypeContext *TagTypeCxt = + WasmEdge_ExportTypeGetTagType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Tag`, the `TagTypeCxt` + * will be NULL. + */ + const WasmEdge_GlobalTypeContext *GlobTypeCxt = + WasmEdge_ExportTypeGetGlobalType(ASTCxt, ExpType); + /* + * If the `ExtType` is not `WasmEdge_ExternalType_Global`, the `GlobTypeCxt` + * will be NULL. + */ + ``` + +### Async + +After calling the [asynchronous execution APIs](#asynchronous-execution), developers will get the `WasmEdge_Async` object. Developers own the object and should call the `WasmEdge_AsyncDelete()` API to destroy it. + +1. Wait for the asynchronous execution + + Developers can wait the execution until finished: + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* Blocking and waiting for the execution. */ + WasmEdge_AsyncWait(Async); + WasmEdge_AsyncDelete(Async); + ``` + + Or developers can wait for a time limit. If the time limit exceeded, developers can choose to cancel the execution. For the interruptible execution in AOT mode, developers should set `TRUE` through the `WasmEdge_ConfigureCompilerSetInterruptible()` API into the configure context for the AOT compiler. + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* Blocking and waiting for the execution for 1 second. */ + bool IsEnd = WasmEdge_AsyncWaitFor(Async, 1000); + if (IsEnd) { + /* The execution finished. Developers can get the result. */ + WasmEdge_Result Res = WasmEdge_AsyncGet(/* ... Ignored */); + } else { + /* + * The time limit exceeded. Developers can keep waiting or cancel the + * execution. + */ + WasmEdge_AsyncCancel(Async); + WasmEdge_Result Res = WasmEdge_AsyncGet(Async, 0, NULL); + /* The result error code will be `WasmEdge_ErrCode_Interrupted`. */ + } + WasmEdge_AsyncDelete(Async); + ``` + +2. Get the execution result of the asynchronous execution + + Developers can use the `WasmEdge_AsyncGetReturnsLength()` API to get the return value list length. This function will block and wait for the execution. If the execution has finished, this function will return the length immediately. If the execution failed, this function will return `0`. This function can help the developers to create the buffer to get the return values. If developers have already known the buffer length, they can skip this function and use the `WasmEdge_AsyncGet()` API to get the result. + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* + * Blocking and waiting for the execution and get the return value list + * length. + */ + uint32_t Arity = WasmEdge_AsyncGetReturnsLength(Async); + WasmEdge_AsyncDelete(Async); + ``` + + The `WasmEdge_AsyncGet()` API will block and wait for the execution. If the execution has finished, this function will fill the return values into the buffer and return the execution result immediately. + + ```c + WasmEdge_Async *Async = ...; /* Ignored. Asynchronous execute a function. */ + /* Blocking and waiting for the execution and get the return values. */ + const uint32_t BUF_LEN = 256; + WasmEdge_Value Buf[BUF_LEN]; + WasmEdge_Result Res = WasmEdge_AsyncGet(Async, Buf, BUF_LEN); + WasmEdge_AsyncDelete(Async); + ``` + +### Configurations + +The configuration context, `WasmEdge_ConfigureContext`, manages the configurations for `Loader`, `Validator`, `Executor`, `VM`, and `Compiler` contexts. Developers can adjust the settings about the proposals, VM host pre-registrations (such as `WASI`), and AOT compiler options, and then apply the `Configure` context to create the runtime contexts. + +1. Proposals + + WasmEdge supports turning on or off the WebAssembly proposals. This configuration is effective in any contexts created with the `Configure` context. + + ```c + enum WasmEdge_Proposal { + WasmEdge_Proposal_ImportExportMutGlobals = 0, + WasmEdge_Proposal_NonTrapFloatToIntConversions, + WasmEdge_Proposal_SignExtensionOperators, + WasmEdge_Proposal_MultiValue, + WasmEdge_Proposal_BulkMemoryOperations, + WasmEdge_Proposal_ReferenceTypes, + WasmEdge_Proposal_SIMD, + WasmEdge_Proposal_TailCall, + WasmEdge_Proposal_ExtendedConst, + WasmEdge_Proposal_FunctionReferences, + WasmEdge_Proposal_GC, + WasmEdge_Proposal_MultiMemories, + WasmEdge_Proposal_RelaxSIMD, + WasmEdge_Proposal_Annotations, + WasmEdge_Proposal_Threads, + WasmEdge_Proposal_ExceptionHandling, + WasmEdge_Proposal_Memory64, + WasmEdge_Proposal_Component, + }; + ``` + + Developers can add or remove the proposals into the `Configure` context. + + ```c + /* + * By default, the following proposals have turned on initially: + * * Import/Export of mutable globals + * * Non-trapping float-to-int conversions + * * Sign-extension operators + * * Multi-value returns + * * Bulk memory operations + * * Reference types + * * Fixed-width SIMD + * + * For the current WasmEdge version, the following proposals are supported + * (turned off by default) additionally: + * * Tail-call + * * Extended-const + * * Typed-function references + * * GC + * * Multiple memories + * * Relaxed SIMD + * * Threads + * * Exception handling (interpreter only) + * * Component model (loader phase only) + */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddProposal(ConfCxt, WasmEdge_Proposal_MultiMemories); + WasmEdge_ConfigureRemoveProposal(ConfCxt, WasmEdge_Proposal_ReferenceTypes); + bool IsBulkMem = WasmEdge_ConfigureHasProposal( + ConfCxt, WasmEdge_Proposal_BulkMemoryOperations); + /* The `IsBulkMem` will be `TRUE`. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +2. Host registrations + + This configuration is used for the `VM` context to turn on the `WASI` supports and only effective in `VM` contexts. + + The element of this enum is reserved for the other built-in host functions (such as `wasi-socket`) in the future. + + ```c + enum WasmEdge_HostRegistration { + WasmEdge_HostRegistration_Wasi = 0 + }; + ``` + + The details will be introduced in the [preregistrations of VM context](#built-in-host-modules-and-plug-in-preregistrations). + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + bool IsHostWasi = WasmEdge_ConfigureHasHostRegistration( + ConfCxt, WasmEdge_HostRegistration_Wasi); + /* The `IsHostWasi` will be `FALSE`. */ + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + IsHostWasi = WasmEdge_ConfigureHasHostRegistration( + ConfCxt, WasmEdge_HostRegistration_Wasi); + /* The `IsHostWasi` will be `TRUE`. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +3. Maximum memory pages + + Developers can limit the page size of memory instances by this configuration. When growing the page size of memory instances in WASM execution and exceeding the limited size, the page growing will fail. This configuration is only effective in the `Executor` and `VM` contexts. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + uint32_t PageSize = WasmEdge_ConfigureGetMaxMemoryPage(ConfCxt); + /* By default, the maximum memory page size is 65536. */ + WasmEdge_ConfigureSetMaxMemoryPage(ConfCxt, 1024); + /* + * Limit the memory size of each memory instance with not larger than 1024 + * pages (64 MiB). + */ + PageSize = WasmEdge_ConfigureGetMaxMemoryPage(ConfCxt); + /* The `PageSize` will be 1024. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +4. Forcibly interpreter mode + + If developers want to execute the WASM file or the AOT compiled WASM in interpreter mode forcibly, they can turn on the configuration. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + bool IsForceInterp = WasmEdge_ConfigureIsForceInterpreter(ConfCxt); + /* By default, The `IsForceInterp` will be `FALSE`. */ + WasmEdge_ConfigureSetForceInterpreter(ConfCxt, TRUE); + IsForceInterp = WasmEdge_ConfigureIsForceInterpreter(ConfCxt); + /* The `IsForceInterp` will be `TRUE`. */ + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +5. AOT compiler options + + The AOT compiler options configure the behavior about optimization level, output format, dump IR, and generic binary. + + ```c + enum WasmEdge_CompilerOptimizationLevel { + // Disable as many optimizations as possible. + WasmEdge_CompilerOptimizationLevel_O0 = 0, + // Optimize quickly without destroying debuggability. + WasmEdge_CompilerOptimizationLevel_O1, + // Optimize for fast execution as much as possible without triggering + // significant incremental compile time or code size growth. + WasmEdge_CompilerOptimizationLevel_O2, + // Optimize for fast execution as much as possible. + WasmEdge_CompilerOptimizationLevel_O3, + // Optimize for small code size as much as possible without triggering + // significant incremental compile time or execution time slowdowns. + WasmEdge_CompilerOptimizationLevel_Os, + // Optimize for small code size as much as possible. + WasmEdge_CompilerOptimizationLevel_Oz + }; + + enum WasmEdge_CompilerOutputFormat { + // Native dynamic library format. + WasmEdge_CompilerOutputFormat_Native = 0, + // WebAssembly with AOT compiled codes in custom section. + WasmEdge_CompilerOutputFormat_Wasm + }; + ``` + + These configurations are only effective in `Compiler` contexts. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* By default, the optimization level is O3. */ + WasmEdge_ConfigureCompilerSetOptimizationLevel( + ConfCxt, WasmEdge_CompilerOptimizationLevel_O2); + /* By default, the output format is universal WASM. */ + WasmEdge_ConfigureCompilerSetOutputFormat( + ConfCxt, WasmEdge_CompilerOutputFormat_Native); + /* By default, the dump IR is `FALSE`. */ + WasmEdge_ConfigureCompilerSetDumpIR(ConfCxt, TRUE); + /* By default, the generic binary is `FALSE`. */ + WasmEdge_ConfigureCompilerSetGenericBinary(ConfCxt, TRUE); + /* By default, the interruptible is `FALSE`. + /* Set this option to `TRUE` to support the interruptible execution in AOT + mode. */ + WasmEdge_ConfigureCompilerSetInterruptible(ConfCxt, TRUE); + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +6. Statistics options + + The statistics options configure the behavior about instruction counting, cost measuring, and time measuring in both runtime and AOT compiler. These configurations are effective in `Compiler`, `VM`, and `Executor` contexts. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* + * By default, the instruction counting is `FALSE` when running a + * compiled-WASM or a pure-WASM. + */ + WasmEdge_ConfigureStatisticsSetInstructionCounting(ConfCxt, TRUE); + /* + * By default, the cost measurement is `FALSE` when running a compiled-WASM + * or a pure-WASM. + */ + WasmEdge_ConfigureStatisticsSetCostMeasuring(ConfCxt, TRUE); + /* + * By default, the time measurement is `FALSE` when running a compiled-WASM + * or a pure-WASM. + */ + WasmEdge_ConfigureStatisticsSetTimeMeasuring(ConfCxt, TRUE); + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +### Statistics + +The statistics context, `WasmEdge_StatisticsContext`, provides the instruction counter, cost summation, and cost limitation at runtime. + +Before using statistics, the statistics configuration must be set. Otherwise, the return values of calling statistics are undefined behaviour. + +1. Instruction counter + + The instruction counter can help developers to profile the performance of WASM running. Developers can retrieve the `Statistics` context from the `VM` context, or create a new one for the `Executor` creation. The details will be introduced in the next partitions. + + ```c + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * ... + * After running the WASM functions with the `Statistics` context + */ + uint32_t Count = WasmEdge_StatisticsGetInstrCount(StatCxt); + double IPS = WasmEdge_StatisticsGetInstrPerSecond(StatCxt); + WasmEdge_StatisticsDelete(StatCxt); + ``` + +2. Cost table + + The cost table is to accumulate the cost of instructions with their weights. Developers can set the cost table array (the indices are the byte code value of instructions, and the values are the cost of instructions) into the `Statistics` context. If the cost limit value is set, the execution will return the `cost limit exceeded` error immediately when exceeds the cost limit in runtime. + + ```c + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + uint64_t CostTable[16] = { + 0, 0, + 10, /* 0x02: Block */ + 11, /* 0x03: Loop */ + 12, /* 0x04: If */ + 12, /* 0x05: Else */ + 0, 0, 0, 0, 0, 0, + 20, /* 0x0C: Br */ + 21, /* 0x0D: Br_if */ + 22, /* 0x0E: Br_table */ + 0 + }; + /* + * Developers can set the costs of each instruction. The value not + * covered will be 0. + */ + WasmEdge_StatisticsSetCostTable(StatCxt, CostTable, 16); + WasmEdge_StatisticsSetCostLimit(StatCxt, 5000000); + /* + * ... + * After running the WASM functions with the `Statistics` context + */ + uint64_t Cost = WasmEdge_StatisticsGetTotalCost(StatCxt); + WasmEdge_StatisticsDelete(StatCxt); + ``` + +## WasmEdge VM + +In this partition, we will introduce the functions of `WasmEdge_VMContext` object and show examples of executing WASM functions. + +### WASM Execution Example With VM Context + +The following shows the example of running the WASM for getting the Fibonacci. This example uses the [fibonacci.wat](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat). + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```wasm +(module + (export "fib" (func $fib)) + (func $fib (param $n i32) (result i32) + (if + (i32.lt_s (get_local $n)(i32.const 2)) + (return (i32.const 1)) + ) + (return + (i32.add + (call $fib (i32.sub (get_local $n)(i32.const 2))) + (call $fib (i32.sub (get_local $n)(i32.const 1))) + ) + ) + ) +) +``` + +1. Run WASM functions rapidly + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + #include + #include + int main() { + /* Create the configure context and add the WASI support. */ + /* This step is not necessary unless you need WASI support. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + /* The configure and store context to the VM creation can be NULL. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(5)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Run the WASM function from file. */ + WasmEdge_Result Res = WasmEdge_VMRunWasmFromFile( + VMCxt, "fibonacci.wasm", FuncName, Params, 1, Returns, 1); + /* + * Developers can run the WASM binary from buffer with the + * `WasmEdge_VMRunWasmFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMRunWasmFromASTModule()` API. + */ + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_ConfigureDelete(ConfCxt); + WasmEdge_StringDelete(FuncName); + return 0; + } + ``` + + Then you can compile and run: (the 5th Fibonacci number is 8 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 8 + ``` + +2. Instantiate and run WASM functions manually + + Besides the above example, developers can run the WASM functions step-by-step with `VM` context APIs: + + ```c + #include + #include + int main() { + /* Create the configure context and add the WASI support. */ + /* This step is not necessary unless you need the WASI support. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + /* The configure and store context to the VM creation can be NULL. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(10)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Step 1: Load WASM file. */ + Res = WasmEdge_VMLoadWasmFromFile(VMCxt, "fibonacci.wasm"); + /* + * Developers can load the WASM binary from buffer with the + * `WasmEdge_VMLoadWasmFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMLoadWasmFromASTModule()` API. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 2: Validate the WASM module. */ + Res = WasmEdge_VMValidate(VMCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 3: Instantiate the WASM module. */ + Res = WasmEdge_VMInstantiate(VMCxt); + /* + * Developers can load, validate, and instantiate another WASM module to + * replace the instantiated one. In this case, the old module will be + * cleared, but the registered modules are still kept. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Instantiation phase failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * Step 4: Execute WASM functions. You can execute functions repeatedly + * after instantiation. + */ + Res = WasmEdge_VMExecute(VMCxt, FuncName, Params, 1, Returns, 1); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_ConfigureDelete(ConfCxt); + WasmEdge_StringDelete(FuncName); + return 0; + } + ``` + + Then you can compile and run: (the 10th Fibonacci number is 89 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 89 + ``` + + The following graph explains the status of the `VM` context. + + ```text + |========================| + |------->| VM: Initiated | + | |========================| + | | + | LoadWasm + | | + | v + | |========================| + |--------| VM: Loaded |<-------| + | |========================| | + | | ^ | + | Validate | | + Cleanup | LoadWasm | + | v | LoadWasm + | |========================| | + |--------| VM: Validated | | + | |========================| | + | | ^ | + | Instantiate | | + | | RegisterModule | + | v | | + | |========================| | + |--------| VM: Instantiated |--------| + |========================| + | ^ + | | + -------------- + Instantiate, Execute, ExecuteRegistered + ``` + + The status of the `VM` context would be `Inited` when created. After loading WASM successfully, the status will be `Loaded`. After validating WASM successfully, the status will be `Validated`. After instantiating WASM successfully, the status will be `Instantiated`, and developers can invoke functions. Developers can register WASM or module instances in any status, but they should instantiate WASM again. Developers can also load WASM in any status, and they should validate and instantiate the WASM module before function invocation. When in the `Instantiated` status, developers can instantiate the WASM module again to reset the old WASM runtime structures. + +### VM Creations + +The `VM` creation API accepts the `Configure` context and the `Store` context. If developers only need the default settings, just pass `NULL` to the creation API. The details of the `Store` context will be introduced in [Store](#store). + +```c +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); +WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); +WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, StoreCxt); +/* The caller should guarantee the life cycle if the store context. */ +WasmEdge_StatisticsContext *StatCxt = WasmEdge_VMGetStatisticsContext(VMCxt); +/* + * The VM context already contains the statistics context and can be retrieved + * by this API. + */ +/* + * Note that the retrieved store and statistics contexts from the VM contexts by + * VM APIs should __NOT__ be destroyed and owned by the VM contexts. + */ +WasmEdge_VMDelete(VMCxt); +WasmEdge_StoreDelete(StoreCxt); +WasmEdge_ConfigureDelete(ConfCxt); +``` + +### Built-in Host Modules and Plug-in Preregistrations + +WasmEdge provides the following built-in host modules and plug-in pre-registrations. + +1. [WASI (WebAssembly System Interface)](https://github.com/WebAssembly/WASI) + + Developers can turn on the WASI support for VM in the `Configure` context. + + ```c + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + WasmEdge_ConfigureDelete(ConfCxt); + /* + * The following API can retrieve the built-in registered module instances + * from the VM context. + */ + /* + * This API will return `NULL` if the corresponding configuration is not set + * when creating the VM context. + */ + WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_VMGetImportModuleContext(VMCxt, + WasmEdge_HostRegistration_Wasi); + /* Initialize the WASI. */ + WasmEdge_ModuleInstanceInitWASI(WasiModule, /* ... ignored */); + WasmEdge_VMDelete(VMCxt); + ``` + + And also can create the WASI module instance from API. The details will be introduced in the [Host Functions](#host-functions) and the [Host Module Registrations](#host-module-registrations). + +2. Plug-ins + + There may be several plug-ins in the default plug-in paths if users [installed WasmEdge plug-ins by the installer](../../../start/install.md#install-wasmedge-plug-ins-and-dependencies). + + Before using the plug-ins, developers should [load the plug-ins from paths](#load-plug-ins-from-paths). + + The `VM` context will automatically create and register the module of the loaded plug-ins when creation. Furthermore, the following host modules will be mocked if the plug-in not loaded: + + - `wasi_ephemeral_crypto_asymmetric_common` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_common` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_kx` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_signatures` (for the `WASI-Crypto`) + - `wasi_ephemeral_crypto_symmetric` (for the `WASI-Crypto`) + - `wasi_ephemeral_nn` + - `wasi_snapshot_preview1` + - `wasmedge_httpsreq` + - `wasmedge_process` + + When the WASM want to invoke these host functions but the corresponding plug-in not installed, WasmEdge will print the error message and return an error. + + ```c + /* Load the plug-ins in the default paths first. */ + WasmEdge_PluginLoadWithDefaultPaths(); + /* Create the configure context and add the WASI configuration. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + WasmEdge_ConfigureAddHostRegistration(ConfCxt, + WasmEdge_HostRegistration_Wasi); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(ConfCxt, NULL); + WasmEdge_ConfigureDelete(ConfCxt); + /* + * The following API can retrieve the registered modules in the VM context, + * includes the built-in WASI and the plug-ins. + */ + /* + * This API will return `NULL` if the module instance not found. + */ + WasmEdge_String WasiName = + WasmEdge_StringCreateByCString("wasi_snapshot_preview1"); + /* The `WasiModule` will not be `NULL` because the configuration was set. */ + const WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_VMGetRegisteredModule(VMCxt, WasiName); + WasmEdge_StringDelete(WasiName); + WasmEdge_String WasiNNName = + WasmEdge_StringCreateByCString("wasi_ephemeral_nn"); + /* + * The `WasiNNModule` will not be `NULL` even if the wasi_nn plug-in is not + * installed, because the VM context will mock and register the host + * modules. + */ + const WasmEdge_ModuleInstanceContext *WasiNNModule = + WasmEdge_VMGetRegisteredModule(VMCxt, WasiNNName); + WasmEdge_StringDelete(WasiNNName); + + WasmEdge_VMDelete(VMCxt); + ``` + +### Host Module Registrations + +[Host functions](https://webassembly.github.io/spec/core/exec/runtime.html#syntax-hostfunc) are functions outside WebAssembly and passed to WASM modules as imports. In WasmEdge, the host functions are composed into host modules as `WasmEdge_ModuleInstanceContext` objects with module names. Please refer to the [Host Functions in WasmEdge Runtime](#host-functions) for the details. + +In this chapter, we show the example for registering the host modules into a `VM` context. Noticed that the developers should guarantee the availability of the registered module instance, and should delete the module instance when it will not be used. + +```c +WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); +WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_ModuleInstanceCreateWASI(/* ... ignored ... */); +/* You can also create and register the WASI host modules by this API. */ +WasmEdge_Result Res = WasmEdge_VMRegisterModuleFromImport(VMCxt, WasiModule); +/* The result status should be checked. */ + +/* ... */ + +WasmEdge_VMDelete(VMCxt); +WasmEdge_ModuleInstanceDelete(WasiModule); +/* + * The created module instances should be deleted by the developers when the VM + * deallocation. + */ +``` + +### WASM Registrations And Executions + +In WebAssembly, the instances in WASM modules can be exported and can be imported by other WASM modules. WasmEdge VM provides APIs for developers to register and export any WASM modules, and execute the functions or host functions in the registered WASM modules. + +1. Register the WASM modules with exported module names + + Unless the module instances have already contained the module names, every WASM module should be named uniquely when registering. + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_Result Res = + WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + /* + * Developers can register the WASM module from buffer with the + * `WasmEdge_VMRegisterModuleFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMRegisterModuleFromASTModule()` API. + */ + /* + * The result status should be checked. + * The error will occur if the WASM module instantiation failed or the + * module name conflicts. + */ + WasmEdge_StringDelete(ModName); + WasmEdge_VMDelete(VMCxt); + ``` + +2. Execute the functions in registered WASM modules + + Assume that the C file `test.c` is as follows: + + ```c + #include + #include + int main() { + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(20)}; + WasmEdge_Value Returns[1]; + /* Names. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Register the WASM module into VM. */ + Res = WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + /* + * Developers can register the WASM module from buffer with the + * `WasmEdge_VMRegisterModuleFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMRegisterModuleFromASTModule()` API. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * The function "fib" in the "fibonacci.wasm" was exported with the module + * name "mod". As the same as host functions, other modules can import the + * function `"mod" "fib"`. + */ + + /* + * Execute WASM functions in registered modules. + * Unlike the execution of functions, the registered functions can be + * invoked without `WasmEdge_VMInstantiate()` because the WASM module was + * instantiated when registering. Developers can also invoke the host + * functions directly with this API. + */ + Res = WasmEdge_VMExecuteRegistered(VMCxt, ModName, FuncName, Params, 1, + Returns, 1); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + WasmEdge_StringDelete(ModName); + WasmEdge_StringDelete(FuncName); + WasmEdge_VMDelete(VMCxt); + return 0; + } + ``` + + Then you can compile and run: (the 20th Fibonacci number is 89 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 10946 + ``` + +3. Forcibly delete the registered WASM modules + + For instantiated and registered modules in VM context, developers can use the `WasmEdge_VMForceDeleteRegisteredModule()` API to forcibly delete and unregister the module instance by name. + + + :::note + This API doesn't check the module instance dependencies for exporting and importing. Developers should guarantee the module dependencies by theirselves when using this API. The safer API will be provided in the future. + ::: + + ```c + #include + #include + int main() { + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* Names. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Register the WASM module into VM. */ + Res = WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * The function "fib" in the "fibonacci.wasm" was exported with the module + * name "mod". As the same as host functions, other modules can import the + * function `"mod" "fib"`. + */ + + /* Forcibly delete the registered module. */ + WasmEdge_VMForceDeleteRegisteredModule(VMCxt, ModName); + + WasmEdge_StringDelete(ModName); + WasmEdge_StringDelete(FuncName); + WasmEdge_VMDelete(VMCxt); + return 0; + } + ``` + +### Asynchronous Execution + +1. Asynchronously run WASM functions rapidly + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + #include + #include + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(20)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Asynchronously run the WASM function from file and get the + * `WasmEdge_Async` object. */ + WasmEdge_Async *Async = WasmEdge_VMAsyncRunWasmFromFile( + VMCxt, "fibonacci.wasm", FuncName, Params, 1); + /* + * Developers can run the WASM binary from buffer with the + * `WasmEdge_VMAsyncRunWasmFromBytes()` API, or from + * `WasmEdge_ASTModuleContext` object with the + * `WasmEdge_VMAsyncRunWasmFromASTModule()` API. + */ + + /* Wait for the execution. */ + WasmEdge_AsyncWait(Async); + /* + * Developers can also use the `WasmEdge_AsyncGetReturnsLength()` or + * `WasmEdge_AsyncGet()` APIs to wait for the asynchronous execution. + * These APIs will wait until the execution finished. + */ + + /* Check the return values length. */ + uint32_t Arity = WasmEdge_AsyncGetReturnsLength(Async); + /* The `Arity` should be 1. Developers can skip this step if they have + * known the return arity. */ + + /* Get the result. */ + WasmEdge_Result Res = WasmEdge_AsyncGet(Async, Returns, Arity); + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_AsyncDelete(Async); + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + return 0; + } + ``` + + Then you can compile and run: (the 20th Fibonacci number is 10946 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 10946 + ``` + +2. Instantiate and asynchronously run WASM functions manually + + Besides the above example, developers can run the WASM functions step-by-step with `VM` context APIs: + + ```c + #include + #include + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(25)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Step 1: Load WASM file. */ + Res = WasmEdge_VMLoadWasmFromFile(VMCxt, "fibonacci.wasm"); + /* + * Developers can load the WASM binary from buffer with the + * `WasmEdge_VMLoadWasmFromBytes()` API, or from `WasmEdge_ASTModuleContext` + * object with the `WasmEdge_VMLoadWasmFromASTModule()` API. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 2: Validate the WASM module. */ + Res = WasmEdge_VMValidate(VMCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 3: Instantiate the WASM module. */ + Res = WasmEdge_VMInstantiate(VMCxt); + /* + * Developers can load, validate, and instantiate another WASM module to + * replace the instantiated one. In this case, the old module will be + * cleared, but the registered modules are still kept. + */ + if (!WasmEdge_ResultOK(Res)) { + printf("Instantiation phase failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Step 4: Asynchronously execute the WASM function and get the + * `WasmEdge_Async` object. */ + WasmEdge_Async *Async = + WasmEdge_VMAsyncExecute(VMCxt, FuncName, Params, 1); + /* + * Developers can execute functions repeatedly after instantiation. + * For invoking the registered functions, you can use the + * `WasmEdge_VMAsyncExecuteRegistered()` API. + */ + + /* Wait and check the return values length. */ + uint32_t Arity = WasmEdge_AsyncGetReturnsLength(Async); + /* The `Arity` should be 1. Developers can skip this step if they have + * known the return arity. */ + + /* Get the result. */ + Res = WasmEdge_AsyncGet(Async, Returns, Arity); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_AsyncDelete(Async); + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + } + ``` + + Then you can compile and run: (the 25th Fibonacci number is 121393 in 0-based index) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get the result: 121393 + ``` + +### Instance Tracing + +Sometimes the developers may have requirements to get the instances of the WASM runtime. The `VM` context supplies the APIs to retrieve the instances. + +1. Store + + If the `VM` context is created without assigning a `Store` context, the `VM` context will allocate and own a `Store` context. + + ```c + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + WasmEdge_StoreContext *StoreCxt = WasmEdge_VMGetStoreContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_StoreDelete()`. */ + WasmEdge_VMDelete(VMCxt); + ``` + + Developers can also create the `VM` context with a `Store` context. In this case, developers should guarantee the life cycle of the `Store` context. Please refer to the [Store Contexts](#store) for the details about the `Store` context APIs. + + ```c + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, StoreCxt); + WasmEdge_StoreContext *StoreCxtMock = WasmEdge_VMGetStoreContext(VMCxt); + /* The `StoreCxt` and the `StoreCxtMock` are the same. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StoreDelete(StoreCxt); + ``` + +2. List exported functions + + After the WASM module instantiation, developers can use the `WasmEdge_VMExecute()` API to invoke the exported WASM functions. For this purpose, developers may need information about the exported WASM function list. Please refer to the [Instances in runtime](#instances) for the details about the function types. + + Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + + :::note + `fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). + ::: + + ```c + #include + #include + int main() { + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, StoreCxt); + + WasmEdge_VMLoadWasmFromFile(VMCxt, "fibonacci.wasm"); + WasmEdge_VMValidate(VMCxt); + WasmEdge_VMInstantiate(VMCxt); + + /* List the exported functions. */ + /* Get the number of exported functions. */ + uint32_t FuncNum = WasmEdge_VMGetFunctionListLength(VMCxt); + /* Create the name buffers and the function type buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String FuncNames[BUF_LEN]; + WasmEdge_FunctionTypeContext *FuncTypes[BUF_LEN]; + /* + * Get the export function list. + * If the function list length is larger than the buffer length, the + * overflowed data will be discarded. The `FuncNames` and `FuncTypes` can + * be NULL if developers don't need them. + */ + uint32_t RealFuncNum = + WasmEdge_VMGetFunctionList(VMCxt, FuncNames, FuncTypes, BUF_LEN); + + for (uint32_t I = 0; I < RealFuncNum && I < BUF_LEN; I++) { + char Buf[BUF_LEN]; + uint32_t Size = WasmEdge_StringCopy(FuncNames[I], Buf, sizeof(Buf)); + printf("Get exported function string length: %u, name: %s\n", Size, + Buf); + /* + * The function names should be __NOT__ destroyed. + * The returned function type contexts should __NOT__ be destroyed. + */ + } + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_VMDelete(VMCxt); + return 0; + } + ``` + + Then you can compile and run: (the only exported function in `fibonacci.wasm` is `fib`) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Get exported function string length: 3, name: fib + ``` + + If developers want to get the exported function names in the registered WASM modules, please retrieve the `Store` context from the `VM` context and refer to the APIs of [Store Contexts](#store) to list the registered functions by the module name. + +3. Get function types + + The `VM` context provides APIs to find the function type by function name. Please refer to the [Instances in runtime](#instances) for the details about the function types. + + ```c + /* + * ... + * Assume that a WASM module is instantiated in `VMCxt`. + */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + const WasmEdge_FunctionTypeContext *FuncType = + WasmEdge_VMGetFunctionType(VMCxt, FuncName); + /* + * Developers can get the function types of functions in the registered + * modules via the `WasmEdge_VMGetFunctionTypeRegistered()` API with the + * module name. If the function is not found, these APIs will return `NULL`. + * The returned function type contexts should __NOT__ be destroyed. + */ + WasmEdge_StringDelete(FuncName); + ``` + +4. Get the active module + + After the WASM module instantiation, an anonymous module is instantiated and owned by the `VM` context. Developers may need to retrieve it to get the instances beyond the module. Then developers can use the `WasmEdge_VMGetActiveModule()` API to get that anonymous module instance. Please refer to the [Module instance](#instances) for the details about the module instance APIs. + + ```c + /* + * ... + * Assume that a WASM module is instantiated in `VMCxt`. + */ + const WasmEdge_ModuleInstanceContext *ModCxt = + WasmEdge_VMGetActiveModule(VMCxt); + /* + * If there's no WASM module instantiated, this API will return `NULL`. + * The returned module instance context should __NOT__ be destroyed. + */ + ``` + +5. List and get the registered modules + + To list and retrieve the registered modules in the `VM` context, besides accessing the `store` context of the `VM`, developers can use the following APIs. + + ```c + /* + * ... + * Assume that the `VMCxt` is created. + */ + WasmEdge_String Names[32]; + uint32_t ModuleLen = WasmEdge_VMListRegisteredModule(VMCxt, Names, 32); + for (uint32_t I = 0; I < ModuleLen; I++) { + /* Will print the registered module names in the VM context. */ + printf("%s\n", Names[I].Buf); + } + + WasmEdge_String WasiName = + WasmEdge_StringCreateByCString("wasi_snapshot_preview1"); + /* The `WasiModule` will not be `NULL` because the configuration was set. */ + const WasmEdge_ModuleInstanceContext *WasiModule = + WasmEdge_VMGetRegisteredModule(VMCxt, WasiName); + WasmEdge_StringDelete(WasiName); + ``` + +6. Get the components + + The `VM` context is composed by the `Loader`, `Validator`, and `Executor` contexts. For the developers who want to use these contexts without creating another instances, these APIs can help developers to get them from the `VM` context. The get contexts are owned by the `VM` context, and developers should not call their delete functions. + + ```c + WasmEdge_LoaderContext *LoadCxt = WasmEdge_VMGetLoaderContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_LoaderDelete()`. */ + WasmEdge_ValidatorContext *ValidCxt = WasmEdge_VMGetValidatorContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_ValidatorDelete()`. */ + WasmEdge_ExecutorContext *ExecCxt = WasmEdge_VMGetExecutorContext(VMCxt); + /* The object should __NOT__ be deleted by `WasmEdge_ExecutorDelete()`. */ + ``` + +## WasmEdge Runtime + +In this partition, we will introduce the objects of WasmEdge runtime manually. + +### WASM Execution Example Step-By-Step + +Besides the WASM execution through the [`VM` context](#wasmedge-vm), developers can execute the WASM functions or instantiate WASM modules step-by-step with the `Loader`, `Validator`, `Executor`, and `Store` contexts. + +Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```c +#include +#include +int main() { + /* + * Create the configure context. This step is not necessary because we didn't + * adjust any setting. + */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* + * Create the statistics context. This step is not necessary if the statistics + * in runtime is not needed. + */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + /* Result. */ + WasmEdge_Result Res; + + /* Create the loader context. The configure context can be NULL. */ + WasmEdge_LoaderContext *LoadCxt = WasmEdge_LoaderCreate(ConfCxt); + /* Create the validator context. The configure context can be NULL. */ + WasmEdge_ValidatorContext *ValidCxt = WasmEdge_ValidatorCreate(ConfCxt); + /* + * Create the executor context. The configure context and the statistics + * context can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + + /* + * Load the WASM file or the compiled-WASM file and convert into the AST + * module context. + */ + WasmEdge_ASTModuleContext *ASTCxt = NULL; + Res = WasmEdge_LoaderParseFromFile(LoadCxt, &ASTCxt, "fibonacci.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Validate the WASM module. */ + Res = WasmEdge_ValidatorValidate(ValidCxt, ASTCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* Instantiate the WASM module into store context. */ + WasmEdge_ModuleInstanceContext *ModCxt = NULL; + Res = WasmEdge_ExecutorInstantiate(ExecCxt, &ModCxt, StoreCxt, ASTCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("Instantiation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + + /* Try to list the exported functions of the instantiated WASM module. */ + uint32_t FuncNum = WasmEdge_ModuleInstanceListFunctionLength(ModCxt); + /* Create the name buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String FuncNames[BUF_LEN]; + /* + * If the list length is larger than the buffer length, the overflowed data + * will be discarded. + */ + uint32_t RealFuncNum = + WasmEdge_ModuleInstanceListFunction(ModCxt, FuncNames, BUF_LEN); + for (uint32_t I = 0; I < RealFuncNum && I < BUF_LEN; I++) { + char Buf[BUF_LEN]; + uint32_t Size = WasmEdge_StringCopy(FuncNames[I], Buf, sizeof(Buf)); + printf("Get exported function string length: %u, name: %s\n", Size, Buf); + /* The function names should __NOT__ be destroyed. */ + } + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(18)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Find the exported function by function name. */ + WasmEdge_FunctionInstanceContext *FuncCxt = + WasmEdge_ModuleInstanceFindFunction(ModCxt, FuncName); + if (FuncCxt == NULL) { + printf("Function `fib` not found.\n"); + return 1; + } + /* Invoke the WASM function. */ + Res = WasmEdge_ExecutorInvoke(ExecCxt, FuncCxt, Params, 1, Returns, 1); + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Execution phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_StringDelete(FuncName); + WasmEdge_ASTModuleDelete(ASTCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + WasmEdge_LoaderDelete(LoadCxt); + WasmEdge_ValidatorDelete(ValidCxt); + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_ConfigureDelete(ConfCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_StatisticsDelete(StatCxt); + return 0; +} +``` + +Then you can compile and run: (the 18th Fibonacci number is 4181 in 0-based index) + +```bash +$ gcc test.c -lwasmedge +$ ./a.out +Get exported function string length: 3, name: fib +Get the result: 4181 +``` + +### Loader + +The `Loader` context loads the WASM binary from files or buffers. Both the WASM and the compiled-WASM from the [WasmEdge AOT Compiler](#wasmedge-aot-compiler) are supported. + +```c +uint8_t Buf[4096]; +/* ... Read the WASM code to the buffer. */ +uint32_t FileSize = ...; +/* The `FileSize` is the length of the WASM code. */ + +/* Developers can adjust settings in the configure context. */ +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); +/* Create the loader context. The configure context can be NULL. */ +WasmEdge_LoaderContext *LoadCxt = WasmEdge_LoaderCreate(ConfCxt); + +WasmEdge_ASTModuleContext *ASTCxt = NULL; +WasmEdge_Result Res; + +/* Load WASM or compiled-WASM from the file. */ +Res = WasmEdge_LoaderParseFromFile(LoadCxt, &ASTCxt, "fibonacci.wasm"); +if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} +/* The output AST module context should be destroyed. */ +WasmEdge_ASTModuleDelete(ASTCxt); + +/* Load WASM or compiled-WASM from the buffer. */ +WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(Buf, FileSize); +Res = WasmEdge_LoaderParseFromBytes(LoadCxt, &ASTCxt, Bytes); +/* + * Note: `WasmEdge_LoaderParseFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_LoaderParseFromBytes()` instead. + */ +if (!WasmEdge_ResultOK(Res)) { + printf("Loading phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} +/* The output AST module context should be destroyed. */ +WasmEdge_ASTModuleDelete(ASTCxt); + +WasmEdge_LoaderDelete(LoadCxt); +WasmEdge_ConfigureDelete(ConfCxt); +``` + +### Validator + +The `Validator` context can validate the WASM module. Every WASM module should be validated before instantiation. + +```c +/* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context. + * Assume that the `ConfCxt` is the configure context. + */ +/* Create the validator context. The configure context can be NULL. */ +WasmEdge_ValidatorContext *ValidCxt = WasmEdge_ValidatorCreate(ConfCxt); +WasmEdge_Result Res = WasmEdge_ValidatorValidate(ValidCxt, ASTCxt); +if (!WasmEdge_ResultOK(Res)) { + printf("Validation phase failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} +WasmEdge_ValidatorDelete(ValidCxt); +``` + +### Executor + +The `Executor` context is the executor for both WASM and compiled-WASM. This object should work base on the `Store` context. For the details of the `Store` context, please refer to the [next chapter](#store). + +1. Instantiate and register an `AST module` as a named `Module` instance + + As the same of [registering host modules](#host-module-registrations) or [importing WASM modules](#wasm-registrations-and-executions) in `VM` contexts, developers can instantiate an `AST module` contexts into a named `Module` instance, and register it into the `Store` context. After the registration, the result `Module` instance is exported to the `Store` with the given module name and can be linked when instantiating another module. + + For the details about the `Module` instances APIs, please refer to the [Instances](#instances). The `Store` context is only the linker for searching and linking the exported modules when instantiation. Developers should delete the output `Module` instance when it will no longer be used. When the `Module` instance being deleted, it will automatically unlink to all linked `Store` contexts. + + ```c + /* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context and has passed the validation. Assume that the `ConfCxt` is the + * configure context. + */ + /* Create the statistics context. This step is not necessary. */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the executor context. The configure and the statistics contexts + * can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = + WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + /* Result. */ + WasmEdge_Result Res; + + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + /* The output module instance. */ + WasmEdge_ModuleInstanceContext *ModCxt = NULL; + /* + * Register the WASM module into the store with the export module name + * "mod". + */ + Res = + WasmEdge_ExecutorRegister(ExecCxt, &ModCxt, StoreCxt, ASTCxt, ModName); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return -1; + } + WasmEdge_StringDelete(ModName); + + /* ... */ + + /* After the execution, the resources should be released. */ + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_StatisticsDelete(StatCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + ``` + +2. Register an existing `Module` instance and export the module name + + Besides instantiating and registering an `AST module` contexts, developers can register an existing `Module` instance into the store with exporting the module name (which is in the `Module` instance already). This case occurs when developers create a `Module` instance for the host functions and want to register it for linking. For the details about the construction of host functions in `Module` instances, please refer to the [Host Functions](#host-functions). + + ```c + /* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context and has passed the validation. Assume that the `ConfCxt` is the + * configure context. + */ + /* Create the statistics context. This step is not necessary. */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the executor context. The configure and the statistics contexts + * can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = + WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + /* Result. */ + WasmEdge_Result Res; + + /* Create a module instance for host functions. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("host-module"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ModName); + WasmEdge_StringDelete(ModName); + /* + * ... + * Create and add the host functions, tables, memories, and globals into the + * module instance. + */ + + /* Register the module instance into store with the exported module name. */ + /* The export module name is in the module instance already. */ + Res = WasmEdge_ExecutorRegisterImport(ExecCxt, StoreCxt, HostModCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return -1; + } + + /* ... */ + + /* After the execution, the resources should be released. */ + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_StatisticsDelete(StatCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + ``` + +3. Instantiate an `AST module` to an anonymous `Module` instance + + WASM or compiled-WASM modules should be instantiated before the function invocation. Before instantiating a WASM module, please check the [import section](https://webassembly.github.io/spec/core/syntax/modules.html#syntax-import) for ensuring the imports are registered into the `Store` context for linking. + + ```c + /* + * ... + * Assume that the `ASTCxt` is the output AST module context from the loader + * context and has passed the validation. Assume that the `ConfCxt` is the + * configure context. + */ + /* Create the statistics context. This step is not necessary. */ + WasmEdge_StatisticsContext *StatCxt = WasmEdge_StatisticsCreate(); + /* + * Create the executor context. The configure and the statistics contexts + * can be NULL. + */ + WasmEdge_ExecutorContext *ExecCxt = + WasmEdge_ExecutorCreate(ConfCxt, StatCxt); + /* + * Create the store context. The store context is the object to link the + * modules for imports and exports. + */ + WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + + /* The output module instance. */ + WasmEdge_ModuleInstanceContext *ModCxt = NULL; + /* Instantiate the WASM module. */ + WasmEdge_Result Res = + WasmEdge_ExecutorInstantiate(ExecCxt, &ModCxt, StoreCxt, ASTCxt); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM instantiation failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return -1; + } + + /* ... */ + + /* After the execution, the resources should be released. */ + WasmEdge_ExecutorDelete(ExecCxt); + WasmEdge_StatisticsDelete(StatCxt); + WasmEdge_StoreDelete(StoreCxt); + WasmEdge_ModuleInstanceDelete(ModCxt); + ``` + +4. Invoke functions + + After registering or instantiating and get the result `Module` instance, developers can retrieve the exported `Function` instances from the `Module` instance for invocation. For the details about the `Module` instances APIs, please refer to the [Instances](#instances). Please refer to the [example above](#wasm-execution-example-step-by-step) for the `Function` instance invocation with the `WasmEdge_ExecutorInvoke()` API. + +5. Asynchronously invoke functions + + Such as [executing WASM functions in VM asynchronously](#asynchronous-execution), developers can also invoke a function asynchronously by `Executor` contexts API. + + After getting the `Function` instance, developers will get the `Async` context by calling the `WasmEdge_ExecutorAsyncInvoke()` API. Please refer to the [Async](#async) chapter to work with this context for getting the results. + +### AST Module + +The `AST Module` context presents the loaded structure from a WASM file or buffer. Developer will get this object after loading a WASM file or buffer from [Loader](#loader). Before instantiation, developers can also query the imports and exports of an `AST Module` context. + +```c +WasmEdge_ASTModuleContext *ASTCxt = ...; +/* Assume that a WASM is loaded into an AST module context. */ + +/* Create the import type context buffers. */ +const uint32_t BUF_LEN = 256; +const WasmEdge_ImportTypeContext *ImpTypes[BUF_LEN]; +uint32_t ImportNum = WasmEdge_ASTModuleListImportsLength(ASTCxt); +/* + * If the list length is larger than the buffer length, the overflowed data will + * be discarded. + */ +uint32_t RealImportNum = + WasmEdge_ASTModuleListImports(ASTCxt, ImpTypes, BUF_LEN); +for (uint32_t I = 0; I < RealImportNum && I < BUF_LEN; I++) { + /* Working with the import type `ImpTypes[I]` ... */ +} + +/* Create the export type context buffers. */ +const WasmEdge_ExportTypeContext *ExpTypes[BUF_LEN]; +uint32_t ExportNum = WasmEdge_ASTModuleListExportsLength(ASTCxt); +/* + * If the list length is larger than the buffer length, the overflowed data will + * be discarded. + */ +uint32_t RealExportNum = + WasmEdge_ASTModuleListExports(ASTCxt, ExpTypes, BUF_LEN); +for (uint32_t I = 0; I < RealExportNum && I < BUF_LEN; I++) { + /* Working with the export type `ExpTypes[I]` ... */ +} + +WasmEdge_ASTModuleDelete(ASTCxt); +/* + * After deletion of `ASTCxt`, all data queried from the `ASTCxt` should not be + * accessed. + */ +``` + +### Serializer + +As the reversion of loading WASM file or buffer into a `AST Module`, the `Loader` context also provide the serializer to serialze the `AST Module` back into a WASM buffer. + +```c +WasmEdge_ASTModuleContext *ASTCxt = ...; +/* Assume that a WASM is loaded into an AST module context. */ + +WasmEdge_LoaderContext *LoadCxt = ...; +/* Assume that a loader context is created with configuration. */ + +WasmEdbe_Bytes Bytes; +/* Serialize the AST module back into WASM binary format. */ +Res = WasmEdge_LoaderSerializeASTModule(LoadCxt, ASTCxt, &Bytes); +if (!WasmEdge_ResultOK(Res)) { + printf("Serialization failed: %s\n", WasmEdge_ResultGetMessage(Res)); +} + +/* The output WasmEdge_Bytes should be destroyed. */ +WasmEdge_BytesDelete(Bytes); +``` + +### Store + +[Store](https://webassembly.github.io/spec/core/exec/runtime.html#store) is the runtime structure for the representation of all global state that can be manipulated by WebAssembly programs. The `Store` context in WasmEdge is an object which present the linker to provide the instance exporting and importing when instantiating WASM modules. Developers can retrieve the named modules from the `Store` context, and should delete the `Module` instances registered into the `Store` context if they will not be used anymore. + +When the `Store` context being deleted, the linked `Module` instances will automatically unlink to this `Store` context. When a `Module` instance being deleted, it will automatically unlink to all the linked `Store` contexts. + +```c +WasmEdge_StoreContext *StoreCxt = WasmEdge_StoreCreate(); + +/* + * ... + * Register a WASM module via the executor context. + */ + +/* Try to list the registered WASM modules. */ +uint32_t ModNum = WasmEdge_StoreListModuleLength(StoreCxt); +/* Create the name buffers. */ +const uint32_t BUF_LEN = 256; +WasmEdge_String ModNames[BUF_LEN]; +/* + * If the list length is larger than the buffer length, the overflowed data will + * be discarded. + */ +uint32_t RealModNum = WasmEdge_StoreListModule(StoreCxt, ModNames, BUF_LEN); +for (uint32_t I = 0; I < RealModNum && I < BUF_LEN; I++) { + /* Working with the module name `ModNames[I]` ... */ + /* The module names should __NOT__ be destroyed. */ +} + +/* Find named module by name. */ +WasmEdge_String ModName = WasmEdge_StringCreateByCString("module"); +const WasmEdge_ModuleInstanceContext *ModCxt = + WasmEdge_StoreFindModule(StoreCxt, ModName); +/* If the module with name not found, the `ModCxt` will be NULL. */ +WasmEdge_StringDelete(ModName); +``` + +### Instances + +The instances are the runtime structures of WASM. Developers can retrieve the `Module` instances from the `Store` contexts, and retrieve the other instances from the `Module` instances. A single instance can be allocated by its creation function. Developers can construct instances into an `Module` instance for registration. Please refer to the [Host Functions](#host-functions) for details. The instances created by their creation functions should be destroyed by developers, EXCEPT they are added into an `Module` instance. + +1. Module instance + + After instantiating or registering an `AST module` context, developers will get a `Module` instance as the result, and have the responsibility to destroy it when not in use. A `Module` instance can also be created for the host module. Please refer to the [host function](#host-functions) for the details. `Module` instance provides APIs to list and find the exported instances in the module. + + ```c + /* + * ... + * Instantiate a WASM module via the executor context and get the `ModCxt` + * as the output module instance. + */ + + /* Try to list the exported instance of the instantiated WASM module. */ + /* Take the function instances for example here. */ + uint32_t FuncNum = WasmEdge_ModuleInstanceListFunctionLength(ModCxt); + /* Create the name buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String FuncNames[BUF_LEN]; + /* + * If the list length is larger than the buffer length, the overflowed data + * will be discarded. + */ + uint32_t RealFuncNum = + WasmEdge_ModuleInstanceListFunction(ModCxt, FuncNames, BUF_LEN); + for (uint32_t I = 0; I < RealFuncNum && I < BUF_LEN; I++) { + /* Working with the function name `FuncNames[I]` ... */ + /* The function names should __NOT__ be destroyed. */ + } + + /* Try to find the exported instance of the instantiated WASM module. */ + /* Take the function instances for example here. */ + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + WasmEdge_FunctionInstanceContext *FuncCxt = + WasmEdge_ModuleInstanceFindFunction(ModCxt, FuncName); + /* `FuncCxt` will be `NULL` if the function not found. */ + /* + * The returned instance is owned by the module instance context and should + * __NOT__ be destroyed. + */ + WasmEdge_StringDelete(FuncName); + ``` + +2. Function instance + + [Host functions](https://webassembly.github.io/spec/core/exec/runtime.html#syntax-hostfunc) are functions outside WebAssembly and passed to WASM modules as imports. In WasmEdge, developers can create the `Function` contexts for host functions and add them into an `Module` instance context for registering into a `VM` or a `Store`. Developers can retrieve the `Function Type` from the `Function` contexts through the API. For the details of the `Host Function` guide, please refer to the [next chapter](#host-functions). + + ```c + /* Retrieve the function instance from the module instance context. */ + WasmEdge_FunctionInstanceContext *FuncCxt = ...; + WasmEdge_FunctionTypeContext *FuncTypeCxt = + WasmEdge_FunctionInstanceGetFunctionType(FuncCxt); + /* + * The `FuncTypeCxt` is owned by the `FuncCxt` and should __NOT__ be + * destroyed. + */ + + /* + * For the function instance creation, please refer to the `Host Function` + * guide. + */ + ``` + +3. Table instance + + In WasmEdge, developers can create the `Table` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. The `Table` contexts supply APIs to control the data in table instances. + + ```c + WasmEdge_Limit TabLimit = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + /* Create the table type with limit and the `FuncRef` element type. */ + WasmEdge_TableTypeContext *TabTypeCxt = + WasmEdge_TableTypeCreate(WasmEdge_ValTypeGenFuncRef(), TabLimit); + /* Create the table instance with table type. */ + /* + * Developers can also use the `WasmEdge_TableInstanceCreateWithInit()` API to + * create the table instance with default reference values. + */ + WasmEdge_TableInstanceContext *HostTable = + WasmEdge_TableInstanceCreate(TabTypeCxt); + /* Delete the table type. */ + WasmEdge_TableTypeDelete(TabTypeCxt); + WasmEdge_Result Res; + WasmEdge_Value Data; + + const WasmEdge_TableTypeContext *GotTabTypeCxt = + WasmEdge_TableInstanceGetTableType(HostTable); + /* + * The `GotTabTypeCxt` got from table instance is owned by the `HostTable` and + * should __NOT__ be destroyed. + */ + WasmEdge_ValType RefType = WasmEdge_TableTypeGetRefType(GotGlobTypeCxt); + bool IsTypeFuncRef = WasmEdge_ValTypeIsFuncRef(RefType); + /* `IsTypeFuncRef` will be `TRUE`. */ + Data = WasmEdge_ValueGenFuncRef(5); + Res = WasmEdge_TableInstanceSetData(HostTable, Data, 3); + /* Set the function index 5 to the table[3]. */ + /* + * This will get an "out of bounds table access" error + * because the position (13) is out of the table size (10): + * Res = WasmEdge_TableInstanceSetData(HostTable, Data, 13); + */ + Res = WasmEdge_TableInstanceGetData(HostTable, &Data, 3); + /* Get the FuncRef value of the table[3]. */ + /* + * This will get an "out of bounds table access" error + * because the position (13) is out of the table size (10): + * Res = WasmEdge_TableInstanceGetData(HostTable, &Data, 13); + */ + + uint32_t Size = WasmEdge_TableInstanceGetSize(HostTable); + /* `Size` will be 10. */ + Res = WasmEdge_TableInstanceGrow(HostTable, 6); + /* Grow the table size of 6, the table size will be 16. */ + /* + * This will get an "out of bounds table access" error because + * the size (16 + 6) will reach the table limit(20): + * Res = WasmEdge_TableInstanceGrow(HostTable, 6); + */ + + WasmEdge_TableInstanceDelete(HostTable); + ``` + +4. Memory instance + + In WasmEdge, developers can create the `Memory` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. The `Memory` contexts supply APIs to control the data in memory instances. + + ```c + WasmEdge_Limit MemLimit = { + .HasMax = true, .Shared = false, .Min = 1, .Max = 5}; + /* Create the memory type with limit. The memory page size is 64KiB. */ + WasmEdge_MemoryTypeContext *MemTypeCxt = + WasmEdge_MemoryTypeCreate(MemLimit); + /* Create the memory instance with memory type. */ + WasmEdge_MemoryInstanceContext *HostMemory = + WasmEdge_MemoryInstanceCreate(MemTypeCxt); + /* Delete the memory type. */ + WasmEdge_MemoryTypeDelete(MemTypeCxt); + WasmEdge_Result Res; + uint8_t Buf[256]; + + Buf[0] = 0xAA; + Buf[1] = 0xBB; + Buf[2] = 0xCC; + Res = WasmEdge_MemoryInstanceSetData(HostMemory, Buf, 0x1000, 3); + /* Set the data[0:2] to the memory[4096:4098]. */ + /* + * This will get an "out of bounds memory access" error + * because [65535:65537] is out of 1 page size (65536): + * Res = WasmEdge_MemoryInstanceSetData(HostMemory, Buf, 0xFFFF, 3); + */ + Buf[0] = 0; + Buf[1] = 0; + Buf[2] = 0; + Res = WasmEdge_MemoryInstanceGetData(HostMemory, Buf, 0x1000, 3); + /* Get the memory[4096:4098]. Buf[0:2] will be `{0xAA, 0xBB, 0xCC}`. */ + /* + * This will get an "out of bounds memory access" error + * because [65535:65537] is out of 1 page size (65536): + * Res = WasmEdge_MemoryInstanceSetData(HostMemory, Buf, 0xFFFF, 3); + */ + + uint32_t PageSize = WasmEdge_MemoryInstanceGetPageSize(HostMemory); + /* `PageSize` will be 1. */ + Res = WasmEdge_MemoryInstanceGrowPage(HostMemory, 2); + /* Grow the page size of 2, the page size of the memory instance will be 3. */ + /* + * This will get an "out of bounds memory access" error because + * the page size (3 + 3) will reach the memory limit(5): + * Res = WasmEdge_MemoryInstanceGrowPage(HostMemory, 3); + */ + + WasmEdge_MemoryInstanceDelete(HostMemory); + ``` + +5. Tag instance + + Unlike the other instances, the `Tag` contexts are only available and can be retrieved from a `Module` instance context when turning on the `Exception Handling` proposal. Developers can retrieve the `Tag Type` from the instance. + + ```c + /* + * ... + * Instantiate a WASM module with exception handling instructions via the + * executor context and get the `ModCxt` as the output module instance. + */ + + /* Try to list the exported tag instance of the instantiated WASM module. */ + uint32_t TagNum = WasmEdge_ModuleInstanceListTagLength(ModCxt); + /* Create the name buffers. */ + const uint32_t BUF_LEN = 256; + WasmEdge_String TagNames[BUF_LEN]; + /* + * If the list length is larger than the buffer length, the overflowed data + * will be discarded. + */ + uint32_t RealTagNum = WasmEdge_ModuleInstanceListTag(ModCxt, TagNames, BUF_LEN); + for (uint32_t I = 0; I < RealTagNum && I < BUF_LEN; I++) { + /* Working with the tag name `TagNames[I]` ... */ + /* The function names should __NOT__ be destroyed. */ + } + + /* Try to find the exported tag instance of the instantiated WASM module. */ + WasmEdge_String TagName = WasmEdge_StringCreateByCString("tag-1"); + WasmEdge_TagInstanceContext *TagCxt = + WasmEdge_ModuleInstanceFindTag(ModCxt, TagName); + /* `TagCxt` will be `NULL` if the tag not found. */ + /* + * The returned instance is owned by the module instance context and should + * __NOT__ be destroyed. + */ + + /* Try to retrieve the tag type from the tag instance. */ + const WasmEdge_TagTypeContext *TagTypeCxt = + WasmEdge_TagInstanceGetTagType(TagCxt); + /* + * The returned tag type context is owned by the tag instance context and should + * __NOT__ be destroyed. + */ + + WasmEdge_StringDelete(TagName); + ``` + +6. Global instance + + In WasmEdge, developers can create the `Global` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. The `Global` contexts supply APIs to control the value in global instances. + + ```c + WasmEdge_Value Val = WasmEdge_ValueGenI64(1000); + /* Create the global type with value type and mutation. */ + WasmEdge_GlobalTypeContext *GlobTypeCxt = WasmEdge_GlobalTypeCreate( + WasmEdge_ValTypeGenI64(), WasmEdge_Mutability_Var); + /* Create the global instance with value and global type. */ + WasmEdge_GlobalInstanceContext *HostGlobal = + WasmEdge_GlobalInstanceCreate(GlobTypeCxt, Val); + /* Delete the global type. */ + WasmEdge_GlobalTypeDelete(GlobTypeCxt); + WasmEdge_Result Res; + + const WasmEdge_GlobalTypeContext *GotGlobTypeCxt = + WasmEdge_GlobalInstanceGetGlobalType(HostGlobal); + /* + * The `GotGlobTypeCxt` got from global instance is owned by the `HostGlobal` + * and should __NOT__ be destroyed. + */ + WasmEdge_ValType ValType = WasmEdge_GlobalTypeGetValType(GotGlobTypeCxt); + bool IsTypeF64 = WasmEdge_ValTypeIsI64(ValType); + /* `ValType` will be `TRUE`. */ + enum WasmEdge_Mutability ValMut = + WasmEdge_GlobalTypeGetMutability(GotGlobTypeCxt); + /* `ValMut` will be `WasmEdge_Mutability_Var`. */ + + Res = WasmEdge_GlobalInstanceSetValue(HostGlobal, WasmEdge_ValueGenI64(888)); + /* + * Set the value u64(888) to the global. + * This function will return error if the value type mismatched or + * the global mutability is `WasmEdge_Mutability_Const`. + */ + WasmEdge_Value GlobVal = WasmEdge_GlobalInstanceGetValue(HostGlobal); + /* Get the value (888 now) of the global context. */ + + WasmEdge_GlobalInstanceDelete(HostGlobal); + ``` + +### Host Functions + +[Host functions](https://webassembly.github.io/spec/core/exec/runtime.html#syntax-hostfunc) are functions outside WebAssembly and passed to WASM modules as imports. In WasmEdge, developers can create the `Function`, `Memory`, `Table`, and `Global` contexts and add them into an `Module` instance context for registering into a `VM` or a `Store`. + +1. Host function allocation + + Developers can define C functions with the following function signature as the host function body: + + ```c + typedef WasmEdge_Result (*WasmEdge_HostFunc_t)( + void *Data, const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *Params, WasmEdge_Value *Returns); + ``` + + The example of an `add` host function to add 2 `i32` values: + + ```c + WasmEdge_Result Add(void *, const WasmEdge_CallingFrameContext *, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + /* + * Params: {i32, i32} + * Returns: {i32} + * Developers should take care about the function type. + */ + /* Retrieve the value 1. */ + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + /* Retrieve the value 2. */ + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + /* Output value 1 is Val1 + Val2. */ + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + /* Return the status of success. */ + return WasmEdge_Result_Success; + } + ``` + + Then developers can create `Function` context with the host function body and the function type: + + ```c + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + /* Create a function type: {i32, i32} -> {i32}. */ + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + /* + * Create a function context with the function type and host function body. + * The `Cost` parameter can be 0 if developers do not need the cost + * measuring. + */ + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, NULL, 0); + /* + * The third parameter is the pointer to the additional data. + * Developers should guarantee the life cycle of the data, and it can be + * `NULL` if the external data is not needed. + */ + WasmEdge_FunctionTypeDelete(HostType); + + /* + * If the function instance is __NOT__ added into a module instance context, + * it should be deleted. + */ + WasmEdge_FunctionInstanceDelete(HostFunc); + ``` + +2. Calling frame context + + The `WasmEdge_CallingFrameContext` is the context to provide developers to access the module instance of the [frame on the top of the calling stack](https://webassembly.github.io/spec/core/exec/runtime.html#activations-and-frames). According to the [WASM spec](https://webassembly.github.io/spec/core/exec/instructions.html#function-calls), a frame with the module instance is pushed into the stack when invoking a function. Therefore, the host functions can access the module instance of the top frame to retrieve the memory instances to read/write data. + + ```c + WasmEdge_Result LoadOffset(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + /* Function type: {i32} -> {} */ + uint32_t Offset = (uint32_t)WasmEdge_ValueGetI32(In[0]); + uint32_t Num = 0; + + /* + * Get the 0-th memory instance of the module instance of the top frame on + * stack. + */ + WasmEdge_MemoryInstanceContext *MemCxt = + WasmEdge_CallingFrameGetMemoryInstance(CallFrameCxt, 0); + + WasmEdge_Result Res = + WasmEdge_MemoryInstanceGetData(MemCxt, (uint8_t *)(&Num), Offset, 4); + if (WasmEdge_ResultOK(Res)) { + printf("u32 at memory[%lu]: %lu\n", Offset, Num); + } else { + return Res; + } + return WasmEdge_Result_Success; + } + ``` + + Besides using the `WasmEdge_CallingFrameGetMemoryInstance()` API to get the memory instance by index in the module instance, developers can use the `WasmEdge_CallingFrameGetModuleInstance()` to get the module instance directly. Therefore, developers can retrieve the exported contexts by the `WasmEdge_ModuleInstanceContext` APIs. And also, developers can use the `WasmEdge_CallingFrameGetExecutor()` API to get the currently used executor context. + +3. User-defined error code of the host functions + + In host functions, WasmEdge provides `WasmEdge_Result_Success` to return success, `WasmEdge_Result_Terminate` to terminate the WASM execution, and `WasmEdge_Result_Fail` to return fail. WasmEdge also provides the usage of returning the user-specified codes. Developers can use the `WasmEdge_ResultGen()` API to generate the `WasmEdge_Result` with error code, and use the `WasmEdge_ResultGetCode()` API to get the error code. + + > Notice: The error code only supports 24-bit integer (0 ~ 16777216 in `uint32_t`). The values larger than 24-bit will be truncated. + + Assume that a simple WASM from the WAT is as following: + + ```wasm + (module + (type $t0 (func (param i32))) + (import "extern" "trap" (func $f-trap (type $t0))) + (func (export "trap") (param i32) + local.get 0 + call $f-trap) + ) + ``` + + And the `test.c` is as following: + + ```c + #include + #include + + /* Host function body definition. */ + WasmEdge_Result Trap(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val = WasmEdge_ValueGetI32(In[0]); + /* Return the error code from the param[0]. */ + return WasmEdge_ResultGen(WasmEdge_ErrCategory_UserLevelError, Val); + } + + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The WASM module buffer. */ + uint8_t WASM[] = {/* WASM header */ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + /* Type section */ + 0x01, 0x05, 0x01, + /* function type {i32} -> {} */ + 0x60, 0x01, 0x7F, 0x00, + /* Import section */ + 0x02, 0x0F, 0x01, + /* module name: "extern" */ + 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, + /* extern name: "trap" */ + 0x04, 0x74, 0x72, 0x61, 0x70, + /* import desc: func 0 */ + 0x00, 0x00, + /* Function section */ + 0x03, 0x02, 0x01, 0x00, + /* Export section */ + 0x07, 0x08, 0x01, + /* export name: "trap" */ + 0x04, 0x74, 0x72, 0x61, 0x70, + /* export desc: func 0 */ + 0x00, 0x01, + /* Code section */ + 0x0A, 0x08, 0x01, + /* code body */ + 0x06, 0x00, 0x20, 0x00, 0x10, 0x00, 0x0B}; + + /* Create the module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + WasmEdge_ValType ParamList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 1, NULL, 0); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Trap, NULL, 0); + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String HostFuncName = WasmEdge_StringCreateByCString("trap"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, HostFuncName, HostFunc); + WasmEdge_StringDelete(HostFuncName); + + WasmEdge_VMRegisterModuleFromImport(VMCxt, HostModCxt); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(5566)}; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("trap"); + /* Run the WASM function from memory. */ + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(WASM, sizeof(WASM)); + /* + * Note: `WasmEdge_VMRunWasmFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_VMRunWasmFromBytes()` instead. + */ + WasmEdge_Result Res = + WasmEdge_VMRunWasmFromBytes(VMCxt, Bytes, FuncName, Params, 1, NULL, 0); + + /* Get the result code and print. */ + printf("Get the error code: %u\n", WasmEdge_ResultGetCode(Res)); + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_ModuleInstanceDelete(HostModCxt); + return 0; + } + ``` + + Then you can compile and run: (giving the expected error code `5566`) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + [2022-08-26 15:06:40.384] [error] user defined failed: user defined error code, Code: 0x15be + [2022-08-26 15:06:40.384] [error] When executing function name: "trap" + Get the error code: 5566 + ``` + +4. Construct a module instance with host instances + + Besides creating a `Module` instance by registering or instantiating a WASM module, developers can create a `Module` instance with a module name and add the `Function`, `Memory`, `Table`, and `Global` instances into it with their exporting names. + + ```c + /* Host function body definition. */ + WasmEdge_Result Add(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + return WasmEdge_Result_Success; + } + + /* Create a module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("module"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + /* + * Developers can also use the WasmEdge_ModuleInstanceCreateWithData() to + * create the module instance with the data and its finalizer. It will be + * introduced later. + */ + WasmEdge_StringDelete(ExportName); + + /* Create and add a function instance into the module instance. */ + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, NULL, 0); + /* + * The third parameter is the pointer to the additional data object. + * Developers should guarantee the life cycle of the data, and it can be + * `NULL` if the external data is not needed. + */ + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("add"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, FuncName, HostFunc); + WasmEdge_StringDelete(FuncName); + + /* Create and add a table instance into the import object. */ + WasmEdge_Limit TableLimit = { + .HasMax = true, .Shared = false, .Min = 10, .Max = 20}; + WasmEdge_TableTypeContext *HostTType = + WasmEdge_TableTypeCreate(WasmEdge_ValTypeGenFuncRef(), TableLimit); + WasmEdge_TableInstanceContext *HostTable = + WasmEdge_TableInstanceCreate(HostTType); + WasmEdge_TableTypeDelete(HostTType); + WasmEdge_String TableName = WasmEdge_StringCreateByCString("table"); + WasmEdge_ModuleInstanceAddTable(HostModCxt, TableName, HostTable); + WasmEdge_StringDelete(TableName); + + /* Create and add a memory instance into the import object. */ + WasmEdge_Limit MemoryLimit = { + .HasMax = true, .Shared = false, .Min = 1, .Max = 2}; + WasmEdge_MemoryTypeContext *HostMType = + WasmEdge_MemoryTypeCreate(MemoryLimit); + WasmEdge_MemoryInstanceContext *HostMemory = + WasmEdge_MemoryInstanceCreate(HostMType); + WasmEdge_MemoryTypeDelete(HostMType); + WasmEdge_String MemoryName = WasmEdge_StringCreateByCString("memory"); + WasmEdge_ModuleInstanceAddMemory(HostModCxt, MemoryName, HostMemory); + WasmEdge_StringDelete(MemoryName); + + /* Create and add a global instance into the module instance. */ + WasmEdge_GlobalTypeContext *HostGType = WasmEdge_GlobalTypeCreate( + WasmEdge_ValTypeGenI32(), WasmEdge_Mutability_Var); + WasmEdge_GlobalInstanceContext *HostGlobal = + WasmEdge_GlobalInstanceCreate(HostGType, WasmEdge_ValueGenI32(666)); + WasmEdge_GlobalTypeDelete(HostGType); + WasmEdge_String GlobalName = WasmEdge_StringCreateByCString("global"); + WasmEdge_ModuleInstanceAddGlobal(HostModCxt, GlobalName, HostGlobal); + WasmEdge_StringDelete(GlobalName); + + /* + * The module instance should be deleted. + * Developers should __NOT__ destroy the instances added into the module + * instance contexts. + */ + WasmEdge_ModuleInstanceDelete(HostModCxt); + ``` + +5. Specified module instance + + `WasmEdge_ModuleInstanceCreateWASI()` API can create and initialize the `WASI` module instance. + + Developers can create these module instance contexts and register them into the `Store` or `VM` contexts rather than adjust the settings in the `Configure` contexts. + + ```c + WasmEdge_ModuleInstanceContext *WasiModCxt = + WasmEdge_ModuleInstanceCreateWASI(/* ... ignored */); + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + /* Register the WASI and WasmEdge_Process into the VM context. */ + WasmEdge_VMRegisterModuleFromImport(VMCxt, WasiModCxt); + /* Get the WASI exit code. */ + uint32_t ExitCode = WasmEdge_ModuleInstanceWASIGetExitCode(WasiModCxt); + /* + * The `ExitCode` will be EXIT_SUCCESS if the execution has no error. + * Otherwise, it will return with the related exit code. + */ + WasmEdge_VMDelete(VMCxt); + /* The module instances should be deleted. */ + WasmEdge_ModuleInstanceDelete(WasiModCxt); + ``` + +6. Example + + Assume that a simple WASM from the WAT is as following: + + ```wasm + (module + (type $t0 (func (param i32 i32) (result i32))) + (import "extern" "func-add" (func $f-add (type $t0))) + (func (export "addTwo") (param i32 i32) (result i32) + local.get 0 + local.get 1 + call $f-add) + ) + ``` + + And the `test.c` is as following: + + ```c + #include + #include + + /* Host function body definition. */ + WasmEdge_Result Add(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + printf("Host function \"Add\": %d + %d\n", Val1, Val2); + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + return WasmEdge_Result_Success; + } + + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The WASM module buffer. */ + uint8_t WASM[] = {/* WASM header */ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + /* Type section */ + 0x01, 0x07, 0x01, + /* function type {i32, i32} -> {i32} */ + 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, + /* Import section */ + 0x02, 0x13, 0x01, + /* module name: "extern" */ + 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, + /* extern name: "func-add" */ + 0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64, + /* import desc: func 0 */ + 0x00, 0x00, + /* Function section */ + 0x03, 0x02, 0x01, 0x00, + /* Export section */ + 0x07, 0x0A, 0x01, + /* export name: "addTwo" */ + 0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F, + /* export desc: func 0 */ + 0x00, 0x01, + /* Code section */ + 0x0A, 0x0A, 0x01, + /* code body */ + 0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B}; + + /* Create the module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, NULL, 0); + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String HostFuncName = WasmEdge_StringCreateByCString("func-add"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, HostFuncName, HostFunc); + WasmEdge_StringDelete(HostFuncName); + + WasmEdge_VMRegisterModuleFromImport(VMCxt, HostModCxt); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[2] = {WasmEdge_ValueGenI32(1234), + WasmEdge_ValueGenI32(5678)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("addTwo"); + /* Run the WASM function from memory. */ + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(WASM, sizeof(WASM)); + /* + * Note: `WasmEdge_VMRunWasmFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_VMRunWasmFromBytes()` instead. + */ + WasmEdge_Result Res = WasmEdge_VMRunWasmFromBytes(VMCxt, Bytes, FuncName, + Params, 2, Returns, 1); + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_ModuleInstanceDelete(HostModCxt); + return 0; + } + ``` + + Then you can compile and run: (the result of 1234 + 5678 is 6912) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Host function "Add": 1234 + 5678 + Get the result: 6912 + ``` + +7. Host Data Example + + Developers can set a external data object to the `Function` context, and access to the object in the function body. Assume that a simple WASM from the WAT is as following: + + ```wasm + (module + (type $t0 (func (param i32 i32) (result i32))) + (import "extern" "func-add" (func $f-add (type $t0))) + (func (export "addTwo") (param i32 i32) (result i32) + local.get 0 + local.get 1 + call $f-add) + ) + ``` + + And the `test.c` is as following: + + ```c + #include + #include + + /* Host function body definition. */ + WasmEdge_Result Add(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + int32_t Val1 = WasmEdge_ValueGetI32(In[0]); + int32_t Val2 = WasmEdge_ValueGetI32(In[1]); + printf("Host function \"Add\": %d + %d\n", Val1, Val2); + Out[0] = WasmEdge_ValueGenI32(Val1 + Val2); + /* Also set the result to the data. */ + int32_t *DataPtr = (int32_t *)Data; + *DataPtr = Val1 + Val2; + return WasmEdge_Result_Success; + } + + int main() { + /* Create the VM context. */ + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The WASM module buffer. */ + uint8_t WASM[] = {/* WASM header */ + 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + /* Type section */ + 0x01, 0x07, 0x01, + /* function type {i32, i32} -> {i32} */ + 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, + /* Import section */ + 0x02, 0x13, 0x01, + /* module name: "extern" */ + 0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E, + /* extern name: "func-add" */ + 0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64, + /* import desc: func 0 */ + 0x00, 0x00, + /* Function section */ + 0x03, 0x02, 0x01, 0x00, + /* Export section */ + 0x07, 0x0A, 0x01, + /* export name: "addTwo" */ + 0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F, + /* export desc: func 0 */ + 0x00, 0x01, + /* Code section */ + 0x0A, 0x0A, 0x01, + /* code body */ + 0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B}; + + /* The external data object: an integer. */ + int32_t Data; + + /* Create the module instance. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("extern"); + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreate(ExportName); + WasmEdge_ValType ParamList[2] = {WasmEdge_ValTypeGenI32(), + WasmEdge_ValTypeGenI32()}; + WasmEdge_ValType ReturnList[1] = {WasmEdge_ValTypeGenI32()}; + WasmEdge_FunctionTypeContext *HostFType = + WasmEdge_FunctionTypeCreate(ParamList, 2, ReturnList, 1); + WasmEdge_FunctionInstanceContext *HostFunc = + WasmEdge_FunctionInstanceCreate(HostFType, Add, &Data, 0); + WasmEdge_FunctionTypeDelete(HostFType); + WasmEdge_String HostFuncName = WasmEdge_StringCreateByCString("func-add"); + WasmEdge_ModuleInstanceAddFunction(HostModCxt, HostFuncName, HostFunc); + WasmEdge_StringDelete(HostFuncName); + + WasmEdge_VMRegisterModuleFromImport(VMCxt, HostModCxt); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[2] = {WasmEdge_ValueGenI32(1234), + WasmEdge_ValueGenI32(5678)}; + WasmEdge_Value Returns[1]; + /* Function name. */ + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("addTwo"); + /* Run the WASM function from memory. */ + WasmEdge_Bytes Bytes = WasmEdge_BytesWrap(WASM, sizeof(WASM)); + /* + * Note: `WasmEdge_VMRunWasmFromBuffer()` will be deprecated in the future. + * We recommand developers to use `WasmEdge_VMRunWasmFromBytes()` instead. + */ + WasmEdge_Result Res = WasmEdge_VMRunWasmFromBytes(VMCxt, Bytes, FuncName, + Params, 2, Returns, 1); + + if (WasmEdge_ResultOK(Res)) { + printf("Get the result: %d\n", WasmEdge_ValueGetI32(Returns[0])); + } else { + printf("Error message: %s\n", WasmEdge_ResultGetMessage(Res)); + } + printf("Data value: %d\n", Data); + + /* Resources deallocations. */ + WasmEdge_VMDelete(VMCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_ModuleInstanceDelete(HostModCxt); + return 0; + } + ``` + + Then you can compile and run: (the result of 1234 + 5678 is 6912) + + ```bash + $ gcc test.c -lwasmedge + $ ./a.out + Host function "Add": 1234 + 5678 + Get the result: 6912 + Data value: 6912 + ``` + +8. Host Data in Module Instance with Finalizer + + Besides setting host data into a host function, developers can set and move ownership of host data into a `Module` instance context with its finalizer. This may be useful when implementing the plug-ins. + + ```c + /* Struct definition. */ + typedef struct Point { + int X; + int Y; + } Point; + + /* Host function body definition. */ + WasmEdge_Result Print(void *Data, + const WasmEdge_CallingFrameContext *CallFrameCxt, + const WasmEdge_Value *In, WasmEdge_Value *Out) { + Point *P = (Point *)In; + printf("Point: (%d, %d)\n", P->X, P->Y); + return WasmEdge_Result_Success; + } + + /* Finalizer definition. */ + void PointFinalizer(void *Data) { + if (Data) { + free((Point *)Data); + } + } + + /* Create a module instance with host data and its finalizer. */ + WasmEdge_String ExportName = WasmEdge_StringCreateByCString("module"); + Point *Data = (Point *)malloc(sizeof(Point)); + Data->X = 5; + Data->Y = -5; + WasmEdge_ModuleInstanceContext *HostModCxt = + WasmEdge_ModuleInstanceCreateWithData(ExportName, Data, PointFinalizer); + /* + * When the `HostModCxt` being destroyed, the finalizer will be invoked and the + * `Data` will be its argument. + */ + WasmEdge_StringDelete(ExportName); + ``` + +### Plug-ins + +The WasmEdge plug-ins are the shared libraries to provide the WasmEdge runtime to load and create host module instances. With the plug-ins, the WasmEdge runtime can be extended more easily. + +#### Load plug-ins from paths + +To use the plug-ins, developers should load the plug-ins from paths first. + +```c +WasmEdge_PluginLoadWithDefaultPaths(); +``` + +After calling this API, the plug-ins in the default paths will be loaded. The default paths are: + +1. The path given in the environment variable `WASMEDGE_PLUGIN_PATH`. +2. The `../plugin/` directory related to the WasmEdge installation path. +3. The `./wasmedge/` directory under the library path if the WasmEdge is installed under the system directory (such as `/usr` and `/usr/local`). + +To load the plug-ins from a specific path or under a specific directory, developers can use this API: + +```c +WasmEdge_PluginLoadFromPath("PATH_TO_PLUGIN/plugin.so"); +``` + +#### Get the plug-in by name + +After loading the plug-ins, developers can list the loaded plug-in names. + +```c +WasmEdge_PluginLoadWithDefaultPaths(); +printf("Number of loaded plug-ins: %d\n", WasmEdge_PluginListPluginsLength()); + +WasmEdge_String Names[20]; +uint32_t NumPlugins = WasmEdge_PluginListPlugins(Names, 20); +for (int I = 0; I < NumPlugins; I++) { + printf("plug-in %d name: %s\n", I, Names[I].Buf); +} +``` + +And developers can retrieve the plug-in context by its name. + +```c +/* Assume that wasi_crypto plug-in is installed in the default plug-in path. */ +WasmEdge_PluginLoadWithDefaultPaths(); + +const char PluginName[] = "wasi_crypto"; +WasmEdge_String NameString = + WasmEdge_StringWrap(PluginName, strlen(PluginName)); +const WasmEdge_PluginContext *PluginCxt = WasmEdge_PluginFind(NameString); +``` + +#### Create the module instance from a plug-in + +With the plug-in context, developers can create the module instances by the module name. + +```c +/* Assume that the `PluginCxt` is the context to the wasi_crypto plug-in. */ + +/* List the available host modules in the plug-in. */ +WasmEdge_String Names[20]; +uint32_t ModuleLen = WasmEdge_PluginListModule(PluginCxt, Names, 20); +for (uint32_t I = 0; I < ModuleLen; I++) { + /* Will print the available host module names in the plug-in. */ + printf("%s\n", Names[I].Buf); +} +/* + * Will print here for the WASI-Crypto plug-in here: + * wasi_ephemeral_crypto_asymmetric_common + * wasi_ephemeral_crypto_common + * wasi_ephemeral_crypto_kx + * wasi_ephemeral_crypto_signatures + * wasi_ephemeral_crypto_symmetric + */ + +/* Create a module instance from the plug-in by the module name. */ +const char ModuleName[] = "wasi_ephemeral_crypto_common"; +WasmEdge_String NameString = + WasmEdge_StringWrap(ModuleName, strlen(ModuleName)); +WasmEdge_ModuleInstance *ModCxt = + WasmEdge_PluginCreateModule(PluginCxt, NameString); + +WasmEdge_ModuleInstanceDelete(ModCxt); +``` + +## WasmEdge AOT Compiler + +In this partition, we will introduce the WasmEdge AOT compiler and the options. + +WasmEdge runs the WASM files in interpreter mode, and WasmEdge also supports the AOT (ahead-of-time) mode running without modifying any code. The WasmEdge AOT (ahead-of-time) compiler compiles the WASM files for running in AOT mode which is much faster than interpreter mode. Developers can compile the WASM files into the compiled-WASM files in shared library format for universal WASM format for the AOT mode execution. + +### Compilation Example + +Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```c +#include +#include +int main() { + /* Create the configure context. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + /* ... Adjust settings in the configure context. */ + /* Result. */ + WasmEdge_Result Res; + + /* Create the compiler context. The configure context can be NULL. */ + WasmEdge_CompilerContext *CompilerCxt = WasmEdge_CompilerCreate(ConfCxt); + /* Compile the WASM file with input and output paths. */ + Res = WasmEdge_CompilerCompile(CompilerCxt, "fibonacci.wasm", + "fibonacci-aot.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("Compilation failed: %s\n", WasmEdge_ResultGetMessage(Res)); + return 1; + } + + WasmEdge_CompilerDelete(CompilerCxt); + WasmEdge_ConfigureDelete(ConfCxt); + return 0; +} +``` + +Then you can compile and run (the output file is "fibonacci-aot.wasm"): + +```bash +$ gcc test.c -lwasmedge +$ ./a.out +[2021-07-02 11:08:08.651] [info] compile start +[2021-07-02 11:08:08.653] [info] verify start +[2021-07-02 11:08:08.653] [info] optimize start +[2021-07-02 11:08:08.670] [info] codegen start +[2021-07-02 11:08:08.706] [info] compile done +``` + +### Compiler Options + +Developers can set options for AOT compilers such as optimization level and output format: + +```c +/// AOT compiler optimization level enumeration. +enum WasmEdge_CompilerOptimizationLevel { + /// Disable as many optimizations as possible. + WasmEdge_CompilerOptimizationLevel_O0 = 0, + /// Optimize quickly without destroying debuggability. + WasmEdge_CompilerOptimizationLevel_O1, + /// Optimize for fast execution as much as possible without triggering + /// significant incremental compile time or code size growth. + WasmEdge_CompilerOptimizationLevel_O2, + /// Optimize for fast execution as much as possible. + WasmEdge_CompilerOptimizationLevel_O3, + /// Optimize for small code size as much as possible without triggering + /// significant incremental compile time or execution time slowdowns. + WasmEdge_CompilerOptimizationLevel_Os, + /// Optimize for small code size as much as possible. + WasmEdge_CompilerOptimizationLevel_Oz +}; + +/// AOT compiler output binary format enumeration. +enum WasmEdge_CompilerOutputFormat { + /// Native dynamic library format. + WasmEdge_CompilerOutputFormat_Native = 0, + /// WebAssembly with AOT compiled codes in custom sections. + WasmEdge_CompilerOutputFormat_Wasm +}; +``` + +Please refer to the [AOT compiler options configuration](#configurations) for details. + +## WasmEdge CLI Tools + +In this partition, we will introduce the C API for triggering the WasmEdge CLI tools. + +Besides executing the `wasmedge` and `wasmedgec` CLI tools, developers can trigger the WasmEdge CLI tools by WasmEdge C API. The API arguments are the same as the command line arguments of the CLI tools. + +### Runtime CLI + +The `WasmEdge_Driver_Tool()` API presents the same function as running the [`wasmedge run` command](../../../start/build-and-run/run.md). + +Noticed that this API presents the old `wasmedge` CLI tool, which is the same as the `wasmedge run` command. For the current unified `wasmedge` CLI, please refer to the [API below](#unified-cli). + +```c +#include +#include +int main(int argc, const char *argv[]) { + /* Run the WasmEdge runtime tool. */ + return WasmEdge_Driver_Tool(argc, argv); +} +``` + +### Compiler CLI + +The `WasmEdge_Driver_Compiler()` API presents the same function as running the [`wasmedge compile` tool](../../../start/build-and-run/aot.md). + +Noticed that this API presents the old `wasmedgec` CLI tool, which is the same as the `wasmedge compile` command. For the current unified `wasmedge` CLI, please refer to the [API below](#unified-cli). + +```c +#include +#include +int main(int argc, const char *argv[]) { + /* Run the WasmEdge AOT compiler. */ + return WasmEdge_Driver_Compiler(argc, argv); +} +``` + +### Unified CLI + +The `WasmEdge_Driver_UniTool()` API presents the same function as running the [`wasmedge` tool](../../../start/build-and-run/cli.md). + +```c +#include +#include +int main(int argc, const char *argv[]) { + /* Run the WasmEdge unified tool. */ + /* (Within both runtime and AOT compiler) */ + return WasmEdge_Driver_UniTool(argc, argv); +} +``` + +### CLI Helpers for Windows + +On Windows platforms, developers can use the `WasmEdge_Driver_ArgvCreate()` and `WasmEdge_Driver_ArgvDelete()` APIs to convert and handle the `UTF-8` command line arguments, or use the `WasmEdge_Driver_SetConsoleOutputCPtoUTF8()` API to set the console output code page to `UTF-8`. diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.9.x.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.9.x.md index 97672b13..4db958e2 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.9.x.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/0.9.x.md @@ -1,5 +1,5 @@ --- -sidebar_position: 11 +sidebar_position: 15 --- # C API 0.9.1 Documentation diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/latest.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/latest.md index cc7b45da..a0ec8e6b 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/latest.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/latest.md @@ -2,7 +2,7 @@ sidebar_position: 1 --- -# C API 0.14.1 Documentation +# C API 0.16.1 Documentation [WasmEdge C API](https://github.com/WasmEdge/WasmEdge/blob/master/include/api/wasmedge/wasmedge.h) denotes an interface to access the WasmEdge runtime at version `{{ wasmedge_version }}`. The following are the guides to working with the C APIs of WasmEdge. @@ -79,9 +79,54 @@ printf("WasmEdge version patch: %u\n", WasmEdge_VersionGetPatch()); ### Logging Settings -The `WasmEdge_LogSetErrorLevel()` and `WasmEdge_LogSetDebugLevel()` APIs can set the logging system to debug level or error level. By default, the error level is set, and the debug info is hidden. +1. Setting logging levels -Developers can also use the `WasmEdge_LogOff()` API to disable all logging. + The `WasmEdge_LogSetErrorLevel()` and `WasmEdge_LogSetDebugLevel()` APIs can set the logging system to debug level or error level. By default, the error level is set, and the debug info is hidden. + + Developers can set the logging level by the `WasmEdge_LogSetLevel()` API with the level enumeration: + + ```c + typedef enum WasmEdge_LogLevel { + WasmEdge_LogLevel_Trace, + WasmEdge_LogLevel_Debug, + WasmEdge_LogLevel_Info, + WasmEdge_LogLevel_Warn, + WasmEdge_LogLevel_Error, + WasmEdge_LogLevel_Critical, + } WasmEdge_LogLevel; + ``` + + Developers can also use the `WasmEdge_LogOff()` API to disable all logging. + +2. Logging callback + + For getting the detailed result or error message, WasmEdge provides the callback interface to register the customized callback function into the logging sink. + + Developers will get the message struct via the callback argument: + + ```c + typedef struct WasmEdge_LogMessage { + WasmEdge_String Message; + WasmEdge_String LoggerName; + WasmEdge_LogLevel Level; + time_t Time; + uint64_t ThreadId; + } WasmEdge_LogMessage; + ``` + + Developers can register the callback by the `WasmEdge_LogSetCallback()` API to receive the message when logging occurs. + + ```c + #include + void callback(const WasmEdge_LogMessage *Message) { + printf("Message: %s, LoggerName: %s\n", Message->Message.Buf, Message->LoggerName.Buf); + } + + int main() { + WasmEdge_LogSetCallback(callback); + return 0; + } + ``` ### Value Types @@ -627,7 +672,53 @@ After calling the [asynchronous execution APIs](#asynchronous-execution), develo The configuration context, `WasmEdge_ConfigureContext`, manages the configurations for `Loader`, `Validator`, `Executor`, `VM`, and `Compiler` contexts. Developers can adjust the settings about the proposals, VM host pre-registrations (such as `WASI`), and AOT compiler options, and then apply the `Configure` context to create the runtime contexts. -1. Proposals +1. Standard + + WasmEdge supports the WebAssembly standards from the oldest `1.0` versions. Developers can use the `WasmEdge_ConfigureSetWASMStandard()` API to assign the WASM standard in the `Configure` context. After assigning the WASM standard, the corresponding WASM proposals will be enabled or disabled, and all of the proposal settings will be overwritten. + + The following WASM standards are supported: + + ```c + enum WasmEdge_Standard { + WasmEdge_Standard_WASM_1, // WASM 1.0 + WasmEdge_Standard_WASM_2, // WASM 2.0 + WasmEdge_Standard_WASM_3, // WASM 3.0, default + } + ``` + + ```c + /* By default, the standard is WASM 3.0. */ + WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + + /* The `IsMultiRet` will be `TRUE`. */ + bool IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + + /* Remove the Multi-value returns proposal, which is in WASM 2.0. */ + WasmEdge_ConfigureRemoveProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + + /* The `IsMultiRet` will be `FALSE`. */ + IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + + /* Set the standard to WASM 2.0. All proposal settings is reset. */ + WasmEdge_ConfigureSetWASMStandard(ConfCxt, WasmEdge_Standard_WASM_2); + + /* The `IsMultiRet` will be `TRUE`. */ + IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + + /* Set the standard to WASM 1.0. All proposal settings is reset. */ + WasmEdge_ConfigureSetWASMStandard(ConfCxt, WasmEdge_Standard_WASM_1); + + /* The `IsMultiRet` will be `FALSE`. */ + IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + + WasmEdge_ConfigureDelete(ConfCxt); + ``` + +2. Proposals WasmEdge supports turning on or off the WebAssembly proposals. This configuration is effective in any contexts created with the `Configure` context. @@ -645,11 +736,11 @@ The configuration context, `WasmEdge_ConfigureContext`, manages the configuratio WasmEdge_Proposal_FunctionReferences, WasmEdge_Proposal_GC, WasmEdge_Proposal_MultiMemories, - WasmEdge_Proposal_Threads, WasmEdge_Proposal_RelaxSIMD, - WasmEdge_Proposal_Annotations, - WasmEdge_Proposal_Memory64, + WasmEdge_Proposal_Annotations, // NOT IMPLEMENTED WasmEdge_Proposal_ExceptionHandling, + WasmEdge_Proposal_Memory64, // NOT IMPLEMENTED + WasmEdge_Proposal_Threads, WasmEdge_Proposal_Component, }; ``` @@ -659,35 +750,39 @@ The configuration context, `WasmEdge_ConfigureContext`, manages the configuratio ```c /* * By default, the following proposals have turned on initially: - * * Import/Export of mutable globals - * * Non-trapping float-to-int conversions - * * Sign-extension operators - * * Multi-value returns - * * Bulk memory operations - * * Reference types - * * Fixed-width SIMD + * * WASM 1.0 Proposals: + * * Import/Export of mutable globals + * * WASM 2.0 Proposals: + * * Non-trapping float-to-int conversions + * * Sign-extension operators + * * Multi-value returns + * * Bulk memory operations + * * Reference types + * * Fixed-width SIMD + * * WASM 3.0 Proposals: + * * Tail-call + * * Extended-const + * * Typed-function references + * * GC + * * Multiple memories + * * Relaxed SIMD + * * Exception handling (interpreter only) * * For the current WasmEdge version, the following proposals are supported * (turned off by default) additionally: - * * Tail-call - * * Extended-const - * * Typed-function references - * * GC (interpreter only) - * * Multiple memories * * Threads - * * Exception handling (interpreter only) * * Component model (loader phase only) */ WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); - WasmEdge_ConfigureAddProposal(ConfCxt, WasmEdge_Proposal_MultiMemories); - WasmEdge_ConfigureRemoveProposal(ConfCxt, WasmEdge_Proposal_ReferenceTypes); + WasmEdge_ConfigureAddProposal(ConfCxt, WasmEdge_Proposal_Threads); + WasmEdge_ConfigureRemoveProposal(ConfCxt, WasmEdge_Proposal_GC); bool IsBulkMem = WasmEdge_ConfigureHasProposal( ConfCxt, WasmEdge_Proposal_BulkMemoryOperations); /* The `IsBulkMem` will be `TRUE`. */ WasmEdge_ConfigureDelete(ConfCxt); ``` -2. Host registrations +3. Host registrations This configuration is used for the `VM` context to turn on the `WASI` supports and only effective in `VM` contexts. @@ -714,7 +809,7 @@ The configuration context, `WasmEdge_ConfigureContext`, manages the configuratio WasmEdge_ConfigureDelete(ConfCxt); ``` -3. Maximum memory pages +4. Maximum memory pages Developers can limit the page size of memory instances by this configuration. When growing the page size of memory instances in WASM execution and exceeding the limited size, the page growing will fail. This configuration is only effective in the `Executor` and `VM` contexts. @@ -732,7 +827,7 @@ The configuration context, `WasmEdge_ConfigureContext`, manages the configuratio WasmEdge_ConfigureDelete(ConfCxt); ``` -4. Forcibly interpreter mode +5. Forcibly interpreter mode If developers want to execute the WASM file or the AOT compiled WASM in interpreter mode forcibly, they can turn on the configuration. @@ -746,7 +841,7 @@ The configuration context, `WasmEdge_ConfigureContext`, manages the configuratio WasmEdge_ConfigureDelete(ConfCxt); ``` -5. AOT compiler options +6. AOT compiler options The AOT compiler options configure the behavior about optimization level, output format, dump IR, and generic binary. @@ -797,7 +892,7 @@ The configuration context, `WasmEdge_ConfigureContext`, manages the configuratio WasmEdge_ConfigureDelete(ConfCxt); ``` -6. Statistics options +7. Statistics options The statistics options configure the behavior about instruction counting, cost measuring, and time measuring in both runtime and AOT compiler. These configurations are effective in `Compiler`, `VM`, and `Executor` contexts. @@ -1316,6 +1411,50 @@ In WebAssembly, the instances in WASM modules can be exported and can be importe Get the result: 10946 ``` +3. Forcibly delete the registered WASM modules + + For instantiated and registered modules in VM context, developers can use the `WasmEdge_VMForceDeleteRegisteredModule()` API to forcibly delete and unregister the module instance by name. + + + :::note + This API doesn't check the module instance dependencies for exporting and importing. Developers should guarantee the module dependencies by theirselves when using this API. The safer API will be provided in the future. + ::: + + ```c + #include + #include + int main() { + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* Names. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Register the WASM module into VM. */ + Res = WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * The function "fib" in the "fibonacci.wasm" was exported with the module + * name "mod". As the same as host functions, other modules can import the + * function `"mod" "fib"`. + */ + + /* Forcibly delete the registered module. */ + WasmEdge_VMForceDeleteRegisteredModule(VMCxt, ModName); + + WasmEdge_StringDelete(ModName); + WasmEdge_StringDelete(FuncName); + WasmEdge_VMDelete(VMCxt); + return 0; + } + ``` + ### Asynchronous Execution 1. Asynchronously run WASM functions rapidly diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.10.0.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.10.0.md index c76cb059..4ccfeefa 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.10.0.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.10.0.md @@ -1,5 +1,5 @@ --- -sidebar_position: 10 +sidebar_position: 14 --- # Upgrade to WasmEdge 0.10.0 diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.11.0.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.11.0.md index a35e6626..c5b3f14a 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.11.0.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.11.0.md @@ -1,5 +1,5 @@ --- -sidebar_position: 8 +sidebar_position: 12 --- # Upgrade to WasmEdge 0.11.0 diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.12.0.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.12.0.md index 145cb438..2dbdf372 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.12.0.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.12.0.md @@ -1,5 +1,5 @@ --- -sidebar_position: 6 +sidebar_position: 10 --- # Upgrade to WasmEdge 0.12.0 diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.13.0.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.13.0.md index 2af7211f..09622731 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.13.0.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.13.0.md @@ -1,5 +1,5 @@ --- -sidebar_position: 4 +sidebar_position: 8 --- # Upgrade to WasmEdge 0.13.0 diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.14.0.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.14.0.md index 24b71144..9fefbc83 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.14.0.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.14.0.md @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 6 --- # Upgrade to WasmEdge 0.14.0 diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.15.0.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.15.0.md new file mode 100644 index 00000000..7ed35c5e --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.15.0.md @@ -0,0 +1,118 @@ +--- +sidebar_position: 4 +--- + +# Upgrade to WasmEdge 0.15.0 + +Due to the WasmEdge C API breaking changes, this document shows the guideline for programming with WasmEdge C API to upgrade from the `0.14.1` to the `0.15.0` version. + +## Concepts + +1. Introduced new APIs for logging. + + Besides the `WasmEdge_LogSetErrorLevel()` and `WasmEdge_LogSetDebugLevel()` APIs, developers can use the `WasmEdge_LogSetLevel()` API to set the logging level. + + On the other hand, developers can use the `WasmEdge_LogSetCallback()` API to set the callback to receive the message struct when logging occurs. + +2. Introduced new API for forcibly deleting registered modules. + + Developers can use the `WasmEdge_VMForceDeleteRegisteredModule()` API to delete the registered modules in the VM context. + + This API provides the force deletion of module instance. After invoking this API, the module instance will be deleted. Developers should consider the module dependency when using this API. + +## Logging Level and Callback Configuration + +Developers can set the logging level by the `WasmEdge_LogSetLevel()` API with the level enumeration: + +```c +typedef enum WasmEdge_LogLevel { + WasmEdge_LogLevel_Trace, + WasmEdge_LogLevel_Debug, + WasmEdge_LogLevel_Info, + WasmEdge_LogLevel_Warn, + WasmEdge_LogLevel_Error, + WasmEdge_LogLevel_Critical, +} WasmEdge_LogLevel; +``` + +For getting the detailed result or error message, WasmEdge provides the callback interface to register the customized callback function into the logging sink. Developers will get the message struct via the callback argument: + +```c +typedef struct WasmEdge_LogMessage { + WasmEdge_String Message; + WasmEdge_String LoggerName; + WasmEdge_LogLevel Level; + time_t Time; + uint64_t ThreadId; +} WasmEdge_LogMessage; +``` + +Developers can register the callback by the `WasmEdge_LogSetCallback()` API to receive the message when logging occurs. + +```c +#include +void callback(const WasmEdge_LogMessage *Message) { + printf("Message: %s, LoggerName: %s\n", Message->Message.Buf, Message->LoggerName.Buf); +} + +int main() { + WasmEdge_LogSetCallback(callback); + return 0; +} +``` + +## Module Instance Deletion in VM Context + +For instantiated and registered modules in VM context, developers can use the `WasmEdge_VMForceDeleteRegisteredModule()` API to forcibly delete and unregister the module instance by name. + + +:::note +This API doesn't check the module instance dependencies for exporting and importing. Developers should guarantee the module dependencies by theirselves when using this API. The safer API will be provided in the future. +::: + +Assume that the WASM file [`fibonacci.wasm`](https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/examples/wasm/fibonacci.wat) is copied into the current directory, and the C file `test.c` is as following: + + +:::note +`fibonacci.wat` file is provided in text format. Users should convert it into corresponding WASM binary format by using [WABT tool](https://github.com/WebAssembly/wabt). +::: + +```c +#include +#include +int main() { + WasmEdge_VMContext *VMCxt = WasmEdge_VMCreate(NULL, NULL); + + /* The parameters and returns arrays. */ + WasmEdge_Value Params[1] = {WasmEdge_ValueGenI32(20)}; + WasmEdge_Value Returns[1]; + /* Names. */ + WasmEdge_String ModName = WasmEdge_StringCreateByCString("mod"); + WasmEdge_String FuncName = WasmEdge_StringCreateByCString("fib"); + /* Result. */ + WasmEdge_Result Res; + + /* Register the WASM module into VM. */ + Res = WasmEdge_VMRegisterModuleFromFile(VMCxt, ModName, "fibonacci.wasm"); + if (!WasmEdge_ResultOK(Res)) { + printf("WASM registration failed: %s\n", + WasmEdge_ResultGetMessage(Res)); + return 1; + } + /* + * The function "fib" in the "fibonacci.wasm" was exported with the module + * name "mod". As the same as host functions, other modules can import the + * function `"mod" "fib"`. + */ + + /* Forcibly delete the registered module. */ + WasmEdge_VMForceDeleteRegisteredModule(VMCxt, ModName); + + WasmEdge_StringDelete(ModName); + WasmEdge_StringDelete(FuncName); + WasmEdge_VMDelete(VMCxt); + return 0; +} +``` + +Noticed that this API will take the ownership of the module instance and delete it. If developers delete the module instance by this API which registered via the `WasmEdge_VMRegisterModuleFromImport()` API, the module instance should NOT be deleted again. diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.16.0.md b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.16.0.md new file mode 100644 index 00000000..b9ff0c34 --- /dev/null +++ b/i18n/zh/docusaurus-plugin-content-docs/current/embed/c/reference/upgrade_to_0.16.0.md @@ -0,0 +1,83 @@ +--- +sidebar_position: 2 +--- + +# Upgrade to WasmEdge 0.16.0 + +Due to the WasmEdge C API breaking changes, this document shows the guideline for programming with WasmEdge C API to upgrade from the `0.15.1` to the `0.16.0` version. + +## Concepts + +1. Introduced new APIs for quickly assigning the WASM standards. + + Developers can use the `WasmEdge_ConfigureSetWASMStandard()` to quickly configure the WASM standard in the `Configure` context. + +## Set the WASM standards and proposals + +With the `WasmEdge_ConfigureSetWASMStandard()` API, the following WASM standards can be used for quickly configuration: + +```c +enum WasmEdge_Standard { + WasmEdge_Standard_WASM_1, // WASM 1.0 + WasmEdge_Standard_WASM_2, // WASM 2.0 + WasmEdge_Standard_WASM_3, // WASM 3.0, default +} +``` + +The `WASM 1.0` contains the basic WASM spec and the following proposal: + +* Import/Export of mutable globals + +The `WASM 2.0` contains the `WASM 1.0` and the following proposals: + +* Non-trapping float-to-int conversions +* Sign-extension operators +* Multi-value returns +* Bulk memory operations +* Reference types +* Fixed-width SIMD + +The `WASM 3.0` contains the `WASM 2.0` and the following proposals: + +* Tail-call +* Extended-const +* Typed-function references +* GC +* Multiple memories +* Relaxed SIMD +* Exception handling (interpreter only) +* Memory64 (not supported in WasmEdge yet) + +After assigning the WASM standard, the corresponding WASM proposals will be enabled or disabled, and all of the proposal settings will be overwritten. + +```c +/* By default, the standard is WASM 3.0. */ +WasmEdge_ConfigureContext *ConfCxt = WasmEdge_ConfigureCreate(); + +/* The `IsMultiRet` will be `TRUE`. */ +bool IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + +/* Remove the Multi-value returns proposal, which is in WASM 2.0. */ +WasmEdge_ConfigureRemoveProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + +/* The `IsMultiRet` will be `FALSE`. */ +IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + +/* Set the standard to WASM 2.0. All proposal settings is reset. */ +WasmEdge_ConfigureSetWASMStandard(ConfCxt, WasmEdge_Standard_WASM_2); + +/* The `IsMultiRet` will be `TRUE`. */ +IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + +/* Set the standard to WASM 1.0. All proposal settings is reset. */ +WasmEdge_ConfigureSetWASMStandard(ConfCxt, WasmEdge_Standard_WASM_1); + +/* The `IsMultiRet` will be `FALSE`. */ +IsMultiRet = + WasmEdge_ConfigureHasProposal(ConfCxt, WasmEdge_Proposal_MultiValue); + +WasmEdge_ConfigureDelete(ConfCxt); +``` diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/start/build-and-run/run.md b/i18n/zh/docusaurus-plugin-content-docs/current/start/build-and-run/run.md index a68bf762..c4500374 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/start/build-and-run/run.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/start/build-and-run/run.md @@ -2,7 +2,7 @@ sidebar_position: 2 --- -# `wasmedge run` +# `wasmedge run` 安装完成后(参见[安装](../install.md#install)),用户可以执行 `wasmedge run` 命令。