忧郁的大能猫
好奇的探索者,理性的思考者,踏实的行动者。
Table of Contents:
每个Wasm模块都可以定义或者导入一个内存,内存大小以页为单位,每一页是64K。定义内存时,需要指定内存的页数下限。页数上限可选,可以指定也可以不指定。内存的初始数据则可以在数据段中指定。下面是一个WAT例子,展示了内存和数据段的定义:
(module
(memory 1 8) ;; { min: 1, max: 8 }
(data 0 (offset (i32.const 100)) "hello")
;; ...
)
memory.size 指令(操作码0x3F)把内存的当前页数按i32类型推入栈顶。memory.size 指令带有一个1字节立即数,可以指定操作的是哪个内存。由于Wasm1.0规范规定最多只能有一个内存,所以目前这个立即数只能是0。下面是memory.size 指令的示意图:
bytecode:
...][ memory.size ][ 0 ][...
stack:
| | | |
| | ➘| p(i32) | # page count
| d | | d |
| c | | c |
| b | | b |
| a | | a |
└───────────┘ └───────────┘
memory.grow 指令(操作码0x40)将内存增长n页,其中n是一个i32类型的整数,从栈顶弹出。如果操作成功,将增长前的页数按i32类型推入栈顶,否则将-1推入栈顶。和memory.size指令一样,memory.grow指令也带有一个1字节立即数,且取值必须为0。下面是memory.grow 指令的示意图:
bytecode:
...][ memory.grow ][ 0 ][...
stack:
| | | |
| n(i32) |➚ ➘| p(i32) | # grow n pages
| d | | d |
| c | | c |
| b | | b |
| a | | a |
└───────────┘ └───────────┘
load指令从内存读取数据,然后推入栈顶。具体读取多少字节的数据,以及将数据解释为何种类型的数,因指令而异。Wasm采用了“立即数+操作数”的内存寻址方式,所有load指令都带有两个u32类型。以i64.load指令(操作码0x29)为例,下面是它的示意图:
bytecode:
...][ i64.load ][ align ][ offset ][...
stack:
| | | |
| | | |
| d(i32) |➚ ➘|m[offset+d]| # i64
| c | | c |
| b | | b |
| a | | a |
└───────────┘ └───────────┘
store 指令从栈顶弹出操作数,然后写入内存。具体如何解释操作数,以及写入多少字节,因指令而异。所有的store指令也都带有两个立即数,含义和 load指令一样。和load指令不同的是,store指令要从栈顶弹出两个操作数,一个用于计算内存地址,另一个是要写入的数据。以i64.store 指令(操作码0x37)为例,下面是它的示意图:
bytecode:
...][ i64.store ][ align ][ offset ][...
stack:
| | | |
| e(i64) |➚ | |
| d(i32) |➚ | | # m[offset+d]=e
| c | | c |
| b | | b |
| a | | a |
└───────────┘ └───────────┘