上一篇文章介绍了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.get0x23global.get
bytecode:
...][ global.get ][ global_idx ][...

stack:
|           |          |           | 
|           |         ➘|globals[i] | 
|     d     |          |     d     |
|     c     |          |     c     | 
|     b     |          |     b     |  
|     a     |          |     a     | 
└───────────┘          └───────────┘

global.set

global.set0x24global.getglobal.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.get0x20global.getlocal.get
bytecode:
...][ local.get ][ local_idx ][...

stack:
|           |          |           | 
|           |         ➘| locals[i] |
|     d     |          |     d     |
|     c     |          |     c     | 
|     b     |          |     b     |  
|     a     |          |     a     | 
└───────────┘          └───────────┘

local.set

local.set0x21global.setlocal.set
bytecode:
...][ local.set ][ local_idx ][...

stack:
|           |          |           | 
|           |          |           | 
|     d     |➚         |           | # locals[local_idx] = d
|     c     |          |     c     | 
|     b     |          |     b     |  
|     a     |          |     a     | 
└───────────┘          └───────────┘

local.tee

local.tee0x22local.setlocal.teelocal.tee
bytecode:
...][ local.tee ][ local_idx ][...

stack:
|           |          |           | 
|           |          |           | 
|     d     |➚        ➘|     d     | # locals[local_idx] = d
|     c     |          |     c     | 
|     b     |          |     b     |  
|     a     |          |     a     | 
└───────────┘          └───────────┘

函数调用

callcall_indirectcallcall_indirect

call

call0x10calli32i32
bytecode:
...][ call ][ func_idx ][...

stack:
|           |          |           | 
|           |          |           | 
|     d     |➚         |           |
|     c     |➚        ➘|     r     | # funcs[func_idx](c,d) 
|     b     |          |     b     |  
|     a     |          |     a     | 
└───────────┘          └───────────┘
calllocal.getlocal.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应用。