EEVM.Interpreter.Instructions.Registry (eevm v0.1.0)

Copy Markdown View Source

Opcode metadata registry — single source of truth for every opcode's name, stack I/O signature, implementing module, and static-context flag.

Given an opcode byte (0x00–0xFF) info/1 returns:

  • :name — the human-readable mnemonic (e.g. "ADD")
  • :inputs / :outputs — stack arity, used by the disassembler and stack-depth checks
  • :module — the EEVM.Interpreter.Instructions.* module that implements the opcode; EEVM.Interpreter dispatches on this field
  • :kind — how the interpreter runs it:
    • :stack opcodes are pure functions of the stack, implemented as module.stack_op(opcode, stack) on a list; this is the default for the Arithmetic, Comparison, Bitwise, and StackOps modules.
    • :control opcodes (PUSH0–PUSH32, JUMP, JUMPI, JUMPDEST, PC, GAS) read or move the interpreter loop's own registers, so EEVM.Interpreter implements them.
    • :state opcodes read or write the machine state through module.execute(opcode, state).
  • :state_mutating (when present) — opcode mutates persistent state and is an exceptional halt ({:error, :static_state_modification}) inside a STATICCALL frame
  • :eip (when present) — the EEVM.HardforkConfig flag of the EIP that introduced the opcode; before that EIP activates the byte is undefined. Opcodes without it exist since Frontier. EEVM.Interpreter.InstructionTable applies this per hardfork.

PUSH1–PUSH32, DUP1–DUP16, and SWAP1–SWAP16 are generated dynamically from their opcode ranges rather than stored in the static map.

Summary

Functions

dup?(op)

@spec dup?(non_neg_integer()) :: boolean()

info(op)

@spec info(non_neg_integer()) :: {:ok, map()} | {:error, :unknown_opcode}

push?(op)

@spec push?(non_neg_integer()) :: boolean()

push_bytes(op)

@spec push_bytes(non_neg_integer()) :: non_neg_integer()

swap?(op)

@spec swap?(non_neg_integer()) :: boolean()