上一篇文章介绍了WebAssembly(简称Wasm)内存和相关指令,这篇文章将介绍变量指令和函数调用指令。 全局变量 Wasm模块可以定义或者导入全局变量。导入时,可以限定全局变量的类型和可修改性(mutability)。定义时,除了限定类型和可修改性还可以给定初始值。下面是一个WAT例子,展示了全局变量的导入和定义: (module (import "env" "g1" (global $g1 i32)) ;; immutable (import "env" "g2" (global $g2 (mut f32))) ;; mutable (global $g3 (mut i32) (i32.const 123)) ;; mutable (global $g4 (mut i64) (i64.const 456)) ;; mutable (global $g5 f32 (f32.const 1.5)) ;; immutable (global $g6 f64 (f64.const 2.5)) ;; immutable (func $main ;; $g3 = $g1 (global.get $g1) (global.set $g3) ) ) 变量指令一共5条,其中2条用来读写全局变量,下面分别介绍。 global.get global.get指令(操作码0x23)把全局变量的值推入栈顶,全局变量的索引由指令的立即数参数(32位无符号整数)给定。下面是global.get指令的示意图: bytecode: ...][ global.get ][ global_idx ][... stack: | | | | | | ?|globals[i] | | d | | d | | c | | c | | b | | b | | a | | a | └───────────┘ └───────────┘ global.set global.set指令(操作码0x24)从栈顶弹出一个操作数,赋值给全局变量(弹出的操作数必须和全局变量类型相同)。和global.get指令一样,全局变量的索引也是由指令的立即数参数给定。下面是global.set指令的示意图: bytecode: ...][ global.set ][ global_idx ][... stack: | | | | | | | | | d |? | | # globals[global_idx] = d | c | | c | | b | | b | | a | | a | └───────────┘ └───────────┘ 局部变量 全局变量的作用域是整个Wasm模块,局部变量的作用域则是整个函数。下面是一个WAT例子,展示了局部变量的定义和使用: (module (func $main (param $a i32) (param $b f32) (local $c i32) (local $d i64) (local $e f32) (local $f f64) ;; $c = $a (local.get $a) (local.set $c) ) ) 从上面的例子可以看到,函数的参数本质上其实就是局部变量。变量指令的其余3条用来读写局部变量,下面分别介绍。 local.get local.get指令(操作码0x20)和global.get指令类似,只不过读的是局部变量。下面是local.get指令的示意图: bytecode: ...][ local.get ][ local_idx ][... stack: | | | | | | ?| locals[i] | | d | | d | | c | | c | | b | | b | | a | | a | └───────────┘ └───────────┘ local.set local.set指令(操作码0x21)和global.set指令类似,只不过写的是局部变量。下面是local.set指令的示意图: bytecode: ...][ local.set ][ local_idx ][... stack: | | | | | | | | | d |? | | # locals[local_idx] = d | c | | c | | b | | b | | a | | a | └───────────┘ └───────────┘ local.tee local.tee指令(操作码0x22)指令和local.set指令类似,差别在于local.tee指令会把操作数留在栈顶。下面是local.tee指令的示意图: bytecode: ...][ local.tee ][ local_idx ][... stack: | | | | | | | | | d |? ?| d | # locals[local_idx] = d | c | | c | | b | | b | | a | | a | └───────────┘ └───────────┘ 函数调用 函数调用指令属于控制指令,一共有两条:call和call_indirect。本文只介绍call指令,call_indirect和其余控制指令将在后续文章中介绍。 call call指令(操作码0x10)进行函数调用,函数索引由指令的立即数参数(32位无符号整数)指定。在执行该指令之前,需要把函数的参数准备好,按顺序放在栈顶(最左边的参数在最下面)。指令执行完毕后,参数已经从栈顶弹出,取而代之的是函数的返回值(如果有的话)。Wasm1.0规范规定函数的返回值最多不超过一个,后续版本可能会放开这个限制。下面是call指令的示意图(假设被调用函数接受两个i32类型的参数,返回一个i32类型的值): bytecode: ...][ call ][ func_idx ][... stack: | | | | | | | | | d |? | | | c |? ?| r | # funcs[func_idx](c,d) | b | | b | | a | | a | └───────────┘ └───────────┘ 下面的WAT例子展示了call、local.get、local.set等指令的用法: (module (func $main (export "main") (result i32) (call $max (i32.const 20) (i32.const 80)) ) (func $max (param $a i32) (param $b i32) (result i32) (local.get $a) (local.get $b) (i32.gt_s (local.get $a) (local.get $b)) (select) ) ) *本文由CoinEx Chain开发团队成员Chase撰写。CoinEx Chain是全球首条基于Tendermint共识协议和Cosmos SDK开发的DEX专用公链,借助IBC来实现DEX公链、智能合约链、隐私链三条链合一的方式去解决可扩展性(Scalability)、去中心化(Decentralization)、安全性(security)区块链不可能三角的问题,能够高性能的支持数字资产的交易以及基于智能合约的Defi应用。 本文来源:CoinEx公链Talk —- 编译者/作者:CoinEx公链Talk 玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。 |
# Wasm介绍之4:函数调用
2020-02-28 CoinEx公链Talk 来源:火星财经
- 上一篇:曦阳说币:2.28晚间大饼行情趋势分析
- 下一篇:钱包安全问答汇总|最近几次分享整理
LOADING...
相关阅读:
- 前哨|挖矿新指令伊朗要求矿工表明身份及矿场规模2020-07-07
- 交易除了佣金别忽略了这个隐形成本2020-04-10
- # Wasm介绍之6:间接函数调用2020-03-12
- 欧洲新颁布的第5条AML指令规范了加密货币市场2020-03-11
- 金色前哨|波卡将通过SecondState引入基于WebAssembly的以太坊2.0虚拟机2020-03-02