<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: jtenner</title>
    <description>The latest articles on DEV Community by jtenner (@jtenner).</description>
    <link>https://dev.to/jtenner</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F48933%2Fd81ed70a-188a-4585-a4ae-8034ce79a19a.png</url>
      <title>DEV Community: jtenner</title>
      <link>https://dev.to/jtenner</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jtenner"/>
    <language>en</language>
    <item>
      <title>Delayed Gratification and Valent Blocks</title>
      <dc:creator>jtenner</dc:creator>
      <pubDate>Mon, 14 Sep 2026 13:54:24 +0000</pubDate>
      <link>https://dev.to/jtenner/delayed-gratification-and-valent-blocks-498o</link>
      <guid>https://dev.to/jtenner/delayed-gratification-and-valent-blocks-498o</guid>
      <description>&lt;p&gt;Creating a good compiler is a two-fold juggling task. On one hand, the compiler itself should run quickly and use very little memory. On the other hand, the machine code it produces should actually be fast too. Over the last few months, I have discovered that balancing between these two values is an art form. Very rarely do we get to cheat and get both at the same time.&lt;/p&gt;

&lt;p&gt;When it comes to my &lt;em&gt;latest&lt;/em&gt; project Wago, my friend Jairus and I stumbled onto a paper that changed our direction completely.&lt;/p&gt;

&lt;p&gt;This paper is called &lt;a href="https://doi.org/10.1109/iCCECE49321.2020.9231154" rel="noopener noreferrer"&gt;"Valent-Blocks: Scalable High-Performance Compilation of WebAssembly Bytecode For Embedded Systems."&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This technique was designed to be usable by resource-constrained systems, and naturally, it turned out to be very valuable in many other places as well. The central idea?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The compiler does not need to emit machine code as soon as it reads an instruction. Instead, it can accumulate a small very focused representation using a stack machine and make better decisions once "side effects" actually occur or when something actually needs to become a value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;An example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider a function that calculates &lt;code&gt;(a + 3) * b&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, let's look at an equivalent function in JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;example&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Typically, I like to use the "wat" format, which stands for "WebAssembly Text Format." This syntax is similar to assembly in a lot of ways, but it's easy to follow along. Each instruction operates on a stack machine instead of on registers.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(func $example (param $a i32) (param $b i32) (result i32)
  local.get $a
  i32.const 3
  i32.add (; a + 3 ;)

  local.get $b
  i32.mul (; $val * b ;)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A direct translation of this into machine code might naively turn this into a very big un-optimized mess.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nasm"&gt;&lt;code&gt;&lt;span class="c1"&gt;; local.get $a&lt;/span&gt;
&lt;span class="nf"&gt;mov&lt;/span&gt;  &lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;DWORD&lt;/span&gt; &lt;span class="nv"&gt;PTR&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;push&lt;/span&gt; &lt;span class="nb"&gt;rax&lt;/span&gt;

&lt;span class="c1"&gt;; i32.const 3&lt;/span&gt;
&lt;span class="nf"&gt;mov&lt;/span&gt;  &lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="nf"&gt;push&lt;/span&gt; &lt;span class="nb"&gt;rax&lt;/span&gt;

&lt;span class="c1"&gt;; i32.add&lt;/span&gt;
&lt;span class="nf"&gt;pop&lt;/span&gt;  &lt;span class="nb"&gt;rcx&lt;/span&gt;
&lt;span class="nf"&gt;pop&lt;/span&gt;  &lt;span class="nb"&gt;rax&lt;/span&gt;
&lt;span class="nf"&gt;add&lt;/span&gt;  &lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;ecx&lt;/span&gt;
&lt;span class="nf"&gt;push&lt;/span&gt; &lt;span class="nb"&gt;rax&lt;/span&gt;

&lt;span class="c1"&gt;; local.get $b&lt;/span&gt;
&lt;span class="nf"&gt;mov&lt;/span&gt;  &lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;DWORD&lt;/span&gt; &lt;span class="nv"&gt;PTR&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;push&lt;/span&gt; &lt;span class="nb"&gt;rax&lt;/span&gt;

&lt;span class="c1"&gt;; i32.mul&lt;/span&gt;
&lt;span class="nf"&gt;pop&lt;/span&gt;  &lt;span class="nb"&gt;rcx&lt;/span&gt;
&lt;span class="nf"&gt;pop&lt;/span&gt;  &lt;span class="nb"&gt;rax&lt;/span&gt;
&lt;span class="nf"&gt;imul&lt;/span&gt; &lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;ecx&lt;/span&gt;
&lt;span class="nf"&gt;push&lt;/span&gt; &lt;span class="nb"&gt;rax&lt;/span&gt;

&lt;span class="c1"&gt;; result&lt;/span&gt;
&lt;span class="nf"&gt;pop&lt;/span&gt;  &lt;span class="nb"&gt;rax&lt;/span&gt;
&lt;span class="nf"&gt;ret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each instruction immediately commits to a physical representation for its result. In doing so, the compiler throws away useful information after almost every instruction.&lt;/p&gt;

&lt;p&gt;Additionally, the compiler threw away useful information after each and every instruction. It results in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5 pushes&lt;/li&gt;
&lt;li&gt;5 pops&lt;/li&gt;
&lt;li&gt;2 local loads&lt;/li&gt;
&lt;li&gt;1 constant materialization&lt;/li&gt;
&lt;li&gt;1 add&lt;/li&gt;
&lt;li&gt;1 multiply&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead, what if we stopped mirroring the WebAssembly operand stack into actual machine-stack operations? We can keep a "symbolic" stack during compilation and delay the machine-code decisions until we have more information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: &lt;code&gt;local.get $a&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our algorithm can simply push a "LocalGet($a)" to a stack.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LocalGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We skip the part where we emit machine instructions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: &lt;code&gt;i32.const 3&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;I32Const&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we have two values on top of the stack.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────┐
│ I32Const(3)  │
├──────────────┤
│ LocalGet($a) │
└──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Again, we skip the machine code. No side effects have happened yet anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: &lt;code&gt;i32.add&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now we need to add the two items on the stack. Instead of emitting an actual add instruction, we can simply produce an &lt;code&gt;I32Add(LocalGet($a), I32Const(3))&lt;/code&gt; and push it to the stack. Pop each of the items off the top of the stack one by one, and then push the result back on. Notice that the right operand is popped first because it was pushed last. We then reconstruct the operands in their original order.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;I32Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Step 4: The rest of the function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The last two instructions follow the same pattern:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LocalGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;I32Mul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And we are done!&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;Just kidding. We are done building the expression, but we still have not generated any machine code.&lt;/p&gt;

&lt;p&gt;Eventually, something has to consume the value. In this case, we have reached the end of the function, and the function must return the value on top of the Wasm stack. This forces us to resolve, or condense, our deferred expression into actual machine instructions.&lt;/p&gt;

&lt;p&gt;This is where things get a bit more complicated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Resolve &lt;code&gt;a + 3&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We need to move "a" into a register and add 3 to it, leaving the resulting value inside the register.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nasm"&gt;&lt;code&gt;&lt;span class="nf"&gt;mov&lt;/span&gt; &lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;DWORD&lt;/span&gt; &lt;span class="nv"&gt;PTR&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;add&lt;/span&gt; &lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We must assume that the parameter of the function exists at &lt;code&gt;[rbp - 4]&lt;/code&gt;, but it only results in a single load operation. We use &lt;code&gt;eax&lt;/code&gt; here to keep a running value of the item on top of the stack, as you will see.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6: Resolve the multiplication&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, we perform the multiplication in a single step here using a &lt;strong&gt;memory operand&lt;/strong&gt; which points to &lt;code&gt;b&lt;/code&gt;, and follow it up with a &lt;code&gt;ret&lt;/code&gt; which signifies the end of the function. The return value is already conveniently stored exactly where it needs to be.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nasm"&gt;&lt;code&gt;&lt;span class="nf"&gt;imul&lt;/span&gt; &lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;DWORD&lt;/span&gt; &lt;span class="nv"&gt;PTR&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;ret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let's put it all together now!&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nasm"&gt;&lt;code&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;  &lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;DWORD&lt;/span&gt; &lt;span class="nv"&gt;PTR&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;add&lt;/span&gt;  &lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="nf"&gt;imul&lt;/span&gt; &lt;span class="nb"&gt;eax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;DWORD&lt;/span&gt; &lt;span class="nv"&gt;PTR&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;rbp&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;ret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Wow. That's a big difference.&lt;/p&gt;

&lt;p&gt;The important part is not only that this code is shorter. By waiting, the compiler kept useful information alive. Since 3 remained a constant, it became an immediate operand to add. Since $b remained a local reference, the multiplication could consume it directly from memory. The result of a + 3 never needed a stack slot at all; it stayed in eax until the multiplication consumed it. In this simplified example, leaving the return value in eax, exactly where it needs to go, is another nice benefit.&lt;/p&gt;

&lt;p&gt;This is the main technique used by my latest project called Wago, which is a single-forward-pass WebAssembly-to-native JIT compiler written in Go. You can check it out here: &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/wago-org" rel="noopener noreferrer"&gt;
        wago-org
      &lt;/a&gt; / &lt;a href="https://github.com/wago-org/wago" rel="noopener noreferrer"&gt;
        wago
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      a wonderfully quick, compact, and extensible webassembly runtime for go
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;&lt;pre&gt;╦ ╦ ╔═╗ ╔═╗ ╔═╗
║║║ ╠═╣ ║ ╦ ║ ║
╚╩╝ ╩ ╩ ╚═╝ ╚═╝&lt;/pre&gt;&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;
  a wonderfully quick, compact, and extensible webassembly runtime for go
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://github.com/wago-org/wago/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/wago-org/wago/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;
  &lt;a href="https://go.dev/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b0deb1a0078c73a1b5e27fc01df0c715ad3a7ea0556ed1360c3c0856c3f8a0f8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f676f2d253345253344312e32322d3030414444382e737667" alt="Go &gt;= 1.22"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/wago-org/wago/releases" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d8ef1f22a401856709ddd5e27ab3d167a59b6fa07ab0b28bb6e22fa9c0048f16/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f7761676f2d6f72672f7761676f3f696e636c7564655f70726572656c6561736573266c6162656c3d72656c65617365" alt="Release"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/wago-org/wago/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ae12a671ff973c9f065484f46896a51cbe0b123ba047350ca2998a40f5039662/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f7761676f2d6f72672f7761676f" alt="License"&gt;&lt;/a&gt;
  &lt;a href="https://wago.sh/discord" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/248061ff84b21b0f1f74dc4c740e9792447d50cffc545a245001680100321ae4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646973636f72642d6a6f696e2d3538363546323f6c6f676f3d646973636f7264266c6f676f436f6c6f723d7768697465" alt="Discord"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://docs.wago.sh" rel="nofollow noopener noreferrer"&gt;documentation&lt;/a&gt; ·
  &lt;a href="https://docs.wago.sh/getting-started" rel="nofollow noopener noreferrer"&gt;getting started&lt;/a&gt; ·
  &lt;a href="https://plugins.wago.sh" rel="nofollow noopener noreferrer"&gt;plugins&lt;/a&gt; ·
  &lt;a href="https://wago.sh/#performance" rel="nofollow noopener noreferrer"&gt;benchmarks&lt;/a&gt; ·
  &lt;a href="https://wago.sh/discord" rel="nofollow noopener noreferrer"&gt;discord&lt;/a&gt; ·
  &lt;a href="https://github.com/sponsors/JairusSW" rel="noopener noreferrer"&gt;sponsor us&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Wago is a pure-Go WebAssembly engine that compiles Wasm directly to native
machine code.&lt;/p&gt;
&lt;div class="markdown-alert markdown-alert-note"&gt;
&lt;p class="markdown-alert-title"&gt;Note&lt;/p&gt;
&lt;p&gt;Wago is still beta. APIs and &lt;code&gt;.wago&lt;/code&gt; artifacts may change.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why Wago?&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast and lightweight.&lt;/strong&gt; Using a few &lt;em&gt;kilobytes&lt;/em&gt; of ram, we compile &lt;em&gt;5x faster&lt;/em&gt; and execute &lt;em&gt;40% quicker&lt;/em&gt; than wazero.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pure Go.&lt;/strong&gt; Embed Wago without CGO while keeping straightforward Go builds
and cross-compilation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standards Compliant&lt;/strong&gt; We pass the &lt;a href="https://github.com/WebAssembly/testsuite" rel="noopener noreferrer"&gt;official WebAssembly test suite&lt;/a&gt;, millions of fuzzes, and many real-world corpora.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensible by design.&lt;/strong&gt; WASI, the Component Model, and other host
capabilities live outside the core runtime as plugins.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standalone executables&lt;/strong&gt; Compile your &lt;code&gt;.wasm&lt;/code&gt; to &lt;em&gt;tiny&lt;/em&gt; native executables. Great for CLIs.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;On macOS and Linux:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;…
&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/wago-org/wago" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Wago compiles Wasm directly to machine code without using a whole-function intermediate representation, while using very little memory at compile time. You can check out some of our computed benchmark numbers and install it here at &lt;a href="https://wago.sh/" rel="noopener noreferrer"&gt;the wago homepage&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a bit of a warning, this software is currently in beta, which means that we are trying to improve stability on both amd64 and arm64 across Linux, macOS, and Windows. If you happen to need a web assembly runtime, we would appreciate it if you took the time to try it out.&lt;/p&gt;

&lt;p&gt;Thanks for reading and happy coding.&lt;/p&gt;

&lt;p&gt;Joshua Tenner&lt;/p&gt;

</description>
      <category>performance</category>
      <category>computerscience</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
