EVM memory — a byte-addressable, dynamically expanding linear memory.
Memory expands in 32-byte words. Reads or writes beyond the current size
expand it, and new bytes read as zero. Gas cost increases quadratically with
memory size (see EEVM.Gas.Memory).
The contents are stored as 4 KiB binary chunks in a map keyed by chunk index.
Chunks that were never written are absent and read as zeros, so expansion
only bumps size. A write rebuilds just the chunks it touches, and reads
slice whole ranges out of the chunks. In bench/ this beat both a map of
single bytes (the previous layout) and one flat binary, which must copy the
whole buffer on every write and falls far behind once memory grows past a
few KiB.
Summary
Functions
Copies length bytes from src to dst within memory (memmove semantics).
Loads a 256-bit (32-byte) word from the given byte offset.
Creates a new empty memory.
Reads a range of bytes from memory as a binary, expanding memory to cover it.
Returns the current memory size in bytes (always a multiple of 32).
Stores a 256-bit (32-byte) word at the given byte offset, big-endian.
Stores the low byte of value at the given offset.
Copies a call's output into the caller's output area, size bytes at offset.
Writes length bytes of source, starting at source_offset, to memory at
offset. Bytes past the end of source are written as zero.
Types
@type t() :: %EEVM.Interpreter.Memory{ data: %{required(non_neg_integer()) => binary()}, size: non_neg_integer() }
Functions
@spec copy(t(), non_neg_integer(), non_neg_integer(), non_neg_integer()) :: t()
Copies length bytes from src to dst within memory (memmove semantics).
This is the MCOPY operation (EIP-5656). Overlapping regions are handled correctly because the source is read before anything is written.
@spec load(t(), non_neg_integer()) :: {non_neg_integer(), t()}
Loads a 256-bit (32-byte) word from the given byte offset.
This is the MLOAD operation. Unwritten bytes read as zero.
@spec new() :: t()
Creates a new empty memory.
@spec read_bytes(t(), non_neg_integer(), non_neg_integer()) :: {binary(), t()}
Reads a range of bytes from memory as a binary, expanding memory to cover it.
Used by RETURN, REVERT, LOG, KECCAK256, CREATE, and the CALL family.
@spec size(t()) :: non_neg_integer()
Returns the current memory size in bytes (always a multiple of 32).
@spec store(t(), non_neg_integer(), non_neg_integer()) :: t()
Stores a 256-bit (32-byte) word at the given byte offset, big-endian.
This is the MSTORE operation.
@spec store_byte(t(), non_neg_integer(), non_neg_integer()) :: t()
Stores the low byte of value at the given offset.
This is the MSTORE8 operation.
@spec write_output(t(), non_neg_integer(), non_neg_integer(), binary()) :: t()
Copies a call's output into the caller's output area, size bytes at offset.
Only min(size, byte_size(output)) bytes are written; the rest of the area keeps
its contents, though memory still expands over all of it, which the CALL already
paid for (execution-specs generic_call, actual_output_size).
@spec write_slice( t(), non_neg_integer(), binary(), non_neg_integer(), non_neg_integer() ) :: t()
Writes length bytes of source, starting at source_offset, to memory at
offset. Bytes past the end of source are written as zero.
These are the semantics of CALLDATACOPY, CODECOPY, EXTCODECOPY, and RETURNDATACOPY.