Skip to content

Latest commit

 

History

History
156 lines (122 loc) · 4.59 KB

README.md

File metadata and controls

156 lines (122 loc) · 4.59 KB

WasmVM.py

A stack-based virtual machine for learning about WebAssembly

This is a simple stack-based virtual machine that can execute a small set of instructions. It is intended to be the starting point for learning more deeply how WebAssembly works. Right now, like WebAssembly, it only supports 32- and 64-bit integers and floats for operations.

Using

Basic usage

  1. Open the Python REPL by running python3 in your terminal.
  2. Install the package wasmvm by running pip install wasmvm.
  3. Import the StackVM class and instructions.
    from wasmvm import StackVM, Add, Sub, Push, i32
  4. Create an instance of the StackVM class.
    vm = StackVM()
    # Optionally, you can specify the number of pages of memory
    # you want your VM to start with, and the maximum number it
    # may have: StackVM(1, 10)
  5. Add instructions to your virtual machine.
    vm.instructions = [Push(i32(2)), Push(i32(3)), Add("i32")]
  6. Execute the instructions.
    vm.run()
  7. Inspect the stack after your instructions have been executed:
    vm.inspect()
    # [5]

Running the API

Deprecation warning: The API is being deprecated in favor of loading the VM in the browser, by way of Pyodide.

  1. Create a Python virtual environment, e.g. python3 -m venv venv.
  2. Activate the virtual environment, e.g. source .venv/bin/activate.
  3. Install the dependencies, e.g. pip install -r requirements.txt.
  4. Install the API dependency: pip install "fastapi[standard]"
  5. Start the API: fastapi dev main.py
  6. Navigate to http://127.0.0.1:8000/docs to use the OpenAPI documentation.

Working with the frontend

In the directory /static, there resides a simple frontend that can be used to interact with the API. To start the frontend, you need to first install the necessary tools:

# install bun for macos
brew install oven-sh/bun/bun
bun upgrade

From here, you'll next install the dependencies:

cd static
bun install

Finally, you can start the frontend:

bun run dev

To build the frontend for production, you can run:

bun run build

Hooking in observers

Since this is a learning tool, it can be useful to see what your machine is doing while it's operating. Since this is intended to be an extensible tool, you can add different types of observers suited to your execution environment.

For example, you can add a simple observer that prints the stack at each step by running (this one is included in the virtual_machine module):

from virtual_machine import StackVM
from lib import Add, Sub, Push
from shared import VMState

def print_state(state: VMState) -> None:
    print(f"Stack: {state.stack} || Program Counter: {state.pc}")

vm = StackVM()
vm.add_observer(print_state)

Then, when your virtual machine runs, you'll see the stack printed after each instruction has been executed.

Wait, what's a stack-based virtual machine?

In short, a stack-based virtual machine is a computer that uses a stack to store data and execute instructions ("stack" like pancakes). Operations are performed by pushing values onto the stack and then popping them off to be used as arguments to instructions. The program counter (PC) keeps track of where the virtual machine is in the program, and the stack is used to store intermediate values.

Stack-based virtual machines are found in the wild in many places, such as the Java Virtual Machine (JVM), the .NET Common Language Runtime (CLR), and (of course) the WebAssembly virtual machine that's in your browser (unless you're using Lynx).

Instruction set

  • Add
  • Sub
  • Mul
  • Div
  • Eq
  • Eqz
  • Lt
  • Le coming soon
  • Gt
  • Ge coming soon

Building

source venv/bin/activate
python -m pip install -r requirements.txt
# Install dev version locally
python -m pip install -e .
# Build wheel
python -m build
# Upload wheel to testpypi -- expects a ~/.pypirc file with credentials
python -m twine upload --verbose --repository testpypi dist/*
# Upload wheel to pypi -- expects a ~/.pypirc file with credentials
python -m twine upload --verbose dist/*

Resources

There are many resources available to learn more about WebAssembly and how it works. Here's what I've been using: