ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Fluent Bit 内嵌 WAMR 的 iWASM vmcore 架构解析:函数、导出、全局变量与经典解释器

Fluent Bit 内嵌 WAMR 的 iWASM vmcore 架构解析:函数、导出、全局变量与经典解释器 Fluent Bit 内嵌 WAMR 的 iWASM vmcore 架构解析函数、导出、全局变量与经典解释器【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit本文以仓库内lib/wasm-micro-runtime-WAMR-2.4.1/core/iwasm/README.md及其四个子文档wasm_function.MD、wasm_exports.MD、wasm_globals.MD、classic_interpreter.MD为核心骨架结合 iWASM 解释器源码与 Fluent Bit 的filter_wasm插件集成代码系统讲解 WAMR 虚拟机核心vmcore在解释器模式下的内部数据结构、模块/实例两级对象模型、三条函数执行路径、导出查找机制以及它们如何支撑 Fluent Bit 的 Wasm 过滤器。读完本文你将能读懂 iWASM 的 vmcore 源码布局并理解wasm_runtime_lookup_function、wasm_runtime_call_wasm等 API 背后的数据结构链路。一、背景WAMR 与 iWASM 在 Fluent Bit 中的位置Fluent Bit 的仓库以lib/wasm-micro-runtime-WAMR-2.4.1/形式内置了WebAssembly Micro RuntimeWAMR作为 Wasm 沙箱运行时plugins/filter_wasm过滤器依赖它执行用户编写的 Wasm 字节码可参考 examples/filter_wasm_c、examples/filter_wasm_go 等示例。WAMR 的源码被组织为core/iwasm解释器/AOT 虚拟机核心、core/iwasm/aotAOT 编译与执行、core/iwasm/fast-jit、core/iwasm/interpreter解释器实现等模块。core/iwasm/README.md正是vmcore 架构的总览入口它把读者引导到四个关键子主题主题说明子文档Wasm function函数在模块级与实例级的内部数据结构、执行路径doc/wasm_function.MDExports导出表的结构、模块/实例两级的导出设置、函数导出的两种用途doc/wasm_exports.MDglobals全局变量相关内部结构doc/wasm_globals.MDclassic interpreter经典解释器的栈布局doc/classic_interpreter.MD此外 README 还指向 WAMR 的「内存模型概述」memory model overview博客作为延伸阅读用于理解线性内存、辅助栈等基础概念本文聚焦于仓库内可验证的源码事实。二、模块级与实例级理解 iWASM 对象模型的两把钥匙vmcore 文档反复强调一组对称的数据结构这是理解整个 iWASM 解释器的关键模块级Module level对应.wasm文件**加载load**阶段产生的结果描述这份字节码长什么样。核心类型是WASMModule及其直接关联的WASMImport、WASMFunction、WASMExport、WASMGlobal等定义在 interpreter/wasm.h。实例级Instance level对应模块**实例化instantiate**阶段产生的结果描述这份字节码运行起来后的状态。核心类型是WASMModuleInstance及WASMModuleInstanceExtra、WASMFunctionInstance等定义在 interpreter/wasm_runtime.h。在 Fluent Bit 侧这一加载/实例化两阶段模型被完整走了一遍src/wasm/flb_wasm.c中的flb_wasm_instantiate()先调用wasm_runtime_load()得到模块module再实例化得到module_inst与exec_env之后每次处理日志记录时通过查找函数并调用执行详见下文函数导出与调用链小节。三、Wasm Function函数的完整生命周期结构3.1 模块级数据结构WASMModule是为加载一个模块而创建的数据结构其函数相关字段包括WASMImport *import_functions由 Wasm 文件的import 段初始化描述本模块声明了哪些外部导入wasm.h L225-L227 附近。与之对应模块的**函数段code section**被解析成WASMFunction **functions数组。WASMImport是一个带kind判别字段的联合体wasm.h L667-L682typedef struct WASMImport { uint8 kind; /* 导入种类 */ union { WASMFunctionImport function; /* 函数导入 */ WASMTableImport table; WASMMemoryImport memory; WASMGlobalImport global; struct { char *module_name; /* 来源模块名module */ char *field_name; /* 导入符号名field */ } names; } u; } WASMImport;文档特别指出运行时会在模块加载阶段尝试解析solve这些导入解析来源是原生 API 注册表native API registration相关机制见 WAMR 文档 export_native_api.md。也就是说Wasm 应用 import 的env.foo这类符号可以由宿主例如 Fluent Bit以注册原生函数的方式提供。WASMFunction代表 Wasm 文件中位于 code 段的内部函数它保存函数体与执行所需的一切元信息wasm.h L684 起struct WASMFunction { WASMFuncType *func_type; /* 函数类型参数/返回值 */ uint32 local_count; uint8 *local_types; uint16 param_cell_num; /* 参数占用的 cell 数 */ uint16 ret_cell_num; /* 返回值 cell 数 */ uint16 local_cell_num; /* 局部变量 cell 数 */ uint16 *local_offsets; /* 每个局部含参数的偏移 */ uint32 max_stack_cell_num; /* 执行时所需最大操作数栈深度 */ uint32 max_block_num; uint32 code_size; uint8 *code; /* 字节码本体 */ /* 后续编译产物code_compiledfast interp、 fast_jit_jitted_code、llvm_jit_func_ptr 等 */ };max_stack_cell_num、max_block_num等字段在解释器执行前由 loader 静态计算出来用于预分配执行环境这也是 WAMR 解释器能做到不依赖递归调用栈的关键之一。3.2 实例级数据结构实例化时运行时把导入函数与内部函数合并为一个数组WASMModuleInstanceExtra::functions类型为WASMFunctionInstance *。WASMModuleInstanceExtra定义于 interpreter/wasm_runtime.h L340-L392除functions外还保存globals、start_function、malloc_function、free_function、running_mode等。WASMFunctionInstancewasm_runtime.h L214-L252是运行期函数实例struct WASMFunctionInstance { bool is_import_func; /* 是导入函数还是内部函数 */ uint16 param_count; uint16 local_count; /* 导入函数为 0 */ uint16 param_cell_num; uint16 ret_cell_num; uint16 local_cell_num; uint16 *local_offsets; uint8 *param_types; uint8 *local_types; /* 导入函数为 NULL */ union { WASMFunctionImport *func_import; /* 导入 → 描述导入信息 */ WASMFunction *func; /* 内部 → 指向模块级函数 */ } u; #if WASM_ENABLE_MULTI_MODULE ! 0 WASMModuleInstance *import_module_inst; /* 来源模块实例 */ WASMFunctionInstance *import_func_inst; /* 目标模块的函数实例 */ #endif };注意is_import_func标志位解释器执行时正是通过它区分执行内部字节码还是转去执行导入。另一个关键实例级字段是WASMModuleInstance::import_func_ptrswasm_runtime.h L440一个void **指针数组存放已解析solved的导入原生函数指针。文档特别提醒两点它初始化自模块级已解析的导入之后可能因为 C-API 调用wasm_*系列被改指向不同的原生函数——即解析结果不是一成不变的。3.3 解释器模式的三种函数执行路径vmcore 文档给出三条执行路径是理解wasm_runtime_call_wasm内部流转的最佳入口路径一执行内部字节码函数WASMModuleInstance::e - WASMModuleInstanceExtra::functions[..] /* 取函数实例 */ - WASMFunctionInstance::func /* 取模块级函数 */ - WASMFunction::code /* 取字节码 */这是最常见的情况函数定义在本模块内解释器直接逐条解释code。路径二执行来自其他模块的导入函数WASMModuleInstance::e - WASMModuleInstanceExtra::functions[..] (WASMFunctionInstance flag 指示这是一个 import) - WASMFunctionInstance::import_func_inst - WASMModuleInstance(second)::func /* 目标模块 */ - WASMFunction (second module)::code当启用多模块multi-module时一个模块可以 import 另一个模块 export 的函数此时本模块的WASMFunctionInstance通过import_func_inst指回目标模块的函数实例执行权被转发过去。路径三执行导入的原生函数WASMModuleInstance::e - WASMModuleInstanceExtra::functions[..] (flag 指示 native import) WASMModuleInstance::import_func_ptrs[..] - native function当导入被解析为宿主原生函数时运行时直接从import_func_ptrs数组取出函数指针并跳转执行——这正是 Fluent Bit 宿主与 Wasm 应用互操作的基础通道。在src/wasm/flb_wasm.c中运行时初始化时通过RuntimeInitArgs的Alloc_With_Allocator把flb_malloc/flb_realloc/flb_free注入 WAMR 作为内存分配器原生导入如 WASI 的 fd 相关函数也在该环境下工作。3.4 在 Fluent Bit 中的完整调用链Fluent Bit 的 filter_wasm 插件在cb_wasm_filter回调里调用flb_wasm_call_function_format_json/flb_wasm_call_function_format_msgpack见 src/wasm/flb_wasm.c L249 起其内部恰好复现了上述数据结构链路wasm_runtime_lookup_function(fw-module_inst, function_name)—— 在实例的导出函数数组里按名字查函数详见第四节wasm_runtime_module_dup_data()—— 把 tag 与 record 数据拷贝进 Wasm 模块内存返回 Wasm 侧指针组装参数数组func_args[6] {tag_buffer, tag_len, tv_sec, tv_nsec, record_buffer, record_len}通过wasm_runtime_call_wasm(fw-exec_env, func, args_size, func_args)触发解释器执行执行后返回值同样以 Wasm 指针形式放在func_args[0]再经wasm_runtime_validate_app_str_addr校验、wasm_runtime_addr_app_to_native映射回宿主指针读取字符串结果。这条链路从查导出 → 拷贝入参 → 解释执行 → 取回结果每一步都对应 vmcore 文档描述的模块/实例两级结构。四、Wasm Exports导出机制与函数查找4.1 WASMExport 三要素导出是 Wasm 对外提供符号的唯一途径。WASMExport定义在 interpreter/wasm.h L776-L780typedef struct WASMExport { char *name; /* 对外可见的导出名 */ uint8 kind; /* 导出类型 */ uint32 index; /* 在目标类型数组中的下标 */ } WASMExport;文档明确指出kind共有4 种导出类型function、globals、memory、table。由于四类对象各自组织在独立数组中index就是在对应类型数组里的下标。相应地实例结构里也维护了四个导出计数export_func_count、export_global_count、export_memory_count、export_table_countwasm_runtime.h L420-L423。4.2 模块级导出设置WASMModule::exports指向的导出数组是在模块加载时建立的运行时解析字节码的 export 段为每个导出项构造一个WASMExportname/kind/index。这一步只是登记索引真正的解析要等到实例化。4.3 函数导出的两种典型用途vmcore 文档强调函数导出通常用于两个场景宿主调用call by host宿主运行时 APIwasm_runtime_lookup_function遍历实例的WASMModuleInstance::export_functions数组把导出名与传入的目标符号名比对命中后返回其function字段指向的WASMFunctionInstance。宿主拿到函数实例后即可用wasm_runtime_call_wasm执行。Fluent Bit 的flb_wasm_call_function_format_json正是如此先wasm_runtime_lookup_function再wasm_runtime_call_wasm。被其他模块导入import by another module多模块链接时运行时把被导出模块的WASMFunctionInstance指针保存进导入模块的本地WASMFunctionInstance即上文路径二中的import_func_inst。4.4 实例级导出设置与查找的实现WASMModuleInstance::export_functions在实例化时建立运行时遍历WASMModule::exports数组筛出所有kind function的项为每个项创建一个WASMExportFuncInstance节点wasm_runtime.h L278-L281typedef struct WASMExportFuncInstance { char *name; WASMFunctionInstance *function; /* 关联的函数实例地址 */ } WASMExportFuncInstance;查找函数的实际实现位于 interpreter/wasm_runtime.c 的 wasm_lookup_function约 L3497 起它在module_inst-export_functions数组上用bsearch按导出名做二分查找命中后返回export_func_inst-function而对外 API wasm_runtime_lookup_function 则根据module_inst-module_typeWasm_Module_Bytecode走解释器实现、Wasm_Module_AoT走aot_lookup_function分发。由此可见导出数组是按名字有序排列的loader 阶段排序才能支持bsearch查找的复杂度为 O(log n)对每一条日志记录都要做一次函数查找的 Fluent Bit 过滤器而言这一设计是经过考量的。五、Wasm Globals全局变量架构doc/wasm_globals.MD 是四个子文档中最短的一篇以一张结构图images/wasm_globals.svg展示全局变量相关的内部数据布局。结合源码可以还原出与函数一致的模块/实例两级对称设计模块级WASMGlobalinterpreter/wasm.h L764-L774描述一个全局变量的类型WASMGlobalType type与初始值表达式InitializerExpression init_expr由 global 段解析而来模块还维护WASMImport *import_globals导入的全局变量。实例级WASMModuleInstanceExtra::globals类型WASMGlobalInstance *见 wasm_runtime.h L343与global_count存放实例化的全局变量导入的全局实例通过import_global_inst关联实例同时维护export_globalsWASMExportGlobInstancename 全局实例指针以支持全局变量的导出。从整体布局看iWASM 把 memory、global data、table 与WASMModuleInstanceExtra连续放置在一块实例内存中WASMModuleInstance末尾的global_table_data联合体wasm_runtime.h L477-L481既减少分配次数也让解释器通过基址 偏移快速访问全局数据区。六、Classic Interpreter经典解释器的栈格式doc/classic_interpreter.MD 以一张栈布局图images/stack_format_ci.svg说明经典解释器的核心执行模型。经典解释器classic interpreter是 iWASM 默认、可移植性最强的解释器实现其执行引擎位于 interpreter/wasm_interp_classic.c与 fast interpreterwasm_interp_fast.c并存可通过编译宏切换。结合函数架构文档与WASMFunction中的max_stack_cell_num、local_offsets等字段可以推断经典解释器在执行一个函数时采用**平坦化的运行时栈runtime stack**模型操作数栈operand stack、局部变量区、调用帧frame按预计算的 cell 数量在运行时栈上排布local_offsets记录了每个参数/局部变量在帧内的偏移从而让解释器能够以数组下标方式访问避免逐层递归调用。这也是 WAMR 能以极小栈空间运行、并支持aux_stack辅助栈的根本原因。若需深入可对照阅读 wasm_interp_classic.c 中wasm_interp_call_func_bytecode一类的解释主循环。七、如何结合 Fluent Bit 进行阅读与实践若要在本仓库内按文档 → 源码 → 应用的顺序消化 vmcore 架构推荐如下路径通读导航文档core/iwasm/README.md 先建立全局地图精读函数与导出两篇doc/wasm_function.MD 与 doc/wasm_exports.MD对照上文源码链接逐字段核对从宿主侧印证阅读 src/wasm/flb_wasm.c 的flb_wasm_instantiate与flb_wasm_call_function_format_json观察load → instantiate → lookup → call的完整生命周期跑一个真实过滤器参考 examples/filter_wasm_cC 编写 Wasm 过滤器、examples/filter_wasm_goGo 编写与 examples/filter_rustRust 编写用plugins/filter_wasm的wasm_path、wasm_function_name配置项把编译好的.wasm挂到 Fluent Bit 管道中验证了解宿主侧原生 API 注册doc/export_native_api.md 说明了如何把宿主函数注册进 WAMR 的 native 注册表——这正是文档中运行时尝试从 native API registration 解析导入的实现入口。需要说明的是本仓库同时提供解释器iwasm、AOT 与 fast-jit 多种执行模式本文所述数据结构与执行路径以解释器bytecode模式为准当模块以 AOT 形式加载Wasm_Module_AoT时WASMModuleInstance会被当作AOTModuleInstance使用wasm_runtime.h L396-L402相关实现见core/iwasm/aot目录。Fluent Bit 在编译时可选择仅加载字节码或同时接受 AOT 对象对应src/wasm/flb_wasm.c中FLB_WAMR_DISABLE_AOT_LOADING宏的分支。八、小结iWASM 的 vmcore 架构可以概括为一句话加载期构建模块蓝图WASMModule及其函数/导入/导出/全局描述实例化期将其物化为运行态对象WASMModuleInstance及其functions、import_func_ptrs、export_functions、globals解释器则依据函数实例的标志位在内部字节码 → 跨模块函数 → 原生函数三条路径之间无缝切换。这套设计既保证了多模块链接与宿主互操作的能力又通过数组化、预计算栈深度的方式满足了嵌入式与日志处理场景对低资源占用的要求。对 Fluent Bit 的开发者而言掌握这一架构就等于掌握了filter_wasm插件性能与正确性背后的全部底层逻辑。【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表