The operand stack¶
The per-frame EVM operand stack (YP §9.1, μ_s): up to 1024 words, LIFO.
The words live behind the host interface (the corresponding stack.c in
extractions/c/spec/contract/ or extractions/c/optimised/contract/) as per-frame flat arrays for O(1) access;
proof targets see the vals as bodyless axioms over an abstract per-frame
list-of-words model.
The active frame's position is the abstract cursor token
StackPointer, threaded by value through the interpreter and
every opcode handler in the state-passing convention and held in the
stack_top frame register at frame boundaries. This module keeps
ownership of the word storage and its workspace binding — only the cursor
changes custody. Frames form a stack of stacks:
operand_stack_push_empty_frame on a sub-call returns the child's
empty cursor, operand_stack_pop_frame releases it on return (the
parent's cursor is restored from its frame checkpoint), and
stack_reset returns the base frame's empty cursor per transaction.
The EVM layer accesses slots through read_stack_word / write_stack_word and enforces the depth bounds through validate_stack before a handler body runs. It charges nothing here — this is pure mechanism, so the slot and cursor axioms perform no re-checks.
Non-normative
This page documents the model's host interface — internal contracts of the executable specification, not protocol rules.
val stack_reset_host¶
Resets to a single empty operand stack (per-transaction reset) and returns the base frame's empty cursor.
val stack_reset_host = impure { c: "stack_reset" } : unit -> bits(64)val operand_stack_push_empty_frame_host¶
Pushes a fresh, empty operand stack for a sub-call frame and returns its empty cursor.
val operand_stack_push_empty_frame_host = impure { c: "operand_stack_push_empty_frame" } : unit -> bits(64)val operand_stack_pop_frame¶
Pops the current frame's stack storage, restoring the caller's; the caller's cursor is restored from its frame checkpoint.
val operand_stack_pop_frame = impure { c: "operand_stack_pop_frame" } : unit -> unitval stack_top_height_host¶
The number of words below a cursor; the 1024-item bound is enforced by the EVM layer.
val stack_top_height_host = impure { c: "stack_top_height" } : bits(64) -> operand_stack_heightThe number of words on an operand stack.
type operand_stack_height = range(0, 1024)val stack_slot_read_host¶
The word index slots below the cursor's top (index = 0 is the
top). The EVM layer has validated index < height.
val stack_slot_read_host = impure { c: "stack_slot_read" } : (bits(64), stack_index) -> wordA zero-based index from the top of the operand stack.
type stack_index = range(0, 1023)The EVM 256-bit machine word (YP §9.1). A transparent range keeps the mathematical subtype relation visible: narrower non-negative ranges can be passed as words without a model-level conversion.
type word = range(0, 2 ^ 256 - 1)val stack_slot_write_host¶
Overwrites the word index slots below the cursor's top (SWAPn).
val stack_slot_write_host = impure { c: "stack_slot_write" } : (bits(64), stack_index, word) -> unitA zero-based index from the top of the operand stack.
type stack_index = range(0, 1023)The EVM 256-bit machine word (YP §9.1). A transparent range keeps the mathematical subtype relation visible: narrower non-negative ranges can be passed as words without a model-level conversion.
type word = range(0, 2 ^ 256 - 1)val stack_slot_write_next_host¶
Writes the next free slot without changing the cursor.
val stack_slot_write_next_host = impure { c: "stack_slot_write_next" } : (bits(64), word) -> unitThe EVM 256-bit machine word (YP §9.1). A transparent range keeps the mathematical subtype relation visible: narrower non-negative ranges can be passed as words without a model-level conversion.
type word = range(0, 2 ^ 256 - 1)val stack_top_advance_host¶
Advances the cursor over count newly pushed slots.
val stack_top_advance_host = impure { c: "stack_top_advance" } : (bits(64), stack_slot_count) -> bits(64)The number of slots an operand-stack cursor moves in one advance or retreat.
type stack_slot_count = range(0, 1024)val stack_top_retreat_host¶
Retreats the cursor over count popped slots.
val stack_top_retreat_host = impure { c: "stack_top_retreat" } : (bits(64), stack_slot_count) -> bits(64)The number of slots an operand-stack cursor moves in one advance or retreat.
type stack_slot_count = range(0, 1024)function stack_reset¶
function stack_reset() -> StackPointer =
struct { storage = stack_reset_host(), height = 0 }Resets to a single empty operand stack (per-transaction reset) and returns the base frame's empty cursor.
val stack_reset_host = impure { c: "stack_reset" } : unit -> bits(64)The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}function operand_stack_push_empty_frame¶
function operand_stack_push_empty_frame() -> StackPointer =
struct { storage = operand_stack_push_empty_frame_host(), height = 0 }Pushes a fresh, empty operand stack for a sub-call frame and returns its empty cursor.
val operand_stack_push_empty_frame_host = impure { c: "operand_stack_push_empty_frame" } : unit -> bits(64)The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}function stack_top_height¶
function stack_top_height(top : StackPointer) -> operand_stack_height =
top.heightThe operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}The number of words on an operand stack.
type operand_stack_height = range(0, 1024)function stack_slot_read¶
function stack_slot_read(top : StackPointer, index : stack_index) -> word =
stack_slot_read_host(top.storage, index)The word index slots below the cursor's top (index = 0 is the
top). The EVM layer has validated index < height.
val stack_slot_read_host = impure { c: "stack_slot_read" } : (bits(64), stack_index) -> wordThe operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}A zero-based index from the top of the operand stack.
type stack_index = range(0, 1023)The EVM 256-bit machine word (YP §9.1). A transparent range keeps the mathematical subtype relation visible: narrower non-negative ranges can be passed as words without a model-level conversion.
type word = range(0, 2 ^ 256 - 1)function stack_slot_write¶
function stack_slot_write(top : StackPointer, index : stack_index, value : word) -> unit =
stack_slot_write_host(top.storage, index, value)Overwrites the word index slots below the cursor's top (SWAPn).
val stack_slot_write_host = impure { c: "stack_slot_write" } : (bits(64), stack_index, word) -> unitThe operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}A zero-based index from the top of the operand stack.
type stack_index = range(0, 1023)The EVM 256-bit machine word (YP §9.1). A transparent range keeps the mathematical subtype relation visible: narrower non-negative ranges can be passed as words without a model-level conversion.
type word = range(0, 2 ^ 256 - 1)function stack_slot_write_next¶
function stack_slot_write_next(top : StackPointer, value : word) -> unit =
stack_slot_write_next_host(top.storage, value)Writes the next free slot without changing the cursor.
val stack_slot_write_next_host = impure { c: "stack_slot_write_next" } : (bits(64), word) -> unitThe operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}The EVM 256-bit machine word (YP §9.1). A transparent range keeps the mathematical subtype relation visible: narrower non-negative ranges can be passed as words without a model-level conversion.
type word = range(0, 2 ^ 256 - 1)function stack_top_advance¶
Advances a stack cursor by count slots and refreshes its semantic height.
function stack_top_advance(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_advance_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}Advances the cursor over count newly pushed slots.
val stack_top_advance_host = impure { c: "stack_top_advance" } : (bits(64), stack_slot_count) -> bits(64)The number of words below a cursor; the 1024-item bound is enforced by the EVM layer.
val stack_top_height_host = impure { c: "stack_top_height" } : bits(64) -> operand_stack_heightThe operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}The number of slots an operand-stack cursor moves in one advance or retreat.
type stack_slot_count = range(0, 1024)function stack_top_retreat¶
Retreats a stack cursor by count slots and refreshes its semantic height.
function stack_top_retreat(top : StackPointer, count : stack_slot_count) -> StackPointer = {
let storage = stack_top_retreat_host(top.storage, count);
struct { storage = storage, height = stack_top_height_host(storage) }
}The number of words below a cursor; the 1024-item bound is enforced by the EVM layer.
val stack_top_height_host = impure { c: "stack_top_height" } : bits(64) -> operand_stack_heightRetreats the cursor over count popped slots.
val stack_top_retreat_host = impure { c: "stack_top_retreat" } : (bits(64), stack_slot_count) -> bits(64)The operand-stack cursor for the active frame, threaded by value through
the interpreter in the state-passing convention and held in the
stack_top frame register at frame boundaries. storage is an opaque
host coordinate while height is the semantic stack height. Keeping the
height in the cursor makes stack validation independent of the host stack
representation. Optimized C refines storage to a native u256 *.
struct StackPointer = {
storage : bits(64),
height : operand_stack_height,
}The number of slots an operand-stack cursor moves in one advance or retreat.
type stack_slot_count = range(0, 1024)