《区块链 WebAssembly 虚拟机之 Singlepass 编译器-许雄-周维 .pdf》由会员分享,可在线阅读,更多相关《区块链 WebAssembly 虚拟机之 Singlepass 编译器-许雄-周维 .pdf(31页珍藏版)》请在三个皮匠报告上搜索。
1、区块链webassembly虚拟机之singlepass编译器许雄/周维目录 Wasm介绍 为什么开发新的Wasm JIT 实现方式 Wasm X Blockchain 性能WASM诞生背景Web永恒主题:性能及能力的追求Shockwave/FlashJava AppletActiveXSilverlightAsm.jsNaCl/PNaClWebAssembly 2017年粉墨登场,2019年12月成为W3C标准并被推荐WASM是什么 高性能 接近native速度 快速启动:语言设计适合快速编译 栈式bytecode,体积小 安全 内存安全 控制流安全 跨平台 超过Java bytecode,
2、支持平台更多 技术标准而不是runtime,倾向性更小 多语言 Post-mvp(module (func$fib(export fib)(param i64)(result i64)(if(result i64)(i64.le_u(local.get 0)(i64.const 1)(then(i64.const 1)(else (i64.add (call$fib(i64.sub(local.get 0)(i64.const 2)(call$fib(i64.sub(local.get 0)(i64.const 1)WASM现状WASM应用场景 Web 插件/三方库 轻量级容器 Faas/se
3、rverless 区块链WASM虚拟机 业界有很多wasm虚拟机的实现 实现方式:解释器,JIT,AOTWASM执行模式:解释器while(!terminated)auto insn=insnspc+;switch(insn)case I32_ADD:auto lhs=val_stack.pop();auto rhs=val_stack.pop();auto res=lhs+rhs;val_stack.push(res);break;case.频繁访问内存 所有运算指令都要访问操作数栈 操作数栈保存在堆上,无法映射到寄存器 频繁发生跳转 while:直接跳转 干扰处理器分支预测,性能损失 20
4、-30%switch:间接跳转 SGX 关闭了间接跳转分支预测WASM执行模式:JIT/AOT 把字节码编译成机器码再执行 JIT:实时编译 AOT:提前编译 操作数栈 栈上元素可以直接分配到寄存器 指令分发 不再需要指令分发逻辑,没有额外的跳转指令 相当于直接利用 CPU 本身的指令分发能力WASM执行模式:JIT/AOT 浏览器内置浏览器内置 JIT 引擎引擎 分层编译模式(Tiered)Tier 1-Baseline compiler 基本不做编译优化,编译速度很快 完成编译后立即开始执行 Tier 2-Optimizing compiler 使用传统编译优化,编译速度较慢 后台编译,替
5、换 tier 1 生成的代码 通用型通用型 JIT 引擎引擎 LLVM JIT 生成代码效率很高,编译速度很慢 Cranelift JIT 生成代码效率很高,编译速度较快 Singlepass JIT 类似 baseline compiler执行模式对比执行模式执行模式编译时间编译时间运行时间运行时间总时间总时间SGX移植难度移植难度解释执行无极长极长无LLVM jit长短长极高Cranelift jit较长较短较长高Wasmer Singlepass jit短较短较短中区块链场景,AOT模式需要在链上部署机器码,存在安全风险。为什么我们要开发自己的WASM JIT 蚂蚁链有比较复杂的业务合约
6、,解释器模式无法满足性能需求 在区块链场景,有很高的确定性和安全性要求,和通用虚拟机有差异 AOT模式有注入危险指令以及产生不确定行为的风险 区块链场景对JIT编译速度和执行速度都有很高要求 蚂蚁链有支持 Intel SGX可信执行环境中执行智能合约的需求 业界WASM虚拟机没有满足以上全部需求的实现自研Singlepass编译器 解析 wasm 字节码的同时生成机器指令,一遍完成 传统编译器需要执行许多遍优化,编译速度很慢编译组件OnePassCompilerOnePassCodeGenCodePatcherX64/A64 MachineStateLocalInfoDataLayoutGlo
7、balInfoArgumentInfoFunctionStateJumpTableInfoX64/A64 CodePatcherX64/A64 ArgumentInfoOnePassABIMachineStateOpAssemblerWASM DecoderX64/A64 OnePassCodeGenX64/A64 OnePassABIX64/A64 OpAssemblerASMJIT assemblerBlockStackLocStack编译过程Loc-Imm-Mem-RegLoc StackMachine Codei32.constLoc StackImmlocal.getLoc Stac
8、kImmMemMachine CodeMachine Codei32.addLoc StackRegMachine CodemovaddMachine State-param_state-register_state-stack_sizeStack-based-register-based,许多指令不用真正生成机器码ABI设计与寄存器规范 call jit stub 参数转换、栈对齐 保存所有callee save、caller save寄存器 将callee save寄存设置为高频访问固定用途的内容module_instglobal_datamemory_basegas_left.,call
9、 native stub 参数转换、栈对齐 call interp stub 栈上分配空间,保存参数,传argc、argv到interp 栈对齐 保存caller save寄存器 scratch寄存器用作指令生成过程的中间寄存器Jited codeInterp codenative codeCall jit stubCall native stubDirect callCall interp stub高效指令翻译 在godbolt上,使用wasm指令等价的c语言或builtin函数,参考gcc/clang的O2生成的指令 popcntpopcount(unsigned int):/popcou
10、nt(unsigned int)mov w8,w0fmov d0,x8cnt v0.8b,v0.8buaddlv h0,v0.8bfmov w0,s0retint popcount(unsigned x)return _builtin_popcount(x);质量保证/问题定位 测试集 spec Python/ruby/spidermonkey等大型wasm程序 X 对应的测试集 Fuzz 问题定位 Jit interp交互 二分定位 trace执行过程Wasm x Blockchain节点(服务器+OS)区块链主进程智能合约虚拟机线程其他线程Solidity程序EVM字节码EVM虚拟机解释执
11、行C+/Go/JavaWASM字节码WASM虚拟机解释执行或JIT确定性不同节点(操作系统/硬件)上执行同样合约和输入,得到的结果必须一致不同时间使用同样的合约和上下文和存储数据,得到的结果必须一致隔离性时间隔离性,前后交易不能相互影响空间隔离性,交易并发时交易间不能相互影响,执行合约的沙箱不能影响蚂蚁链主进程对沙箱要求沙箱启动速度足够快(毫秒级)蚂蚁链主进程能够控制沙箱通信安全和沙箱安全Wasm x Blockchain 智能合约:运行在区块链上的一段用户程序 为什么选择 wasm?安全性:沙盒执行环境 高性能:接近底层机器指令 多语言:支持多种编程语言 仍面临一些技术挑战 确定性 停机问题
12、Wasm x Blockchain 为什么选择 JIT?解释器性能难以满足复杂业务的要求 JIT 有更高的技术挑战 安全性、确定性更难保证 需要适配不同处理器架构 链上编译,对时间敏感Blockchain:确定性 智能合约在不同区块链节点的执行结果必须完全一致 Wasm 执行过程中存在一些非确定性因素 浮点数:不同处理器架构对浮点数处理存在细微差异 NaN 的二进制表示 rounding mode 内存资源:不同节点进程的堆/栈空间大小不一致 Host 函数:执行在 wasm 沙箱之外 JIT 的确定性比解释器更加难以保证(调用栈深度,寄存器数量不同影响帧内存大小不一致,溢出检查,异常处理等)
13、JIT的确定性增强对性能的影响需要针对性优化Blockchain:停机问题 智能合约运行在每一个区块链节点上 消耗大量计算资源和内存资源 无法静态判定智能合约是否会停止执行 Gas 计量:动态监控智能合约执行 以指令为单位度量资源消耗 超时机制无法保证确定性 根据 gas 消耗量向用户收费 gas 消耗超限时立即停止执行 性能开销?JIT:gas 计量优化 降低计量频率 以基本块而不是指令为单位 在基本块入口插入计量逻辑 减少内存访问 预留专门的寄存器来记录 gas 减少判断逻辑 使用硬件减法指令更新 gas 值 通过溢出状态位判断 gas 耗尽JIT:Intel SGX 支持 蚂蚁链支持基于
14、 Intel SGX 的可信执行环境 SGX 可信区域中的代码不能使用系统调用 可以借助 libOS 实现,但是有开销 传统 JIT 对系统调用依赖较重 编译器:过于庞大(如 LLVM),裁剪系统调用很困难 运行时:默认依赖 mmap,信号处理等机制 蚂蚁链Singlepass JIT 原生支持 Intel SGXJIT:编译速度 测试用例:蚂蚁链真实业务合约,大小 200KB 1MB编译时间编译时间合约合约 A合约合约 B合约合约 C合约合约 Dant-singlepass42ms71ms98ms172mswasmer-singlepass95ms174ms264ms512mswasmer-
15、cranelift627ms1.25s1.54s3.21swasmer-llvm9.36s16.8s21.43s39.5s-测试环境:x86-64,8 核 2.50 GHz,16 GB 内存-均采用单线程编译JIT:执行速度 测试用例:常见计算密集型程序-测试环境:x86-64,8 核 2.50 GHz,16 GB 内存-DES,MD5,SHA256:十万次,RegEx:一百次执行时间执行时间DESDESMD5MD5RegExRegExSHA256SHA256解释执行11.54s15.56s12.32s17.4sant-singlepassant-singlepass435ms435ms716ms716ms431ms431ms723ms723mswasmer-singlepass608ms922ms433ms964mswasmer-cranelift261ms380ms240ms463mswasmer-llvm210ms324ms213ms358ms总结 Wasm JIT 编译速度与生成代码执行效率之间的权衡 区块链 对 JIT 编译和执行的确定性有很高要求 轻量级的 JIT 更容易运行在 SGX 中 Singlepass JIT 为区块链定制开发,保证确定性 支持 SGX 环境,不依赖系统调用 相比 LLVM:运行慢 50%,编译快 200 x