1. 引言
虚拟机采用指令集架构(Instruction set architecture,ISA),即:
- 具有固定语义的一组有限数量的指令集。
虚拟机(Virtual Machine,VM)的主要结构有:
- 程序:由指令序列组成。虚拟机每次仅读取程序中的一条指令。
- 内存
- 虚拟机:主要工作为:
- 1)读取输入
- 2)对内存(RAM)读写
- 3)修改本地机器状态:内部机器状态为:Stack和(或)Registers。
- 4)写输出
- 5)中止执行
现有的VM/zkVM架构,以及内部机器状态内存模型,选型情况为:
1.1 虚拟机架构选型——Harvard架构 vs. Von Neumann架构
虚拟机(VM)架构通常需考虑在哈佛架构 和 冯·诺依曼架构 之间二选一:
- 哈佛架构:程序和内存分属不同区域。
- 优点为:
- 无program loader
- 仅lookup table需要额外的cycles。
- 缺点为:
- 无JIT
- per program setup(需对每个程序做setup)
- 优点为:
- 冯·诺依曼架构:程序在内存中。
- 优点为:
- 通用,更接近现代CPUs
- 缺点为:
- 必须约束所取指令的正确性
- 需要program loader(来将程序加载到内存中), 意味着需要更多cycles
- 优点为:
1.2 虚拟机内存模型选型——Stack, Register, vs. Direct Memory
虚拟机内部机器状态内存模型,通常有3种选择:
- 1)Stack Machine:通过访问stack top来进行数据移动,指令更简单。如:
- EVM
- Miden-asm
- Wasm
- 2)Register Machine:指令比Stack Machine要短,但更复杂,不过数据移动操作要少的多。如:
- RISC-V
- 3)Direct Memory Machine:无需数据移动(zero data movement),但有更多的读写操作。如:
- LLVM-IR
三种虚拟机内部机器状态内存模型的性能对比为:
1.3 虚拟机指令集选型——RISC-V vs. WASM vs. LLVM vs. …
2022年6月视频 Comparing ARM vs RISC-V vs x86_64 with GCC vs Clang 中,有对比了GCC和CLang编译器,对相同程序分别为ARM、RISC-V和x86_64架构编译的具体情况对比:
传统Web2世界的指令集有:
- RISC-V
- WASM
- LLVM
- MIPS
- ARM
- x86_x64
- i686
- aarch64等等
而Web3世界引入的指令集有:
- Cairo虚拟机所用的CASM指令集
- EVM所用的bytecode指令集
- BTC所用的BTC脚本指令集
- Polygon Miden所用的MAST指令集
其中Polygon Miden所用的MAST指令集,是针对ZK应用定制的指令集。
ISA(Instruction set architecture)性能分析,主要关注的是程序中的指令数。
传统ISA和“ZK ISA”是针对不同的场景进行了优化:
-
传统ISA为:
- 内存局限性:处理器具有内存上限。
- 程序size(如压缩):无法有太多通用寄存器。
- 执行速度
-
"ZK ISA"为:
- 每个cycle,一条指令:具有指令上限。
- 指令大小的影响小:指令可包含更多信息,如引用更多寄存器或本地变量。
- 证明速度或性能。
2. 指令集
WebAssembly和RISC-V都是近 10 年发展起来的新型指令集架构 (ISA)。引用webassembly.org上对 WebAssembly 的介绍:
WebAssembly(缩写为Wasm )是一种基于栈的虚拟机的二进制指令格式。Wasm 被设计为 C/C++/Rust 等高级语言编译的可移植目标,支持在 Web 上部署客户端和服务端应用程序。
以及riscv.org上对 RISC-V 的介绍:
RISC-V 是一种免费且开放的 ISA,通过开放标准协作开启处理器创新的新时代。RISC-V ISA 诞生于学术界和研究界,在架构上提供了全新水平的免费、可扩展的软件和硬件自由度,为未来 50 年的计算设计和创新铺平了道路。
这两个 ISA 似乎有很大不同。WebAssembly 主要针对 JIT 编译,特别是浏览器,而 RISC-V 是为硬件设计的,其目标之一是在 FPGA 和电路上高效实现。它们就像过去的 Java 和 x86:一种字节码格式和一套硬件指令集。它们之间有什么关系呢?
其实,字节码和真实硬件指令集之间的界限是有点模糊的。如,x86 指令集曾经直接由执行控制和算术运算的电路执行。但现在在较新的 Intel 和 AMD CPU 上,x86 指令被即时解码为内部 RISC 格式,并发送到 RISC 核心执行——这难道不是某种类似于 JRE 对 Java 所做的硬件“JIT 编译”吗?同时, Java 和 WebAssembly 也有实验性的硬件实现,尽管其效率不如 JIT 编译器在现代成熟 CPU 上所能实现的那么高。
实际上,人们已经在 WebAssembly 通常用于区块链上的智能合约的位置上使用 RISC-V。它就是CKB VM。跨越 WebAssembly 字节码格式和 RISC-V 硬件指令集之间模糊的界限,它们有哪些相似之处,又有哪些不同之处?
RISC-V和WASM的不同之处主要在于:
- 1)代码与数据分离
- 大多数现代架构都使用独特的寻址空间来存放代码和数据,包括 RISC-V。但 WebAssembly 却没有这样做,实际上,正在运行的代码甚至没有提供访问自身的方法。可能的原因如下:
- JIT 编译的简单性。如果代码可以自我修改,那么 JIT 编译器需要检测修改并更新相应的机器代码 —— 这非常复杂。
WebAssembly 对强大主机环境的假设。链接等将完全由主机完成,程序无需关心自身启动。 - 安全性。在运行时生成代码是危险的。
- 2)整数宽度
- RISC-V 有 32 位版本 (RV32) 和 64 位版本 (RV64)。在 RV32 上,指针宽度和最大数据宽度均为 32 位,而在 RV64 上,两个宽度均为 64 位。
- 同时,对于 WebAssembly,指针宽度为 32 位,而最大数据宽度为 64 位。这里的假设可能是现代桌面或移动环境,其中 CPU 具有 64 位数据宽度。由于 WebAssembly 使用线性内存布局,因此 32 位地址空间(4GB)对于大多数 Web 应用程序来说已经足够了。
- 3)类型和控制流
- WebAssembly 非常“结构化”:JIT 编译器要求所有函数调用、循环、跳转和值类型都符合结构约束。如,不能将两个值传递给接受三个参数的函数,不能跳转到另一个函数中的位置,也不能对两个整数执行浮点加法指令。
- 然而 RISC-V 没有这些限制。一切都只是寄存器中的值,程序员可以决定如何使用它们。
- 4)机器模型
- WebAssembly 建立在stack machine栈机模型之上,而 RISC-V(以及大多数其他硬件架构)是register machine寄存器机。
- 在 WebAssembly 中,从语义上讲,任何指令都会从值栈中弹出其操作数(如果有),执行定义的操作,并将其结果(如果有)推回到值栈。但是,程序中任何时候的值栈结构都可以静态确定——这与 Java 字节码不同,如,保持栈结构静态可确定不是一种优化,而是一种编译时强制性要求。
- 5)内存
- 虽然两种 ISA 都定义了无类型、字节寻址的内存,但有些细节有所不同。WebAssembly 中的内存实际上是一个大字节数组:地址从零开始,不断扩展到上限(可以通过执行指令动态增加上限)。相比之下,RISC-V 使用虚拟内存,其中page tables页表用于将地址映射到底层物理内存。
- WebAssembly 的内存模型虽然实现简单、JIT 编译效率高,但与 RISC-V 相比存在几个问题:
- 地址零是有效的,导致假定因取消引用空指针而崩溃的程序出现异常。
- No "gaps"是可能的。因此,在多线程环境中防止栈溢出的保护页技巧将不起作用。
- 虚拟内存通常带有内存保护功能,其中每个内存页都具有读取、写入和执行权限的组合。这是一种重要的安全机制,因为它可以防止在不期望此类操作的内存区域执行和写入。RISC-V 实现了内存保护,但 WebAssembly 没有——也许在可执行代码不可寻址的架构中,它不那么重要?
- 虽然两种 ISA 都定义了无类型、字节寻址的内存,但有些细节有所不同。WebAssembly 中的内存实际上是一个大字节数组:地址从零开始,不断扩展到上限(可以通过执行指令动态增加上限)。相比之下,RISC-V 使用虚拟内存,其中page tables页表用于将地址映射到底层物理内存。
- 6)同步
- 计算机至少需要一条条件分支指令才能实现图灵完备。同样,多处理器架构至少需要一条“原子条件分支”指令才能正确同步。在 WebAssembly中该指令为
i{32,64}.atomic.rmw.cmpxchg
和 RISC-V中该指令为LR/SC
。 LR/SC
具有比cmpxchg
更强的语义。有了cmpxchg
,就有了著名的ABA 问题,但LR/SC
不受影响。这也意味着使用cmpxchg
-only架构进行LR/SC
模拟比其他方式要困难得多;必须使用全局锁或事务内存之类的东西,这大大增加了复杂性。RISC-V 无论如何都是为硬件设计的,但如果想编写软件实现,将不得不解决这个问题。
- 计算机至少需要一条条件分支指令才能实现图灵完备。同样,多处理器架构至少需要一条“原子条件分支”指令才能正确同步。在 WebAssembly中该指令为
LLVM 字节码、WebAssembly 和 RISC-V 是三种不同的技术,它们具有一些共同的特征和目标。它们都基于精简指令集计算机 (reduced instruction set computer,RISC) 的概念,这意味着它们使用一组小型且简单的指令,这些指令可以由处理器高效执行。它们还都设计为可移植的,这意味着它们可以在不同的平台和架构上运行,而无需重新编译或修改。
- LLVM 字节码是 LLVM 编译器框架使用的中间表示 (IR)。它是一种低级语言,可以从各种源语言生成,如 C、C++、Rust 和 Swift。然后,LLVM 字节码可以通过各种 LLVM 工具进行优化、分析和转换,最终编译为目标平台的本机代码。LLVM 字节码并非旨在直接执行,而是作为编译器开发和优化的通用格式。
- WebAssembly 是一种基于栈的虚拟机的二进制指令格式。它被设计为 Web 应用程序的编译目标,可在现代 Web 浏览器中实现 C、C++、Rust 和 Go 等语言的高性能执行。WebAssembly 还可以与 JavaScript 一起运行,允许两种语言交互并访问 Web API。但是,WebAssembly 并不局限于 Web 平台,也可以嵌入到其他环境中,如桌面应用程序、移动设备和云服务。
- RISC-V 是一种开放标准指令集架构 (ISA),它定义了处理器可以执行的基本操作。它被设计为模块化和可扩展的,允许不同的扩展和变体来满足不同的需求和应用。RISC-V 还根据免版税的开源许可提供,使任何人都可以实施、修改和分发 RISC-V 处理器和软件。RISC-V 已被各种行业和领域采用,如嵌入式系统、个人计算机、超级计算机和人工智能。
这三项技术在设计原理和特点上具有一些相似之处。如:
- 它们都使用可变长度编码来编码指令,这意味着每条指令可以根据其操作数和编码方案具有不同的大小。这允许更紧凑和高效的代码表示。
- 它们都支持多种地址空间大小,如 32 位、64 位和 128 位。这为内存管理和寻址提供了更大的灵活性和可扩展性。
- 它们都支持使用 IEEE 754 标准的浮点运算。这允许在不同的平台和环境中一致且准确地计算实数。
- 它们都具有文本表示形式,可用于调试、测试、学习和手动编写程序。可以使用各种工具将文本表示形式转换为二进制格式或从二进制格式转换为文本表示形式。
这三种技术在范围和用途上也存在一些差异。如:
- LLVM 字节码是一种中间表示(通常称为LLVM IR),并非用于直接执行,而是为了方便编译器的开发和优化。它不是标准或规范,而是 LLVM 框架的实现细节。
- 默认情况下,LLVM IR 不可移植(同一程序对不同架构有不同的表示)或不稳定(它会随着优化和语言要求的变化而变化)。它具有大量信息的表示,这些信息对于实现中级编译器优化很有用,但对于代码生成没有用(但它代表了代码生成实现者需要处理的大面积)。它还具有未定义的行为(与 C 和 C++ 的行为非常相似),这使得某些优化类可行或更强大,但可能导致运行时行为不可预测。LLVM 的二进制格式(位码)是为链接时优化而设计的 IR 的临时磁盘序列化,而不是为了稳定性或可压缩性(尽管它确实具有这两者的一些功能)。
- WebAssembly 是一种二进制格式,旨在由虚拟机直接执行。它是一种 Web 标准,由 W3C WebAssembly 工作组和社区组开发和维护,主要浏览器供应商也参与其中。
- RISC-V 是一种指令集架构,定义处理器可以执行的基本操作。它是一种开放标准,由 RISC-V International 开发和维护,并有各种成员和贡献者参与。
LLVM 字节码、WebAssembly 和 RISC-V 是三种不同的技术,它们基于 RISC 概念,具有一些共同的特征和目标。它们还被设计为可跨不同平台和架构移植。然而,它们在范围和用途上也存在一些差异,可满足软件和硬件领域的不同需求和应用。
参考资料
[1] 2023年9月ZKSummit10 Wei Dai @1k(x) & Terry Chung @1k(x)分享视频ZK10: Analysis of zkVM Designs - Wei Dai & Terry Chung【1k(x)为早期密码学投资基金】
[2] 2020年3月 Heyang Zhou博客 A Comparison between WebAssembly and RISC-V
[3] Ethereum WebAssembly Comparison with Other Architectures
[4] Hacker News 2020年10月讨论 RISC-V讨论
[5] 2022年6月视频 Comparing ARM vs RISC-V vs x86_64 with GCC vs Clang
[6] PURE ENGINEERING Instruction Sets: Comparing LLVM bytecode, Web Assembly and RISC-V