Skip to content

Latest commit

Β 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

README.md

Epsilon Python Wrapper

Note

This is an AI-generated research report. All text and code in this report was created by an LLM (Large Language Model). For more information on how these reports are created, see the main research repository.

Python bindings for the epsilon WebAssembly runtime.

About Epsilon

Epsilon is a pure Go WebAssembly runtime with zero dependencies, created by Google. Key features:

  • Pure Go Implementation: No cgo dependencies for the core runtime, runs on any Go-supported architecture
  • WebAssembly 2.0 Complete: Full specification support including SIMD (v128) instructions
  • Zero External Dependencies: Self-contained implementation
  • Clean API: Simple, intuitive interface for embedding WASM in Go applications
  • Apache 2.0 Licensed: Permissive open-source license

Epsilon Capabilities

Feature Support
WebAssembly 2.0 βœ… Full
SIMD (v128) βœ… Full
Multiple Memories βœ… Experimental
Host Functions βœ… Full
Tables βœ… Full
Globals βœ… Full
Memory Import/Export βœ… Full
Interactive REPL βœ… Included

Architecture

Epsilon uses a bytecode interpreter design:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     Runtime                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚                      VM                          β”‚ β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚ β”‚
β”‚  β”‚  β”‚  Store   β”‚  β”‚  Stack   β”‚  β”‚  Call Stack  β”‚  β”‚ β”‚
β”‚  β”‚  β”‚ (funcs,  β”‚  β”‚ (values) β”‚  β”‚  (frames)    β”‚  β”‚ β”‚
β”‚  β”‚  β”‚ memories,β”‚  β”‚          β”‚  β”‚              β”‚  β”‚ β”‚
β”‚  β”‚  β”‚ tables,  β”‚  β”‚          β”‚  β”‚              β”‚  β”‚ β”‚
β”‚  β”‚  β”‚ globals) β”‚  β”‚          β”‚  β”‚              β”‚  β”‚ β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚                                                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚              Module Instance                     β”‚ β”‚
β”‚  β”‚  - Function addresses                            β”‚ β”‚
β”‚  β”‚  - Memory addresses                              β”‚ β”‚
β”‚  β”‚  - Table addresses                               β”‚ β”‚
β”‚  β”‚  - Global addresses                              β”‚ β”‚
β”‚  β”‚  - Exports                                       β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Installation

Prerequisites

  • Python 3.8+
  • Go 1.24+ (for building)

Building from Source

# Clone this repository
git clone <this-repo>
cd epsilon-python-wrapper

# Install in development mode
pip install -e .

# Or build the wheel
pip install build
python -m build

Quick Start

Basic Usage

from epsilon import Runtime

# Load and run a WebAssembly module
with Runtime() as runtime:
    wasm_bytes = open("add.wasm", "rb").read()
    with runtime.instantiate(wasm_bytes) as module:
        result = module.call("add", 5, 37)
        print(result)  # [42]

Memory Access

with Runtime() as runtime:
    with runtime.instantiate(wasm_bytes) as module:
        # Read memory
        data = module.read_memory(offset=0, length=100, memory_name="memory")

        # Write memory
        module.write_memory(offset=0, data=b"Hello, WASM!", memory_name="memory")

        # Get memory size (in pages, 1 page = 64KB)
        size = module.get_memory_size("memory")

Export Inspection

with Runtime() as runtime:
    with runtime.instantiate(wasm_bytes) as module:
        exports = module.get_export_names()
        print(exports)  # ['add', 'memory', 'global_counter', ...]

Typed Function Calls

with Runtime() as runtime:
    with runtime.instantiate(wasm_bytes) as module:
        # Call with typed arguments
        result = module.call_typed("compute", [
            (42, 'i32'),
            (3.14, 'f64'),
            (1000000, 'i64'),
        ])

Resource Limiting

Memory Limits

# Limit memory to 256 pages (16 MB)
with Runtime(max_memory_pages=256) as runtime:
    module = runtime.instantiate(wasm_bytes)

# Or per-module
with Runtime() as runtime:
    module = runtime.instantiate(wasm_bytes, max_memory_pages=128)

Execution Timeout

# Set a timeout (in milliseconds)
result = module.call("slow_function", 42, timeout_ms=5000)

Important limitations of the timeout mechanism:

  1. Non-preemptive: Epsilon does not support context cancellation. The timeout uses a Go context wrapper, but WASM execution cannot be interrupted mid-instruction.

  2. Works for returning functions: If a function completes before the timeout, results are returned normally. If it takes longer, a EpsilonTimeoutError is raised.

  3. Infinite loops: An infinite loop in WASM will NOT be interrupted by the timeout. The Go goroutine will continue running indefinitely.

Call Stack Depth

Epsilon has a hardcoded call stack depth limit of 1000 frames. This protects against stack overflow from deeply nested recursion.

Resource Limiting Options Analysis

What Epsilon Provides

Resource Built-in Limit Configurable
Memory (pages) 32,768 max (2GB) βœ… Via Limits.Max
Call Stack 1,000 frames ❌ Hardcoded
CPU Time None ❌ Not available
Fuel/Gas None ❌ Not available
Instructions None ❌ Not available

Comparison with Other Runtimes

Feature Epsilon wazero wasmtime
Memory Limits βœ… βœ… βœ…
Context Cancellation ❌ βœ… βœ…
Fuel Metering ❌ ❌ βœ…
Instruction Counting ❌ ❌ βœ…
Pure Go βœ… βœ… ❌ (Rust)
CGo Free βœ… βœ… ❌

Alternative Approaches for CPU Limiting

If you need strict CPU/time limits, consider these approaches:

  1. Process-level limits (Linux):

    import resource
    resource.setrlimit(resource.RLIMIT_CPU, (5, 5))  # 5 second CPU limit
  2. Subprocess with timeout:

    import subprocess
    result = subprocess.run(
        ["python", "run_wasm.py"],
        timeout=5.0,
        capture_output=True
    )
  3. Multiprocessing:

    from multiprocessing import Process, Queue
    
    def run_wasm(q):
        result = module.call("function")
        q.put(result)
    
    q = Queue()
    p = Process(target=run_wasm, args=(q,))
    p.start()
    p.join(timeout=5.0)
    if p.is_alive():
        p.terminate()
  4. Signal-based timeout (Unix only):

    import signal
    
    def timeout_handler(signum, frame):
        raise TimeoutError("Execution timed out")
    
    signal.signal(signal.SIGALRM, timeout_handler)
    signal.alarm(5)  # 5 second timeout
    try:
        result = module.call("function")
    finally:
        signal.alarm(0)

API Reference

epsilon.Runtime

class Runtime:
    PAGE_SIZE = 65536  # 64KB
    MAX_PAGES = 32768  # 2GB total

    def __init__(self, max_memory_pages: int = 0):
        """Create a new WebAssembly runtime.

        Args:
            max_memory_pages: Default max memory for modules (0 = no limit)
        """

    def instantiate(self, wasm_bytes, max_memory_pages=None) -> Module:
        """Instantiate a WASM module from bytes."""

    def instantiate_file(self, file_path, max_memory_pages=None) -> Module:
        """Instantiate a WASM module from a file."""

    def close(self):
        """Close the runtime and free resources."""

epsilon.Module

class Module:
    def call(self, func_name: str, *args, timeout_ms=None) -> List[int]:
        """Call an exported function."""

    def call_typed(self, func_name: str, args: List[tuple], timeout_ms=None) -> List[int]:
        """Call with typed arguments: [(value, 'i32'|'i64'|'f32'|'f64'), ...]"""

    def get_export_names(self) -> List[str]:
        """Get names of all exports."""

    def get_memory_size(self, memory_name="memory") -> int:
        """Get memory size in pages."""

    def read_memory(self, offset, length, memory_name="memory") -> bytes:
        """Read bytes from linear memory."""

    def write_memory(self, offset, data, memory_name="memory") -> int:
        """Write bytes to linear memory."""

    def get_global(self, global_name: str) -> int:
        """Get the value of an exported global."""

    def close(self):
        """Close the module and free resources."""

Exceptions

class EpsilonError(Exception):
    """Base exception for epsilon errors."""

class EpsilonTimeoutError(EpsilonError):
    """Raised when execution times out."""

Utility Functions

def version() -> str:
    """Get the epsilon library version."""

def wrapper_version() -> str:
    """Get the Python wrapper version."""

Epsilon Technical Details

Memory Model

  • Page size: 64 KiB (65,536 bytes)
  • Maximum pages: 32,768 (2 GiB total)
  • Limits: Configurable min/max via MemoryType.Limits

Value Types Supported

Type Description Size
i32 32-bit integer 4 bytes
i64 64-bit integer 8 bytes
f32 32-bit float 4 bytes
f64 64-bit float 8 bytes
v128 128-bit SIMD vector 16 bytes
funcref Function reference pointer
externref External reference pointer

VM Limits

Limit Value Configurable
Call stack depth 1,000 No
Value stack Unlimited* No
Memory pages 32,768 Yes
Table size 2^32-1 Yes

*Value stack is implemented as a Go slice and grows as needed

Known Limitations

  1. No true timeout support: WASM execution cannot be preemptively interrupted
  2. No fuel metering: Cannot limit instruction count or CPU cycles
  3. Single-threaded: Epsilon does not support WebAssembly threads proposal
  4. No WASI: Epsilon is a pure runtime without WASI support
  5. Fixed call depth: 1000 frame limit is hardcoded

License

Apache 2.0 - see LICENSE

Acknowledgments