Name Date Size #Lines LOC

..15-May-2026-

examples/H15-May-2026-200140

fuzz/H15-May-2026-5241

macros/H15-May-2026-133109

src/H15-May-2026-10,2177,593

tests/all/H15-May-2026-990904

CONTRIBUTING.mdH A D15-May-202612.1 KiB279208

Cargo.tomlH A D15-May-20261.2 KiB4437

README.mdH A D15-May-20264.9 KiB11081

README.md

1<div align="center">
2  <h1>Pulley</h1>
3
4  <h3>Portable, Universal, Low-Level Execution strategY</h3>
5
6  <p>
7    <strong>A portable bytecode and fast interpreter</strong>
8  </p>
9
10  <strong>A <a href="https://bytecodealliance.org/">Bytecode Alliance</a> project</strong>
11
12  <p>
13    <a href="https://github.com/bytecodealliance/wasmtime/actions?query=workflow%3ACI"><img src="https://github.com/bytecodealliance/wasmtime/workflows/CI/badge.svg" alt="build status" /></a>
14    <a href="https://bytecodealliance.zulipchat.com/#narrow/stream/217126-wasmtime"><img src="https://img.shields.io/badge/zulip-join_chat-brightgreen.svg" alt="zulip chat" /></a>
15    <img src="https://img.shields.io/badge/rustc-stable+-green.svg" alt="supported rustc stable" />
16    <a href="https://docs.rs/pulley-interpreter"><img src="https://docs.rs/pulley-interpreter/badge.svg" alt="Documentation Status" /></a>
17  </p>
18
19  <h3>
20    <a href="https://bytecodealliance.zulipchat.com/#narrow/stream/217126-wasmtime">Chat</a>
21  </h3>
22</div>
23
24## About
25
26Pulley is a portable bytecode and fast interpreter for use in Wasmtime.
27
28Pulley's primary goal is portability and its secondary goal is fast
29interpretation.
30
31Pulley is not intended to be a simple reference interpreter, support dynamically
32switching to just-in-time compiled code, or even to be the very fastest
33interpreter in the world.
34
35For more details on Pulley's motivation, goals, and non-goals, see [the Bytecode
36Alliance RFC that originally proposed Pulley][rfc].
37
38[rfc]: https://github.com/bytecodealliance/rfcs/blob/main/accepted/pulley.md
39
40## Status
41
42Pulley is very much still a work in progress! Expect the details of the bytecode
43to change, instructions to appear and disappear, and APIs to be overhauled.
44
45## Example
46
47Here is the disassembly of `f(a, b) = a + b` in Pulley today:
48
49```
50       0: 2f                              push_frame
51       1: 12 00 04                        xadd32 x0, x0, x1
52       4: 30                              pop_frame
53       5: 00                              ret
54```
55
56Note that there are a number of things that could be improved here:
57
58* We could avoid allocating and deallocating a stack frame because this function's
59  body doesn't use any stack slots.
60
61As mentioned above, Pulley is very much a work in progress.
62
63## Principles
64
65What follows are some general, incomplete, and sometimes-conflicting principles
66that we try and follow when designing the Pulley bytecode format and its
67interpreter:
68
69* The bytecode should be simple and fast to decode in software. For example, we
70  should avoid overly-complicated bitpacking, and only reach for that kind of
71  thing when benchmarks and profiles show it to be of benefit.
72
73* The interpreter never materializes `enum Instruction { .. }` values. Instead,
74  it decodes immediates and operands as needed in each opcode handler. This
75  avoids constructing unnecessary temporary storage and branching on opcode
76  multiple times.
77
78* Because we never materialize `enum Instruction { .. }` values, we don't have
79  to worry about unused padding or one very-large instruction inflating the size
80  of all the rest of our small instructions. To put it concisely: we can lean
81  into a variable-length encoding where some instructions require only a single
82  byte and others require many. This helps keep the bytecode compact and
83  cache-efficient.
84
85* We lean into defining super-instructions (sometimes called "macro ops") that
86  perform the work of multiple operations in a single instruction. The more work
87  we do in each turn of the interpreter loop the less we are impacted by its
88  overhead. Additionally, Cranelift, as the primary Pulley bytecode producer,
89  can leverage ISLE lowering patterns to easily identify opportunities for
90  emitting super-instructions.
91
92* We do not, in general, define sub-opcodes. There should be only one branch, on
93  the initial opcode, when evaluating any given instruction. For example, we do
94  *not* have a generic `load` instruction that is followed by a sub-opcode to
95  discriminate between different addressing modes. Instead, we have many
96  different kinds of `load` instructions, one for each of our addressing modes.
97
98  The one exception is the split between regular and extended ops. Regular ops
99  are a single `u8` opcode, where `255` is reserved for all extended ops, and a
100  `u16` opcode follows after the `255` regular opcode. This keeps the most
101  common instructions extra small, and provides a pressure release valve for
102  defining an unbounded number of additional, colder, ops.
103
104* We strive to cut down on boilerplate as much as possible, and try to avoid
105  matching on every opcode repeatedly throughout the whole code base. We do this
106  via heavy `macro_rules` usage where we define the bytecode inside a
107  higher-order macro and then automatically derive a disassembler, decoder,
108  encoder, etc... from that definition. This also avoids any kind of drift where
109  the encoder and decoder get out of sync with each other, for example.
110