Wasmex.Memory (Wasmex v0.6.0)
A WebAssembly instance has its own memory, represented by the Wasmex.Memory
struct.
It is accessible by the Wasmex.Instance.memory/3
getter.
The grow/2
method allows to grow the memory by a number of pages (of 65kb each).
Wasmex.Memory.grow(memory, 1)
The current size of the memory can be obtained with the length/1
method:
Wasmex.Memory.length(memory) # in bytes, always a multiple of the the page size (65kb)
When creating the memory struct, the offset
param can be provided, to subset the memory array at a particular offset.
offset = 7
index = 4
value = 42
{:ok, memory} = Wasmex.Instance.memory(instance, :uint8, offset)
Wasmex.Memory.set(memory, index, value)
IO.puts Wasmex.Memory.get(memory, index) # 42
Memory Buffer viewed in different Datatypes
The Wasmex.Memory
struct views the WebAssembly memory of an instance as an array of values of different types.
Possible types are: uint8
, int8
, uint16
, int16
, uint32
, and int32
.
The underlying data is not changed when viewed in different types - it is just its representation that changes.
View memory buffer as a sequence of… | Bytes per element |
---|---|
int8 | 1 |
uint8 | 1 |
int16 | 2 |
uint16 | 2 |
int32 | 4 |
uint32 | 4 |
This can be resolved at runtime:
{:ok, memory} = Wasmex.memory(instance, :uint16, 0)
Wasmex.Memory.bytes_per_element(memory) # 2
Since the same memory seen in different data types uses the same buffer internally. Let's have some fun:
int8 = Wasmex.memory(instance, :int8, 0)
int16 = Wasmex.memory(instance, :int16, 0)
int32 = Wasmex.memory(instance, :int32, 0)
b₁
┌┬┬┬┬┬┬┐
Memory.set(int8, 0, 0b00000001)
b₂
┌┬┬┬┬┬┬┐
Memory.set(int8, 1, 0b00000100)
b₃
┌┬┬┬┬┬┬┐
Memory.set(int8, 2, 0b00010000)
b₄
┌┬┬┬┬┬┬┐
Memory.set(int8, 3, 0b01000000)
# Viewed in `int16`, 2 bytes are read per value
b₂ b₁
┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐
assert 0b00000100_00000001 == Memory.get(int16, 0)
b₄ b₃
┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐
assert 0b01000000_00010000 == Memory.get(int16, 1)
# Viewed in `int32`, 4 bytes are read per value
b₄ b₃ b₂ b₁
┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐
assert 0b01000000_00010000_00000100_00000001 == Memory.get(int32, 0)
Link to this section Summary
Functions
Returns the number of bytes used to represent a unit in memory.
Grows the amount of available memory by the given number of pages and returns the number of previously available pages.
Note that the maximum number of pages is 65_536
Returns the number of elements that fit into memory for the given unit size and offset.
Same as length/1 except the unit size
and offset given at memory creation are overwritten by the given values.
Link to this section Types
Specs
Link to this section Functions
bytes_per_element(memory)
Specs
bytes_per_element(t()) :: pos_integer()
bytes_per_element(atom()) :: pos_integer()
Returns the number of bytes used to represent a unit in memory.
For the limited number of unit sizes the byte values are the following:
size | Bytes per element |
|----------|---|
| int8
| 1 |
| uint8
| 1 |
| int16
| 2 |
| uint16
| 2 |
| int32
| 4 |
| uint32
| 4 |
{:ok, memory} = Wasmex.Instance.memory(instance, :uint16, 0)
Wasmex.Memory.bytes_per_element(memory) # 2
Alternatively, the size atom can be given directly:
Wasmex.Memory.bytes_per_element(:uint32) # 4
from_instance(instance)
Specs
from_instance(Wasmex.Instance.t()) :: {:ok, t()} | {:error, binary()}
from_instance(instance, size, offset)
Specs
from_instance(Wasmex.Instance.t(), atom(), non_neg_integer()) :: {:ok, t()} | {:error, binary()}
get(memory, index)
Specs
get(t(), non_neg_integer()) :: number()
get(memory, size, offset, index)
Specs
get(t(), atom(), non_neg_integer(), non_neg_integer()) :: number()
grow(memory, pages)
Specs
grow(t(), pos_integer()) :: pos_integer()
Grows the amount of available memory by the given number of pages and returns the number of previously available pages.
Note that the maximum number of pages is 65_536
length(memory)
Specs
length(t()) :: pos_integer()
Returns the number of elements that fit into memory for the given unit size and offset.
Note that the WebAssembly memory consists of pages of 65kb each.
Different unit size
s needs a different number of bytes per element and the offset
may reduce the number of available elements.
{:ok, memory} = Wasmex.Memory.from_instance(instance, :uint8, 0)
Wasmex.Memory.length(memory) # 1114112 (17 * 65_536)
length(memory, size, offset)
Specs
length(t(), atom(), non_neg_integer()) :: pos_integer()
Same as length/1 except the unit size
and offset given at memory creation are overwritten by the given values.
{:ok, memory} = Wasmex.Instance.memory(instance)
Wasmex.Memory.length(memory, :uint8, 0) # 1114112 (17 * 65_536)
read_binary(memory, index, length)
Specs
read_binary(t(), non_neg_integer(), non_neg_integer()) :: binary()
read_binary(memory, size, offset, index, length)
Specs
read_binary( t(), atom(), non_neg_integer(), non_neg_integer(), non_neg_integer() ) :: binary()
read_string(memory, index, length)
Specs
read_string(t(), non_neg_integer(), non_neg_integer()) :: String.t()
read_string(memory, size, offset, index, length)
Specs
read_string( t(), atom(), non_neg_integer(), non_neg_integer(), non_neg_integer() ) :: String.t()
set(memory, index, value)
Specs
set(t(), non_neg_integer(), number()) :: number()
set(memory, size, offset, index, value)
Specs
set(t(), atom(), non_neg_integer(), non_neg_integer(), number()) :: number()
wrap_resource(resource, size, offset)
write_binary(memory, index, str)
Specs
write_binary(t(), non_neg_integer(), binary()) :: :ok
write_binary(memory, size, offset, index, str)
Specs
write_binary(t(), atom(), non_neg_integer(), non_neg_integer(), binary()) :: :ok