LOADING...
LOADING...
LOADING...
当前位置: 玩币族首页 > 行情分析 > Wasm介绍之2:指令集和栈

Wasm介绍之2:指令集和栈

2020-02-15 CoinEx公链Talk 来源:火星财经


上?篇文章介绍了WebAssembly(后?简称Wasm)二进制格式,这一篇文章将介绍Wasm指令集、操作数栈

和部分指令。

Wasm指令集

和真实的机器码?样,Wasm?进制文件中的代码也由一条?条的指令构成。同样,Wasm指令也包含两部分信息:操作码(Opcode)和操作数 (Operands)。Wasm操作码固定为?一个字节,因此最多能表示256条指令,这?点和Java字节码?样。Wasm1.0规范?共定义了?172条指令,这些指令按功能可以分为5大类,分别是:

控制指令(Control Instructions),共13条。

参数指令(Parametric Instructions),共2条。

变量?指令(Variable Instructions),共5条。

内存指令(Memory Instructions),共25条。

数值指令(Numeric Instructions),共127条。

可以看到,已经定义的指令中,有超过2/3属于数值指令。为了?便??类书写和?解,Wasm规范给也给每个操作码定义了?助记符(Mnemonic),?比如说操作码 0x41 的助记符是 i32.const 。下?是已定义指令的操作码分布示意图:


有一部分指令需要携带?些信息,这些信息编码后紧跟在指令操作数的后面,叫做静态?立即参数(StaticImmediate Arguments,后?简称?即数)。 以 i32.const 指令为?,操作码 0x41 后?要跟?个编码后的32位整数。在后?的例子中,我们将用类似下面这样的示意图来表示编码后的指令:


和JVM等栈式虚拟机一样,?部分Wasm指令也会?到操作数栈(Operand Stack,后文简称栈)。这些指令从栈顶弹出一个或多个数,进?计算,然后把结果推入栈顶。被指令操作的这些栈顶元素叫做指令的动态操作数(Dynamic Operands,后?文简称操作数)。在后?的?子中,我们将?类似下?这样的示意图来表示指令执? 前后栈的状态(?小箭头表示弹出或推入操作):


参数指令和数值指令仅对栈进?操作,?为比较简单,由本?进?介绍。其他指令将在后续文章中介绍。

参数指令

参数指令有两条: drop (操作码是 0x1A )和 select (操作码是 0x1B )。

drop

drop 指令,从栈顶弹出?个任意类型的操作数。 drop 指令没有立即数,下?是它的示意图:


select

select 指令先后从栈顶弹出3个操作数,如果最先弹出的操作数等于0则将第二个弹出的操作数推?入栈,否则将第三个弹出的操作数推?入栈。 select 指令也没有?即数,下面是它的示意图:


注意位于栈顶的操作数必须是 i32 类型,其余两个操作数必须有相同类型。当需要强调操作数的具体类型时,我们会在示意图中用圆括号标出类型。 drop 和 select 是比较特殊的两条指令,因为只有这两条指令没有将操作数的类型完全限定。对于其他的指令,所有操作数的类型都是完全限定的。

数值指令

数值指令可以按操作数类型分成 i32 、 i64 、 f32 、 f64 四组,每一组指令?可以按照操作进?一步分为:

常?指令(Constant Instructions)

测试指令(Test Instructions)

比较指令(Comparison Instructions)

算术指令(Arithmetic Instructions)

一元(Unary)算术指令

二元(Binary)算术指令转换指令(Conversion Instructions)

除常量?指令外,其余数值指令都没有?立即数。

常量指令

常量指令将?即数推入栈顶,以 i32.const 指令(操作码 0x41 )为?,下?是它的示意图:


常量指令一共有四条,另外三条是: i64.const (操作码 0x42 )、 f32.const (操作码 0x43 )、f64.const (操作码 0x44 )。?难发现,Wasm操作码助记符的命名规则是:如果指令执?后栈顶元素的类型是 t ,那么助记符就以 t. 开头。

测试指令从栈顶弹出一个操作数,测试它是否是0,如果是则将 i32 类型1推?入栈,否则将 i32 类型0推入栈。测试指令只有两条: i32.eqz (操作码 0x45 )和 i64.eqz (操作码 0x50 )。以 i64.eqz 指令为?,下面是它的示意图:


可以看到,测试指令的结果其实是布尔值,只不?过Wasm没有定义 bool 类型,而是用 i32 类型来表示(1表示 ture ,0表示 false )。

比较指令

比较指令从栈顶弹出两个相同类型的操作数,进??较,然后将结果压栈。和测试指令一样,比较指令的结果也是布尔值(也就是 i32 类型)。以 i64.lt_s 指令(操作码 0x53 )为?,下面是它的示意图:


除?等于(eq),还有进?不?等于(ne)、小于(le)、大于(gt)、小于等于(le)、大于等于(ge)比较的指令,这?就不?一介绍?。需要说明的是,对于有些整数类型的指令,需要明确指出如何解释操作数:将其当成有符号数(Signed,助记符带 _s 后缀)还是无符号数(Unsigned,助记符带 _u 后缀)。这类指令一般是成对儿出现,?比如上??子中的 i64.lt_s 指令,与之对应的还有 i64.lt_u 指令(操作码 0x54 )。

一元算术运算

一元算术指令从栈顶弹出一个操作数,进?计算,然后把结果推入栈顶。以 f32.neg (操作码 0x8C )指令为 ?,下?是它的示意图:


二元算术运算

二元算术指令从栈顶弹出两个操作数,进?计算,然后将结果推入栈顶。以 f32.sub 指令(操作码 0x93 )为 ?,下?是它的示意图:


类型转换

类型转换指令从栈顶弹出?个操作数,进?行?类型转换,然后把结果推?栈顶。如果操作数在类型转换之前的类型是 t ,之后的类型是 t' ,转换操作是 conv ,则指令的助记符是 t'.conv_t 。以 i32.wrap_i64 (操作
码 0xA7 )指令为例?,下?面是它的示意图:


比较、算 术、转换指令数??较多,本?无法?一介绍,请读者参考Wasm规范。

*本文由CoinEx Chain开发团队成员Chase撰写。CoinEx Chain是全球首条基于Tendermint共识协议和Cosmos SDK开发的DEX专用公链,借助IBC来实现DEX公链、智能合约链、隐私链三条链合一的方式去解决可扩展性(Scalability)、去中心化(Decentralization)、安全性(security)区块链不可能三角的问题,能够高性能的支持数字资产的交易以及基于智能合约的Defi应用。

—-

编译者/作者:CoinEx公链Talk

玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。

LOADING...
LOADING...